<commit_before>// aws-costexplorer-export
// exports data from AWS Cost Explorer and imports it into a GCS Bucket as JSON

package main

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

	"github.com/aws/aws-sdk-go-v2/aws"
	awssdkconfig "github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/service/costexplorer"
	cetypes "github.com/aws/aws-sdk-go-v2/service/costexplorer/types"
	"gocloud.dev/blob"
	_ "gocloud.dev/blob/fileblob"
	_ "gocloud.dev/blob/gcsblob"
	_ "gocloud.dev/blob/memblob"
	_ "gocloud.dev/blob/s3blob"
)

// date formats used in different places
const (
	usageDateFormat  = "2006-01-02"
	resultDateFormat = "200601021504"
	fileNameTemplate = "cncf-aws-infra-billing-and-usage-data-%v.json"
)
// default config for runtime
var (
	defaultConfig = AWSCostExplorerExportConfig{
		AWSRegion: "us-east-1",
		LocalOutputFile:"/tmp/local-cncf-aws-infra-billing-and-usage-data.json",
		LocalOutputFileEnable: false,
		BucketURI: "gs://cncf-aws-infra-cost-and-billing-data",
		AmountOfDaysToReportFrom: 365,
		PromoteToLatest: true,
	}
)

// MarshalAsJSON returns a JSON string from an interface
func MarshalAsJSON(input interface{}) string {
	o, err := json.Marshal(input)
	if err != nil {
		log.Println(err)
		return ""
	}
	return string(o)
}

// WriteFile writes the file to disk
func WriteFile(path string, contents string) error {
	f, err := os.Create(path)
	if err != nil {
		return err
	}
	defer f.Close()
	_, err = f.WriteString(contents)
	if err != nil {
		return err
	}
	return nil
}

// AWSCostExplorerExportConfig stores configuration for the runtime
type AWSCostExplorerExportConfig struct {
	AWSRegion                string
	LocalOutputFile          string
	LocalOutputFileEnable    bool
	BucketURI                string
	AmountOfDaysToReportFrom int
	PromoteToLatest          bool
}

// usageClient stores the client for costexplorer
type usageClient struct {
	client *costexplorer.Client
	config AWSCostExplorerExportConfig
}

// GetInputForUsage returns an input for making the cost and usage data request
func (c usageClient) GetInputForUsage(nextPageToken *string) *costexplorer.GetCostAndUsageInput {
	start := time.Now().
		Add(-time.Duration(time.Hour * 24 * time.Duration(c.config.AmountOfDaysToReportFrom))).
		Format(usageDateFormat)
	end := time.Now().Format(usageDateFormat)
	input := &costexplorer.GetCostAndUsageInput{
		Filter: &cetypes.Expression{
			Not: &cetypes.Expression{
				Dimensions: &cetypes.DimensionValues{
					Key:          cetypes.DimensionPurchaseType,
					MatchOptions: []cetypes.MatchOption{cetypes.MatchOptionEquals},
					Values:       []string{"Refund", "Credit"},
				},
			},
		},
		Metrics:     []string{string(cetypes.MetricUnblendedCost)},
		Granularity: cetypes.GranularityDaily,
		GroupBy: []cetypes.GroupDefinition{{
			Type: cetypes.GroupDefinitionTypeDimension,
			Key:  aws.String(string(cetypes.DimensionLinkedAccount)),
		}},
		TimePeriod: &cetypes.DateInterval{
			Start: aws.String(start),
			End:   aws.String(end),
		},
		NextPageToken: nextPageToken,
	}
	return input
}

// GetUsage returns the cost and usage data collected without pages
func (c usageClient) GetUsage() (costAndUsageOutput *costexplorer.GetCostAndUsageOutput, err error) {
	costAndUsageOutput = &costexplorer.GetCostAndUsageOutput{}
	var nextPageToken *string
	for page := 0; true; page ++ {
		usage, err := c.client.GetCostAndUsage(context.TODO(), c.GetInputForUsage(nextPageToken))
		if err != nil {
			return &costexplorer.GetCostAndUsageOutput{}, fmt.Errorf("error with getting usage, %v", err)
		}
		if usage == nil {
			break
		}
		log.Printf("- page (%v): dimensions (%v); group definitions (%v); results by time (%v)\n", page, len(usage.DimensionValueAttributes), len(usage.GroupDefinitions), len(usage.ResultsByTime))
		costAndUsageOutput.DimensionValueAttributes = append(costAndUsageOutput.DimensionValueAttributes, usage.DimensionValueAttributes...)
		costAndUsageOutput.GroupDefinitions = append(costAndUsageOutput.GroupDefinitions, usage.GroupDefinitions...)
		costAndUsageOutput.ResultsByTime = append(costAndUsageOutput.ResultsByTime, usage.ResultsByTime...)

		if usage.NextPageToken == nil {
			break
		}
		nextPageToken = usage.NextPageToken
		costAndUsageOutput.ResultMetadata = usage.ResultMetadata
	}
	costAndUsageOutput.NextPageToken = nil
	if err != nil {
		return &costexplorer.GetCostAndUsageOutput{}, fmt.Errorf("error with usage with resources, %v", err)
	}
	if len(costAndUsageOutput.ResultsByTime) == 0 {
		return &costexplorer.GetCostAndUsageOutput{}, fmt.Errorf("error: empty dataset")
	}
	return costAndUsageOutput, nil
}

// BucketAccess stores config for accessing a bucket
type BucketAccess struct {
	URI    string
	Bucket *blob.Bucket
}

// Open returns access to a bucket
func (b BucketAccess) Open() (BucketAccess, error) {
	bucket, err := blob.OpenBucket(context.TODO(), b.URI)
	if err != nil {
		return BucketAccess{}, err
	}
	b.Bucket = bucket
	return b, nil
}

// WriteToFile writes a file in the bucket with access
func (b BucketAccess) WriteToFile(name string, data string) (err error) {
	w, err := b.Bucket.NewWriter(context.TODO(), name, nil)
	if err != nil {
		return err
	}
	_, writeErr := fmt.Fprintln(w, data)
	closeErr := w.Close()
	if writeErr != nil {
		return err
	}
	if closeErr != nil {
		return err
	}
	return nil
}

func main() {
	var config AWSCostExplorerExportConfig
	flag.StringVar(&config.AWSRegion, "aws-region", defaultConfig.AWSRegion, "specify an AWS region")
	flag.StringVar(&config.LocalOutputFile, "output-file", defaultConfig.LocalOutputFile, "specify a local file to write the usage JSON data to")
	flag.BoolVar(&config.LocalOutputFileEnable, "output-file-enable", defaultConfig.LocalOutputFileEnable, "specify whether the usage data is also written to disk locally")
	flag.StringVar(&config.BucketURI, "bucket-uri", defaultConfig.BucketURI, "specify a bucket to write to")
	flag.IntVar(&config.AmountOfDaysToReportFrom, "days-ago", defaultConfig.AmountOfDaysToReportFrom, "specify the amount of days back to report from today")
	flag.BoolVar(&config.PromoteToLatest, "promote-to-latest", defaultConfig.PromoteToLatest, "specifies whether to promote the cost and usage data to a latest JSON file")
	flag.Parse()

	cfg, err := awssdkconfig.LoadDefaultConfig(context.TODO(),
		awssdkconfig.WithRegion(config.AWSRegion),
	)
	if err != nil {
		log.Printf("unable to load SDK config, %v", err)
		return
	}

	ceclient := costexplorer.NewFromConfig(cfg)

	log.Println("Fetching usage data")
	uc := usageClient{client: ceclient, config: config}
	costAndUsageOutput, err := uc.GetUsage()
	if err != nil {
		log.Printf("%v", err)
		return
	}
	log.Println("Fetched usage data")
	costAndUsageOutputJSON := MarshalAsJSON(costAndUsageOutput)
	if config.LocalOutputFileEnable {
		log.Println("Writing usage data to file")
		err = WriteFile(config.LocalOutputFile, costAndUsageOutputJSON)
		if err != nil {
			log.Printf("%v", err)
			return
		}
		log.Printf("Wrote usage data to file '%v'\n", config.LocalOutputFile)
	}
	log.Printf("Opening GCS bucket '%v'\n", config.BucketURI)
	ba := BucketAccess{URI: config.BucketURI}
	ba, err = ba.Open()
	if err != nil {
		log.Printf("%v", err)
		return
	}
	defer func() {
		log.Printf("Closing GCS bucket '%v'\n", config.BucketURI)
		ba.Bucket.Close()
	}()
	fileNames := []string{
		fmt.Sprintf(fileNameTemplate, time.Now().Format(resultDateFormat)),
	}
	if config.PromoteToLatest {
		fileNames = append(fileNames, fmt.Sprintf(fileNameTemplate, "latest"))
	}
	for _, fileName := range fileNames {
		log.Printf("Uploading '%v' to '%v/%v'", fileName, config.BucketURI, fileName)
		err = ba.WriteToFile(fileName, costAndUsageOutputJSON)
		if err != nil {
			log.Printf("%v", err)
			return
		}
		log.Printf("Uploaded '%v' to '%v/%v' successfully", fileName, config.BucketURI, fileName)
	}
}
<commit_msg>Add print of config before start<commit_after>// aws-costexplorer-export
// exports data from AWS Cost Explorer and imports it into a GCS Bucket as JSON

package main

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

	"github.com/aws/aws-sdk-go-v2/aws"
	awssdkconfig "github.com/aws/aws-sdk-go-v2/config"
	"github.com/aws/aws-sdk-go-v2/service/costexplorer"
	cetypes "github.com/aws/aws-sdk-go-v2/service/costexplorer/types"
	"gocloud.dev/blob"
	_ "gocloud.dev/blob/fileblob"
	_ "gocloud.dev/blob/gcsblob"
	_ "gocloud.dev/blob/memblob"
	_ "gocloud.dev/blob/s3blob"
)

// date formats used in different places
const (
	usageDateFormat  = "2006-01-02"
	resultDateFormat = "200601021504"
	fileNameTemplate = "cncf-aws-infra-billing-and-usage-data-%v.json"
)
// default config for runtime
var (
	defaultConfig = AWSCostExplorerExportConfig{
		AWSRegion: "us-east-1",
		LocalOutputFile:"/tmp/local-cncf-aws-infra-billing-and-usage-data.json",
		LocalOutputFileEnable: false,
		BucketURI: "gs://cncf-aws-infra-cost-and-billing-data",
		AmountOfDaysToReportFrom: 365,
		PromoteToLatest: true,
	}
)

// MarshalAsJSON returns a JSON string from an interface
func MarshalAsJSON(input interface{}) string {
	o, err := json.Marshal(input)
	if err != nil {
		log.Println(err)
		return ""
	}
	return string(o)
}

// WriteFile writes the file to disk
func WriteFile(path string, contents string) error {
	f, err := os.Create(path)
	if err != nil {
		return err
	}
	defer f.Close()
	_, err = f.WriteString(contents)
	if err != nil {
		return err
	}
	return nil
}

// AWSCostExplorerExportConfig stores configuration for the runtime
type AWSCostExplorerExportConfig struct {
	AWSRegion                string
	LocalOutputFile          string
	LocalOutputFileEnable    bool
	BucketURI                string
	AmountOfDaysToReportFrom int
	PromoteToLatest          bool
}

// usageClient stores the client for costexplorer
type usageClient struct {
	client *costexplorer.Client
	config AWSCostExplorerExportConfig
}

// GetInputForUsage returns an input for making the cost and usage data request
func (c usageClient) GetInputForUsage(nextPageToken *string) *costexplorer.GetCostAndUsageInput {
	start := time.Now().
		Add(-time.Duration(time.Hour * 24 * time.Duration(c.config.AmountOfDaysToReportFrom))).
		Format(usageDateFormat)
	end := time.Now().Format(usageDateFormat)
	input := &costexplorer.GetCostAndUsageInput{
		Filter: &cetypes.Expression{
			Not: &cetypes.Expression{
				Dimensions: &cetypes.DimensionValues{
					Key:          cetypes.DimensionPurchaseType,
					MatchOptions: []cetypes.MatchOption{cetypes.MatchOptionEquals},
					Values:       []string{"Refund", "Credit"},
				},
			},
		},
		Metrics:     []string{string(cetypes.MetricUnblendedCost)},
		Granularity: cetypes.GranularityDaily,
		GroupBy: []cetypes.GroupDefinition{{
			Type: cetypes.GroupDefinitionTypeDimension,
			Key:  aws.String(string(cetypes.DimensionLinkedAccount)),
		}},
		TimePeriod: &cetypes.DateInterval{
			Start: aws.String(start),
			End:   aws.String(end),
		},
		NextPageToken: nextPageToken,
	}
	return input
}

// GetUsage returns the cost and usage data collected without pages
func (c usageClient) GetUsage() (costAndUsageOutput *costexplorer.GetCostAndUsageOutput, err error) {
	costAndUsageOutput = &costexplorer.GetCostAndUsageOutput{}
	var nextPageToken *string
	for page := 0; true; page ++ {
		usage, err := c.client.GetCostAndUsage(context.TODO(), c.GetInputForUsage(nextPageToken))
		if err != nil {
			return &costexplorer.GetCostAndUsageOutput{}, fmt.Errorf("error with getting usage, %v", err)
		}
		if usage == nil {
			break
		}
		log.Printf("- page (%v): dimensions (%v); group definitions (%v); results by time (%v)\n", page, len(usage.DimensionValueAttributes), len(usage.GroupDefinitions), len(usage.ResultsByTime))
		costAndUsageOutput.DimensionValueAttributes = append(costAndUsageOutput.DimensionValueAttributes, usage.DimensionValueAttributes...)
		costAndUsageOutput.GroupDefinitions = append(costAndUsageOutput.GroupDefinitions, usage.GroupDefinitions...)
		costAndUsageOutput.ResultsByTime = append(costAndUsageOutput.ResultsByTime, usage.ResultsByTime...)

		if usage.NextPageToken == nil {
			break
		}
		nextPageToken = usage.NextPageToken
		costAndUsageOutput.ResultMetadata = usage.ResultMetadata
	}
	costAndUsageOutput.NextPageToken = nil
	if err != nil {
		return &costexplorer.GetCostAndUsageOutput{}, fmt.Errorf("error with usage with resources, %v", err)
	}
	if len(costAndUsageOutput.ResultsByTime) == 0 {
		return &costexplorer.GetCostAndUsageOutput{}, fmt.Errorf("error: empty dataset")
	}
	return costAndUsageOutput, nil
}

// BucketAccess stores config for accessing a bucket
type BucketAccess struct {
	URI    string
	Bucket *blob.Bucket
}

// Open returns access to a bucket
func (b BucketAccess) Open() (BucketAccess, error) {
	bucket, err := blob.OpenBucket(context.TODO(), b.URI)
	if err != nil {
		return BucketAccess{}, err
	}
	b.Bucket = bucket
	return b, nil
}

// WriteToFile writes a file in the bucket with access
func (b BucketAccess) WriteToFile(name string, data string) (err error) {
	w, err := b.Bucket.NewWriter(context.TODO(), name, nil)
	if err != nil {
		return err
	}
	_, writeErr := fmt.Fprintln(w, data)
	closeErr := w.Close()
	if writeErr != nil {
		return err
	}
	if closeErr != nil {
		return err
	}
	return nil
}

func main() {
	var config AWSCostExplorerExportConfig
	flag.StringVar(&config.AWSRegion, "aws-region", defaultConfig.AWSRegion, "specify an AWS region")
	flag.StringVar(&config.LocalOutputFile, "output-file", defaultConfig.LocalOutputFile, "specify a local file to write the usage JSON data to")
	flag.BoolVar(&config.LocalOutputFileEnable, "output-file-enable", defaultConfig.LocalOutputFileEnable, "specify whether the usage data is also written to disk locally")
	flag.StringVar(&config.BucketURI, "bucket-uri", defaultConfig.BucketURI, "specify a bucket to write to")
	flag.IntVar(&config.AmountOfDaysToReportFrom, "days-ago", defaultConfig.AmountOfDaysToReportFrom, "specify the amount of days back to report from today")
	flag.BoolVar(&config.PromoteToLatest, "promote-to-latest", defaultConfig.PromoteToLatest, "specifies whether to promote the cost and usage data to a latest JSON file")
	flag.Parse()

	log.Printf("Config: %#v\n", config)

	cfg, err := awssdkconfig.LoadDefaultConfig(context.TODO(),
		awssdkconfig.WithRegion(config.AWSRegion),
	)
	if err != nil {
		log.Printf("unable to load SDK config, %v", err)
		return
	}

	ceclient := costexplorer.NewFromConfig(cfg)

	log.Println("Fetching usage data")
	uc := usageClient{client: ceclient, config: config}
	costAndUsageOutput, err := uc.GetUsage()
	if err != nil {
		log.Printf("%v", err)
		return
	}
	log.Println("Fetched usage data")
	costAndUsageOutputJSON := MarshalAsJSON(costAndUsageOutput)
	if config.LocalOutputFileEnable {
		log.Println("Writing usage data to file")
		err = WriteFile(config.LocalOutputFile, costAndUsageOutputJSON)
		if err != nil {
			log.Printf("%v", err)
			return
		}
		log.Printf("Wrote usage data to file '%v'\n", config.LocalOutputFile)
	}
	log.Printf("Opening GCS bucket '%v'\n", config.BucketURI)
	ba := BucketAccess{URI: config.BucketURI}
	ba, err = ba.Open()
	if err != nil {
		log.Printf("%v", err)
		return
	}
	defer func() {
		log.Printf("Closing GCS bucket '%v'\n", config.BucketURI)
		ba.Bucket.Close()
	}()
	fileNames := []string{
		fmt.Sprintf(fileNameTemplate, time.Now().Format(resultDateFormat)),
	}
	if config.PromoteToLatest {
		fileNames = append(fileNames, fmt.Sprintf(fileNameTemplate, "latest"))
	}
	for _, fileName := range fileNames {
		log.Printf("Uploading '%v' to '%v/%v'", fileName, config.BucketURI, fileName)
		err = ba.WriteToFile(fileName, costAndUsageOutputJSON)
		if err != nil {
			log.Printf("%v", err)
			return
		}
		log.Printf("Uploaded '%v' to '%v/%v' successfully", fileName, config.BucketURI, fileName)
	}
}
<|endoftext|>


<commit_before>package dashboard

import (
	"database/sql"

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

type DatabaseManager interface {
	GetAll(pageSize, offset int) (result []Widget, err error)
	GetPages() (result []Page, err error)
	InsertWidget(widget *Widget) (int64, error)
	InsertOrUpdateWidget(widget *Widget) (int64, error)
	InsertWidgetToPage(pageId int64, widgetId string) (int64, error)
	InsertPage(page *Page) (int64, error)
	UpdatePage(page *Page) (int64, error)
	GetPageWidgets(pageId int64) (result []Widget, err error)
	GetUnlinkedWidgets() (result []Widget, err error)
	Close() error
}

func NewDbManager(path string) DatabaseManager {
	return &DbManager{path: path}
}

type DbManager struct {
	db   *sql.DB
	path string
}

func (m *DbManager) Db() (*sql.DB, error) {
	var err error
	if m.db == nil {
		m.db, err = sql.Open("sqlite3", m.path)
		if err != nil {
			return nil, err
		}
	}
	return m.db, err
}

func (m *DbManager) Close() error {
	if m.db != nil {
		err := m.db.Close()
		return err
	}
	return nil
}

func (m *DbManager) InsertWidget(widget *Widget) (int64, error) {
	insertQuery := `
		INSERT INTO widgets (id,url,width,height)
		VALUES (?,?,?,?);
	`
	db, err := m.Db()
	if err != nil {
		return 0, err
	}
	res, err := db.Exec(insertQuery, widget.Id, widget.Url, widget.Width, widget.Height)
	if err != nil {
		return 0, err
	}

	return res.RowsAffected()
}

func (m *DbManager) InsertOrUpdateWidget(widget *Widget) (int64, error) {
	insertOrReplace := `
		INSERT OR REPLACE INTO widgets (id,url,width,height)
		VALUES (?,?,?,?);
	`
	db, err := m.Db()
	if err != nil {
		return 0, err
	}
	res, err := db.Exec(insertOrReplace, widget.Id, widget.Url, widget.Width, widget.Height)
	if err != nil {
		return 0, err
	}

	return res.LastInsertId()
}

func (m *DbManager) GetAll(pageSize, offset int) (result []Widget, err error) {
	result = []Widget{}
	selectAllWithPaging := `
		SELECT * FROM widgets LIMIT ?,?;
	`
	db, err := m.Db()
	if err != nil {
		return
	}
	rows, err := db.Query(selectAllWithPaging, offset, pageSize)
	if err != nil {
		return
	}
	defer rows.Close()
	for rows.Next() {
		var row Widget
		err = rows.Scan(&row.Id, &row.Width, &row.Height, &row.Url, &row.Content)
		if err != nil {
			return
		}
		result = append(result, row)
	}
	return
}

func (m *DbManager) InsertPage(page *Page) (int64, error) {
	insertOrReplace := `
		INSERT INTO pages (title,visible)
		VALUES (?,?);
	`
	db, err := m.Db()
	if err != nil {
		return 0, err
	}
	res, err := db.Exec(insertOrReplace, page.Title, page.Visible)
	if err != nil {
		return 0, err
	}
	return res.LastInsertId()
}

func (m *DbManager) UpdatePage(page *Page) (int64, error) {
	insertOrReplace := `
		UPDATE pages SET title=?, visible=? WHERE id = ?
	`
	db, err := m.Db()
	if err != nil {
		return 0, err
	}
	res, err := db.Exec(insertOrReplace, page.Title, page.Visible, page.Id)
	if err != nil {
		return 0, err
	}
	return res.RowsAffected()
}

func (m *DbManager) InsertWidgetToPage(pageId int64, widgetId string) (int64, error) {
	insertOrReplace := `
		INSERT INTO page_widgets (id_widget,id_page)
		VALUES (?,?);
	`
	db, err := m.Db()
	if err != nil {
		return 0, err
	}
	res, err := db.Exec(insertOrReplace, widgetId, pageId)
	if err != nil {
		return 0, err
	}
	return res.RowsAffected()
}

func (m *DbManager) GetPageWidgets(pageId int64) (result []Widget, err error) {
	result = []Widget{}
	selectAllPageWidgets := `
		SELECT * FROM widgets WHERE id in (SELECT id_widget FROM page_widgets WHERE id_page=?);
	`
	db, err := m.Db()
	if err != nil {
		return
	}
	rows, err := db.Query(selectAllPageWidgets, pageId)
	if err != nil {
		return
	}
	defer rows.Close()
	for rows.Next() {
		var row Widget
		err = rows.Scan(&row.Id, &row.Width, &row.Height, &row.Url, &row.Content)
		if err != nil {
			return
		}
		result = append(result, row)
	}
	return
}

func (m *DbManager) GetUnlinkedWidgets() (result []Widget, err error) {
	result = []Widget{}
	selectQuery := `
		SELECT * FROM widgets WHERE id not in (SELECT DISTINCT id_widget FROM page_widgets);
	`
	db, err := m.Db()
	if err != nil {
		return
	}
	rows, err := db.Query(selectQuery)
	if err != nil {
		return
	}
	defer rows.Close()
	for rows.Next() {
		var row Widget
		err = rows.Scan(&row.Id, &row.Width, &row.Height, &row.Url, &row.Content)
		if err != nil {
			return
		}
		if row.Id != nil {
			result = append(result, row)
		}
	}
	return
}

func (m *DbManager) GetPages() (result []Page, err error) {
	result = []Page{}
	selectQuery := `
		SELECT p.*, w.* FROM pages as p
		LEFT OUTER JOIN page_widgets as pw ON p.id = pw.id_page
		LEFT OUTER JOIN widgets as w ON w.id = pw.id_widget
		ORDER BY p.id;
	`
	db, err := m.Db()
	if err != nil {
		return
	}
	rows, err := db.Query(selectQuery)
	if err != nil {
		return
	}
	defer rows.Close()
	var page *Page
	var currentPageId int64

	for rows.Next() {
		var rowWidget Widget
		var rowPage Page
		err = rows.Scan(&rowPage.Id,
			&rowPage.Title,
			&rowPage.Visible,
			&rowWidget.Id,
			&rowWidget.Width,
			&rowWidget.Height,
			&rowWidget.Url,
			&rowWidget.Content)

		if err != nil {
			return
		}

		if currentPageId != rowPage.Id {
			if page != nil {
				result = append(result, *page)
				page = nil
			}
			page = &Page{}
			page.Id = rowPage.Id
			page.Title = rowPage.Title
			page.Visible = rowPage.Visible
		}
		page.Widgets = append(page.Widgets, rowWidget)
		currentPageId = rowPage.Id
	}

	if page != nil {
		result = append(result, *page)
	}

	return
}
<commit_msg>SM-22 #time 10m Fixed adding null widget to widgets prop of page<commit_after>package dashboard

import (
	"database/sql"

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

type DatabaseManager interface {
	GetAll(pageSize, offset int) (result []Widget, err error)
	GetPages() (result []Page, err error)
	InsertWidget(widget *Widget) (int64, error)
	InsertOrUpdateWidget(widget *Widget) (int64, error)
	InsertWidgetToPage(pageId int64, widgetId string) (int64, error)
	InsertPage(page *Page) (int64, error)
	UpdatePage(page *Page) (int64, error)
	GetPageWidgets(pageId int64) (result []Widget, err error)
	GetUnlinkedWidgets() (result []Widget, err error)
	Close() error
}

func NewDbManager(path string) DatabaseManager {
	return &DbManager{path: path}
}

type DbManager struct {
	db   *sql.DB
	path string
}

func (m *DbManager) Db() (*sql.DB, error) {
	var err error
	if m.db == nil {
		m.db, err = sql.Open("sqlite3", m.path)
		if err != nil {
			return nil, err
		}
	}
	return m.db, err
}

func (m *DbManager) Close() error {
	if m.db != nil {
		err := m.db.Close()
		return err
	}
	return nil
}

func (m *DbManager) InsertWidget(widget *Widget) (int64, error) {
	insertQuery := `
		INSERT INTO widgets (id,url,width,height)
		VALUES (?,?,?,?);
	`
	db, err := m.Db()
	if err != nil {
		return 0, err
	}
	res, err := db.Exec(insertQuery, widget.Id, widget.Url, widget.Width, widget.Height)
	if err != nil {
		return 0, err
	}

	return res.RowsAffected()
}

func (m *DbManager) InsertOrUpdateWidget(widget *Widget) (int64, error) {
	insertOrReplace := `
		INSERT OR REPLACE INTO widgets (id,url,width,height)
		VALUES (?,?,?,?);
	`
	db, err := m.Db()
	if err != nil {
		return 0, err
	}
	res, err := db.Exec(insertOrReplace, widget.Id, widget.Url, widget.Width, widget.Height)
	if err != nil {
		return 0, err
	}

	return res.LastInsertId()
}

func (m *DbManager) GetAll(pageSize, offset int) (result []Widget, err error) {
	result = []Widget{}
	selectAllWithPaging := `
		SELECT * FROM widgets LIMIT ?,?;
	`
	db, err := m.Db()
	if err != nil {
		return
	}
	rows, err := db.Query(selectAllWithPaging, offset, pageSize)
	if err != nil {
		return
	}
	defer rows.Close()
	for rows.Next() {
		var row Widget
		err = rows.Scan(&row.Id, &row.Width, &row.Height, &row.Url, &row.Content)
		if err != nil {
			return
		}
		result = append(result, row)
	}
	return
}

func (m *DbManager) InsertPage(page *Page) (int64, error) {
	insertOrReplace := `
		INSERT INTO pages (title,visible)
		VALUES (?,?);
	`
	db, err := m.Db()
	if err != nil {
		return 0, err
	}
	res, err := db.Exec(insertOrReplace, page.Title, page.Visible)
	if err != nil {
		return 0, err
	}
	return res.LastInsertId()
}

func (m *DbManager) UpdatePage(page *Page) (int64, error) {
	insertOrReplace := `
		UPDATE pages SET title=?, visible=? WHERE id = ?
	`
	db, err := m.Db()
	if err != nil {
		return 0, err
	}
	res, err := db.Exec(insertOrReplace, page.Title, page.Visible, page.Id)
	if err != nil {
		return 0, err
	}
	return res.RowsAffected()
}

func (m *DbManager) InsertWidgetToPage(pageId int64, widgetId string) (int64, error) {
	insertOrReplace := `
		INSERT INTO page_widgets (id_widget,id_page)
		VALUES (?,?);
	`
	db, err := m.Db()
	if err != nil {
		return 0, err
	}
	res, err := db.Exec(insertOrReplace, widgetId, pageId)
	if err != nil {
		return 0, err
	}
	return res.RowsAffected()
}

func (m *DbManager) GetPageWidgets(pageId int64) (result []Widget, err error) {
	result = []Widget{}
	selectAllPageWidgets := `
		SELECT * FROM widgets WHERE id in (SELECT id_widget FROM page_widgets WHERE id_page=?);
	`
	db, err := m.Db()
	if err != nil {
		return
	}
	rows, err := db.Query(selectAllPageWidgets, pageId)
	if err != nil {
		return
	}
	defer rows.Close()
	for rows.Next() {
		var row Widget
		err = rows.Scan(&row.Id, &row.Width, &row.Height, &row.Url, &row.Content)
		if err != nil {
			return
		}
		result = append(result, row)
	}
	return
}

func (m *DbManager) GetUnlinkedWidgets() (result []Widget, err error) {
	result = []Widget{}
	selectQuery := `
		SELECT * FROM widgets WHERE id not in (SELECT DISTINCT id_widget FROM page_widgets);
	`
	db, err := m.Db()
	if err != nil {
		return
	}
	rows, err := db.Query(selectQuery)
	if err != nil {
		return
	}
	defer rows.Close()
	for rows.Next() {
		var row Widget
		err = rows.Scan(&row.Id, &row.Width, &row.Height, &row.Url, &row.Content)
		if err != nil {
			return
		}
		if row.Id != nil {
			result = append(result, row)
		}
	}
	return
}

func (m *DbManager) GetPages() (result []Page, err error) {
	result = []Page{}
	selectQuery := `
		SELECT p.*, w.* FROM pages as p
		LEFT OUTER JOIN page_widgets as pw ON p.id = pw.id_page
		LEFT OUTER JOIN widgets as w ON w.id = pw.id_widget
		ORDER BY p.id;
	`
	db, err := m.Db()
	if err != nil {
		return
	}
	rows, err := db.Query(selectQuery)
	if err != nil {
		return
	}
	defer rows.Close()
	var page *Page
	var currentPageId int64

	for rows.Next() {
		var rowWidget Widget
		var rowPage Page
		err = rows.Scan(&rowPage.Id,
			&rowPage.Title,
			&rowPage.Visible,
			&rowWidget.Id,
			&rowWidget.Width,
			&rowWidget.Height,
			&rowWidget.Url,
			&rowWidget.Content)

		if err != nil {
			return
		}

		if currentPageId != rowPage.Id {
			if page != nil {
				result = append(result, *page)
				page = nil
			}
			page = &Page{}
			page.Id = rowPage.Id
			page.Title = rowPage.Title
			page.Visible = rowPage.Visible
		}

		if rowWidget.Id != nil {
			page.Widgets = append(page.Widgets, rowWidget)
		}

		currentPageId = rowPage.Id
	}

	if page != nil {
		result = append(result, *page)
	}

	return
}
<|endoftext|>


<commit_before>// Package stickyerrwriter provides a Writer based on the
// sticky error writer written about here:
// http://blog.golang.org/error-handling-and-go
// Implements the Writer interface. Stashes the first error
// encountered which can be later retrieved via the Err method.
// Subsequent writes following an error are essentially NOOPs.
package stickyerrwriter

import "io"

type StickyErrorWriter struct {
	io.Writer
	err error
}

func (s *StickyErrorWriter) Write(p []byte) (int, error) {
	if s.err != nil {
		return len(p), nil
	}
	n, err := s.Writer.Write(p)
	if err != nil {
		s.err = err
		return len(p), nil
	}
	return n, nil
}

func (s *StickyErrorWriter) Err() error { return s.err }
<commit_msg>Update stickyerr.go<commit_after>// Package stickyerrwriter provides a Writer based on the
// sticky error writer written about here:
// http://blog.golang.org/error-handling-and-go
// Implements the Writer interface. Stashes the first error
// encountered which can be later retrieved via the Err method.
// Subsequent writes following an error are essentially NOOPs.
package stickyerrwriter

import "io"

type StickyErrorWriter struct {
	io.Writer
	err error
}

func (s *StickyErrorWriter) Write(p []byte) (int, error) {
	if s.err != nil {
		return 0, nil
	}
	n, err := s.Writer.Write(p)
	if err != nil {
		s.err = err
		return n, nil
	}
	return n, nil
}

func (s *StickyErrorWriter) Err() error { return s.err }
<|endoftext|>


<commit_before>package gxutil

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"

	. "github.com/whyrusleeping/stump"
)

type ErrAlreadyInstalled struct {
	pkg string
}

func IsErrAlreadyInstalled(err error) bool {
	_, ok := err.(ErrAlreadyInstalled)
	return ok
}

func (eai ErrAlreadyInstalled) Error() string {
	return fmt.Sprintf("package %s already installed", eai.pkg)
}

func (pm *PM) GetPackageTo(hash, out string) (*Package, error) {
	var pkg Package
	_, err := os.Stat(out)
	if err == nil {
		err := FindPackageInDir(&pkg, out)
		if err == nil {
			return &pkg, nil
		} else if !os.IsNotExist(err) {
			return nil, err
		}
	}

	if err != nil && !os.IsNotExist(err) {
		return nil, err
	}

	begin := time.Now()
	VLog("  - fetching %s via ipfs api", hash)
	err = pm.Shell().Get(hash, out)
	if err != nil {
		return nil, err
	}
	VLog("  - fetch finished in %s", time.Now().Sub(begin))

	err = FindPackageInDir(&pkg, out)
	if err != nil {
		return nil, err
	}

	return &pkg, nil
}

func FindPackageInDir(pkg interface{}, dir string) error {
	name, err := PackageNameInDir(dir)
	if err != nil {
		return err
	}
	return LoadPackageFile(pkg, filepath.Join(dir, name, PkgFileName))
}

func PackageNameInDir(dir string) (string, error) {
	fs, err := ioutil.ReadDir(dir)
	if err != nil {
		return "", err
	}

	if len(fs) == 0 {
		return "", fmt.Errorf("no package found in hashdir: %s", dir)
	}

	if len(fs) > 1 {
		return "", fmt.Errorf("found multiple packages in hashdir: %s", dir)
	}

	return fs[0].Name(), nil
}
<commit_msg>add retries to fetching code<commit_after>package gxutil

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"

	. "github.com/whyrusleeping/stump"
)

type ErrAlreadyInstalled struct {
	pkg string
}

func IsErrAlreadyInstalled(err error) bool {
	_, ok := err.(ErrAlreadyInstalled)
	return ok
}

func (eai ErrAlreadyInstalled) Error() string {
	return fmt.Sprintf("package %s already installed", eai.pkg)
}

func (pm *PM) GetPackageTo(hash, out string) (*Package, error) {
	var pkg Package
	_, err := os.Stat(out)
	if err == nil {
		err := FindPackageInDir(&pkg, out)
		if err == nil {
			return &pkg, nil
		} else if !os.IsNotExist(err) {
			return nil, err
		}
	}

	if err != nil && !os.IsNotExist(err) {
		return nil, err
	}

	begin := time.Now()
	VLog("  - fetching %s via ipfs api", hash)
	tries := 3
	for i := 0; i < tries; i++ {
		err = pm.Shell().Get(hash, out)
		if err != nil {
			Error("from shell.Get(): ", err)
			if i == tries-1 {
				return nil, err
			}
			Log("retrying fetch %s after a second...", hash)
			time.Sleep(time.Second)
		} else {
			break
		}
	}
	VLog("  - fetch finished in %s", time.Now().Sub(begin))

	err = FindPackageInDir(&pkg, out)
	if err != nil {
		return nil, err
	}

	return &pkg, nil
}

func FindPackageInDir(pkg interface{}, dir string) error {
	name, err := PackageNameInDir(dir)
	if err != nil {
		return err
	}
	return LoadPackageFile(pkg, filepath.Join(dir, name, PkgFileName))
}

func PackageNameInDir(dir string) (string, error) {
	fs, err := ioutil.ReadDir(dir)
	if err != nil {
		return "", err
	}

	if len(fs) == 0 {
		return "", fmt.Errorf("no package found in hashdir: %s", dir)
	}

	if len(fs) > 1 {
		return "", fmt.Errorf("found multiple packages in hashdir: %s", dir)
	}

	return fs[0].Name(), nil
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"strings"

	"github.com/dotcloud/docker/api"
	"github.com/dotcloud/docker/api/client"
	"github.com/dotcloud/docker/builtins"
	"github.com/dotcloud/docker/dockerversion"
	"github.com/dotcloud/docker/engine"
	"github.com/dotcloud/docker/opts"
	flag "github.com/dotcloud/docker/pkg/mflag"
	"github.com/dotcloud/docker/sysinit"
	"github.com/dotcloud/docker/utils"
)

const (
	defaultCaFile   = "ca.pem"
	defaultKeyFile  = "key.pem"
	defaultCertFile = "cert.pem"
)

var (
	dockerConfDir = os.Getenv("HOME") + "/.docker/"
)

func main() {
	if selfPath := utils.SelfPath(); strings.Contains(selfPath, ".dockerinit") {
		// Running in init mode
		sysinit.SysInit()
		return
	}

	var (
		flVersion            = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit")
		flDaemon             = flag.Bool([]string{"d", "-daemon"}, false, "Enable daemon mode")
		flGraphOpts          opts.ListOpts
		flDebug              = flag.Bool([]string{"D", "-debug"}, false, "Enable debug mode")
		flAutoRestart        = flag.Bool([]string{"r", "-restart"}, true, "Restart previously running containers")
		bridgeName           = flag.String([]string{"b", "-bridge"}, "", "Attach containers to a pre-existing network bridge\nuse 'none' to disable container networking")
		bridgeIp             = flag.String([]string{"#bip", "-bip"}, "", "Use this CIDR notation address for the network bridge's IP, not compatible with -b")
		pidfile              = flag.String([]string{"p", "-pidfile"}, "/var/run/docker.pid", "Path to use for daemon PID file")
		flRoot               = flag.String([]string{"g", "-graph"}, "/var/lib/docker", "Path to use as the root of the Docker runtime")
		flSocketGroup        = flag.String([]string{"G", "-group"}, "docker", "Group to assign the unix socket specified by -H when running in daemon mode\nuse '' (the empty string) to disable setting of a group")
		flEnableCors         = flag.Bool([]string{"#api-enable-cors", "-api-enable-cors"}, false, "Enable CORS headers in the remote API")
		flDns                = opts.NewListOpts(opts.ValidateIp4Address)
		flDnsSearch          = opts.NewListOpts(opts.ValidateDomain)
		flEnableIptables     = flag.Bool([]string{"#iptables", "-iptables"}, true, "Enable Docker's addition of iptables rules")
		flEnableIpForward    = flag.Bool([]string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward")
		flDefaultIp          = flag.String([]string{"#ip", "-ip"}, "0.0.0.0", "Default IP address to use when binding container ports")
		flInterContainerComm = flag.Bool([]string{"#icc", "-icc"}, true, "Enable inter-container communication")
		flGraphDriver        = flag.String([]string{"s", "-storage-driver"}, "", "Force the Docker runtime to use a specific storage driver")
		flExecDriver         = flag.String([]string{"e", "-exec-driver"}, "native", "Force the Docker runtime to use a specific exec driver")
		flHosts              = opts.NewListOpts(api.ValidateHost)
		flMtu                = flag.Int([]string{"#mtu", "-mtu"}, 0, "Set the containers network MTU\nif no value is provided: default to the default route MTU or 1500 if no default route is available")
		flTls                = flag.Bool([]string{"-tls"}, false, "Use TLS; implied by tls-verify flags")
		flTlsVerify          = flag.Bool([]string{"-tlsverify"}, false, "Use TLS and verify the remote (daemon: verify client, client: verify daemon)")
		flCa                 = flag.String([]string{"-tlscacert"}, dockerConfDir+defaultCaFile, "Trust only remotes providing a certificate signed by the CA given here")
		flCert               = flag.String([]string{"-tlscert"}, dockerConfDir+defaultCertFile, "Path to TLS certificate file")
		flKey                = flag.String([]string{"-tlskey"}, dockerConfDir+defaultKeyFile, "Path to TLS key file")
		flSelinuxEnabled     = flag.Bool([]string{"-selinux-enabled"}, false, "Enable selinux support")
	)
	flag.Var(&flDns, []string{"#dns", "-dns"}, "Force Docker to use specific DNS servers")
	flag.Var(&flDnsSearch, []string{"-dns-search"}, "Force Docker to use specific DNS search domains")
	flag.Var(&flHosts, []string{"H", "-host"}, "The socket(s) to bind to in daemon mode\nspecified using one or more tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd.")
	flag.Var(&flGraphOpts, []string{"-storage-opt"}, "Set storage driver options")

	flag.Parse()

	if *flVersion {
		showVersion()
		return
	}
	if flHosts.Len() == 0 {
		defaultHost := os.Getenv("DOCKER_HOST")

		if defaultHost == "" || *flDaemon {
			// If we do not have a host, default to unix socket
			defaultHost = fmt.Sprintf("unix://%s", api.DEFAULTUNIXSOCKET)
		}
		if _, err := api.ValidateHost(defaultHost); err != nil {
			log.Fatal(err)
		}
		flHosts.Set(defaultHost)
	}

	if *bridgeName != "" && *bridgeIp != "" {
		log.Fatal("You specified -b & --bip, mutually exclusive options. Please specify only one.")
	}

	if *flDebug {
		os.Setenv("DEBUG", "1")
	}

	if *flDaemon {
		if runtime.GOOS != "linux" {
			log.Fatalf("The Docker daemon is only supported on linux")
		}
		if os.Geteuid() != 0 {
			log.Fatalf("The Docker daemon needs to be run as root")
		}

		if flag.NArg() != 0 {
			flag.Usage()
			return
		}

		// set up the TempDir to use a canonical path
		tmp := os.TempDir()
		realTmp, err := utils.ReadSymlinkedDirectory(tmp)
		if err != nil {
			log.Fatalf("Unable to get the full path to the TempDir (%s): %s", tmp, err)
		}
		os.Setenv("TMPDIR", realTmp)

		// get the canonical path to the Docker root directory
		root := *flRoot
		var realRoot string
		if _, err := os.Stat(root); err != nil && os.IsNotExist(err) {
			realRoot = root
		} else {
			realRoot, err = utils.ReadSymlinkedDirectory(root)
			if err != nil {
				log.Fatalf("Unable to get the full path to root (%s): %s", root, err)
			}
		}
		if err := checkKernelAndArch(); err != nil {
			log.Fatal(err)
		}

		eng := engine.New()
		// Load builtins
		if err := builtins.Register(eng); err != nil {
			log.Fatal(err)
		}
		// load the daemon in the background so we can immediately start
		// the http api so that connections don't fail while the daemon
		// is booting
		go func() {
			// Load plugin: httpapi
			job := eng.Job("initserver")
			job.Setenv("Pidfile", *pidfile)
			job.Setenv("Root", realRoot)
			job.SetenvBool("AutoRestart", *flAutoRestart)
			job.SetenvList("Dns", flDns.GetAll())
			job.SetenvList("DnsSearch", flDnsSearch.GetAll())
			job.SetenvBool("EnableIptables", *flEnableIptables)
			job.SetenvBool("EnableIpForward", *flEnableIpForward)
			job.Setenv("BridgeIface", *bridgeName)
			job.Setenv("BridgeIP", *bridgeIp)
			job.Setenv("DefaultIp", *flDefaultIp)
			job.SetenvBool("InterContainerCommunication", *flInterContainerComm)
			job.Setenv("GraphDriver", *flGraphDriver)
			job.SetenvList("GraphOptions", flGraphOpts.GetAll())
			job.Setenv("ExecDriver", *flExecDriver)
			job.SetenvInt("Mtu", *flMtu)
			job.SetenvBool("EnableSelinuxSupport", *flSelinuxEnabled)
			job.SetenvList("Sockets", flHosts.GetAll())
			if err := job.Run(); err != nil {
				log.Fatal(err)
			}
			// after the daemon is done setting up we can tell the api to start
			// accepting connections
			if err := eng.Job("acceptconnections").Run(); err != nil {
				log.Fatal(err)
			}
		}()

		// TODO actually have a resolved graphdriver to show?
		log.Printf("docker daemon: %s %s; execdriver: %s; graphdriver: %s",
			dockerversion.VERSION,
			dockerversion.GITCOMMIT,
			*flExecDriver,
			*flGraphDriver)

		// Serve api
		job := eng.Job("serveapi", flHosts.GetAll()...)
		job.SetenvBool("Logging", true)
		job.SetenvBool("EnableCors", *flEnableCors)
		job.Setenv("Version", dockerversion.VERSION)
		job.Setenv("SocketGroup", *flSocketGroup)

		job.SetenvBool("Tls", *flTls)
		job.SetenvBool("TlsVerify", *flTlsVerify)
		job.Setenv("TlsCa", *flCa)
		job.Setenv("TlsCert", *flCert)
		job.Setenv("TlsKey", *flKey)
		job.SetenvBool("BufferRequests", true)
		if err := job.Run(); err != nil {
			log.Fatal(err)
		}
	} else {
		if flHosts.Len() > 1 {
			log.Fatal("Please specify only one -H")
		}
		protoAddrParts := strings.SplitN(flHosts.GetAll()[0], "://", 2)

		var (
			cli       *client.DockerCli
			tlsConfig tls.Config
		)
		tlsConfig.InsecureSkipVerify = true

		// If we should verify the server, we need to load a trusted ca
		if *flTlsVerify {
			*flTls = true
			certPool := x509.NewCertPool()
			file, err := ioutil.ReadFile(*flCa)
			if err != nil {
				log.Fatalf("Couldn't read ca cert %s: %s", *flCa, err)
			}
			certPool.AppendCertsFromPEM(file)
			tlsConfig.RootCAs = certPool
			tlsConfig.InsecureSkipVerify = false
		}

		// If tls is enabled, try to load and send client certificates
		if *flTls || *flTlsVerify {
			_, errCert := os.Stat(*flCert)
			_, errKey := os.Stat(*flKey)
			if errCert == nil && errKey == nil {
				*flTls = true
				cert, err := tls.LoadX509KeyPair(*flCert, *flKey)
				if err != nil {
					log.Fatalf("Couldn't load X509 key pair: %s. Key encrypted?", err)
				}
				tlsConfig.Certificates = []tls.Certificate{cert}
			}
		}

		if *flTls || *flTlsVerify {
			cli = client.NewDockerCli(os.Stdin, os.Stdout, os.Stderr, protoAddrParts[0], protoAddrParts[1], &tlsConfig)
		} else {
			cli = client.NewDockerCli(os.Stdin, os.Stdout, os.Stderr, protoAddrParts[0], protoAddrParts[1], nil)
		}

		if err := cli.ParseCommands(flag.Args()...); err != nil {
			if sterr, ok := err.(*utils.StatusError); ok {
				if sterr.Status != "" {
					log.Println(sterr.Status)
				}
				os.Exit(sterr.StatusCode)
			}
			log.Fatal(err)
		}
	}
}

func showVersion() {
	fmt.Printf("Docker version %s, build %s\n", dockerversion.VERSION, dockerversion.GITCOMMIT)
}

func checkKernelAndArch() error {
	// Check for unsupported architectures
	if runtime.GOARCH != "amd64" {
		return fmt.Errorf("The Docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH)
	}
	// Check for unsupported kernel versions
	// FIXME: it would be cleaner to not test for specific versions, but rather
	// test for specific functionalities.
	// Unfortunately we can't test for the feature "does not cause a kernel panic"
	// without actually causing a kernel panic, so we need this workaround until
	// the circumstances of pre-3.8 crashes are clearer.
	// For details see http://github.com/dotcloud/docker/issues/407
	if k, err := utils.GetKernelVersion(); err != nil {
		log.Printf("WARNING: %s\n", err)
	} else {
		if utils.CompareKernelVersion(k, &utils.KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0}) < 0 {
			if os.Getenv("DOCKER_NOWARN_KERNEL_VERSION") == "" {
				log.Printf("WARNING: You are running linux kernel version %s, which might be unstable running docker. Please upgrade your kernel to 3.8.0.", k.String())
			}
		}
	}
	return nil
}
<commit_msg>Add mutex warning when specifying -icc or -ip-forward and -iptables=false<commit_after>package main

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"strings"

	"github.com/dotcloud/docker/api"
	"github.com/dotcloud/docker/api/client"
	"github.com/dotcloud/docker/builtins"
	"github.com/dotcloud/docker/dockerversion"
	"github.com/dotcloud/docker/engine"
	"github.com/dotcloud/docker/opts"
	flag "github.com/dotcloud/docker/pkg/mflag"
	"github.com/dotcloud/docker/sysinit"
	"github.com/dotcloud/docker/utils"
)

const (
	defaultCaFile   = "ca.pem"
	defaultKeyFile  = "key.pem"
	defaultCertFile = "cert.pem"
)

var (
	dockerConfDir = os.Getenv("HOME") + "/.docker/"
)

func main() {
	if selfPath := utils.SelfPath(); strings.Contains(selfPath, ".dockerinit") {
		// Running in init mode
		sysinit.SysInit()
		return
	}

	var (
		flVersion            = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit")
		flDaemon             = flag.Bool([]string{"d", "-daemon"}, false, "Enable daemon mode")
		flGraphOpts          opts.ListOpts
		flDebug              = flag.Bool([]string{"D", "-debug"}, false, "Enable debug mode")
		flAutoRestart        = flag.Bool([]string{"r", "-restart"}, true, "Restart previously running containers")
		bridgeName           = flag.String([]string{"b", "-bridge"}, "", "Attach containers to a pre-existing network bridge\nuse 'none' to disable container networking")
		bridgeIp             = flag.String([]string{"#bip", "-bip"}, "", "Use this CIDR notation address for the network bridge's IP, not compatible with -b")
		pidfile              = flag.String([]string{"p", "-pidfile"}, "/var/run/docker.pid", "Path to use for daemon PID file")
		flRoot               = flag.String([]string{"g", "-graph"}, "/var/lib/docker", "Path to use as the root of the Docker runtime")
		flSocketGroup        = flag.String([]string{"G", "-group"}, "docker", "Group to assign the unix socket specified by -H when running in daemon mode\nuse '' (the empty string) to disable setting of a group")
		flEnableCors         = flag.Bool([]string{"#api-enable-cors", "-api-enable-cors"}, false, "Enable CORS headers in the remote API")
		flDns                = opts.NewListOpts(opts.ValidateIp4Address)
		flDnsSearch          = opts.NewListOpts(opts.ValidateDomain)
		flEnableIptables     = flag.Bool([]string{"#iptables", "-iptables"}, true, "Enable Docker's addition of iptables rules")
		flEnableIpForward    = flag.Bool([]string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward")
		flDefaultIp          = flag.String([]string{"#ip", "-ip"}, "0.0.0.0", "Default IP address to use when binding container ports")
		flInterContainerComm = flag.Bool([]string{"#icc", "-icc"}, true, "Enable inter-container communication")
		flGraphDriver        = flag.String([]string{"s", "-storage-driver"}, "", "Force the Docker runtime to use a specific storage driver")
		flExecDriver         = flag.String([]string{"e", "-exec-driver"}, "native", "Force the Docker runtime to use a specific exec driver")
		flHosts              = opts.NewListOpts(api.ValidateHost)
		flMtu                = flag.Int([]string{"#mtu", "-mtu"}, 0, "Set the containers network MTU\nif no value is provided: default to the default route MTU or 1500 if no default route is available")
		flTls                = flag.Bool([]string{"-tls"}, false, "Use TLS; implied by tls-verify flags")
		flTlsVerify          = flag.Bool([]string{"-tlsverify"}, false, "Use TLS and verify the remote (daemon: verify client, client: verify daemon)")
		flCa                 = flag.String([]string{"-tlscacert"}, dockerConfDir+defaultCaFile, "Trust only remotes providing a certificate signed by the CA given here")
		flCert               = flag.String([]string{"-tlscert"}, dockerConfDir+defaultCertFile, "Path to TLS certificate file")
		flKey                = flag.String([]string{"-tlskey"}, dockerConfDir+defaultKeyFile, "Path to TLS key file")
		flSelinuxEnabled     = flag.Bool([]string{"-selinux-enabled"}, false, "Enable selinux support")
	)
	flag.Var(&flDns, []string{"#dns", "-dns"}, "Force Docker to use specific DNS servers")
	flag.Var(&flDnsSearch, []string{"-dns-search"}, "Force Docker to use specific DNS search domains")
	flag.Var(&flHosts, []string{"H", "-host"}, "The socket(s) to bind to in daemon mode\nspecified using one or more tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd.")
	flag.Var(&flGraphOpts, []string{"-storage-opt"}, "Set storage driver options")

	flag.Parse()

	if *flVersion {
		showVersion()
		return
	}
	if flHosts.Len() == 0 {
		defaultHost := os.Getenv("DOCKER_HOST")

		if defaultHost == "" || *flDaemon {
			// If we do not have a host, default to unix socket
			defaultHost = fmt.Sprintf("unix://%s", api.DEFAULTUNIXSOCKET)
		}
		if _, err := api.ValidateHost(defaultHost); err != nil {
			log.Fatal(err)
		}
		flHosts.Set(defaultHost)
	}

	if *bridgeName != "" && *bridgeIp != "" {
		log.Fatal("You specified -b & --bip, mutually exclusive options. Please specify only one.")
	}

	if !*flEnableIptables && !*flInterContainerComm {
		log.Fatal("You specified --iptables=false with --icc=false. ICC uses iptables to function. Please set --icc or --iptables to true.")
	}

	if *flDebug {
		os.Setenv("DEBUG", "1")
	}

	if *flDaemon {
		if runtime.GOOS != "linux" {
			log.Fatalf("The Docker daemon is only supported on linux")
		}
		if os.Geteuid() != 0 {
			log.Fatalf("The Docker daemon needs to be run as root")
		}

		if flag.NArg() != 0 {
			flag.Usage()
			return
		}

		// set up the TempDir to use a canonical path
		tmp := os.TempDir()
		realTmp, err := utils.ReadSymlinkedDirectory(tmp)
		if err != nil {
			log.Fatalf("Unable to get the full path to the TempDir (%s): %s", tmp, err)
		}
		os.Setenv("TMPDIR", realTmp)

		// get the canonical path to the Docker root directory
		root := *flRoot
		var realRoot string
		if _, err := os.Stat(root); err != nil && os.IsNotExist(err) {
			realRoot = root
		} else {
			realRoot, err = utils.ReadSymlinkedDirectory(root)
			if err != nil {
				log.Fatalf("Unable to get the full path to root (%s): %s", root, err)
			}
		}
		if err := checkKernelAndArch(); err != nil {
			log.Fatal(err)
		}

		eng := engine.New()
		// Load builtins
		if err := builtins.Register(eng); err != nil {
			log.Fatal(err)
		}
		// load the daemon in the background so we can immediately start
		// the http api so that connections don't fail while the daemon
		// is booting
		go func() {
			// Load plugin: httpapi
			job := eng.Job("initserver")
			job.Setenv("Pidfile", *pidfile)
			job.Setenv("Root", realRoot)
			job.SetenvBool("AutoRestart", *flAutoRestart)
			job.SetenvList("Dns", flDns.GetAll())
			job.SetenvList("DnsSearch", flDnsSearch.GetAll())
			job.SetenvBool("EnableIptables", *flEnableIptables)
			job.SetenvBool("EnableIpForward", *flEnableIpForward)
			job.Setenv("BridgeIface", *bridgeName)
			job.Setenv("BridgeIP", *bridgeIp)
			job.Setenv("DefaultIp", *flDefaultIp)
			job.SetenvBool("InterContainerCommunication", *flInterContainerComm)
			job.Setenv("GraphDriver", *flGraphDriver)
			job.SetenvList("GraphOptions", flGraphOpts.GetAll())
			job.Setenv("ExecDriver", *flExecDriver)
			job.SetenvInt("Mtu", *flMtu)
			job.SetenvBool("EnableSelinuxSupport", *flSelinuxEnabled)
			job.SetenvList("Sockets", flHosts.GetAll())
			if err := job.Run(); err != nil {
				log.Fatal(err)
			}
			// after the daemon is done setting up we can tell the api to start
			// accepting connections
			if err := eng.Job("acceptconnections").Run(); err != nil {
				log.Fatal(err)
			}
		}()

		// TODO actually have a resolved graphdriver to show?
		log.Printf("docker daemon: %s %s; execdriver: %s; graphdriver: %s",
			dockerversion.VERSION,
			dockerversion.GITCOMMIT,
			*flExecDriver,
			*flGraphDriver)

		// Serve api
		job := eng.Job("serveapi", flHosts.GetAll()...)
		job.SetenvBool("Logging", true)
		job.SetenvBool("EnableCors", *flEnableCors)
		job.Setenv("Version", dockerversion.VERSION)
		job.Setenv("SocketGroup", *flSocketGroup)

		job.SetenvBool("Tls", *flTls)
		job.SetenvBool("TlsVerify", *flTlsVerify)
		job.Setenv("TlsCa", *flCa)
		job.Setenv("TlsCert", *flCert)
		job.Setenv("TlsKey", *flKey)
		job.SetenvBool("BufferRequests", true)
		if err := job.Run(); err != nil {
			log.Fatal(err)
		}
	} else {
		if flHosts.Len() > 1 {
			log.Fatal("Please specify only one -H")
		}
		protoAddrParts := strings.SplitN(flHosts.GetAll()[0], "://", 2)

		var (
			cli       *client.DockerCli
			tlsConfig tls.Config
		)
		tlsConfig.InsecureSkipVerify = true

		// If we should verify the server, we need to load a trusted ca
		if *flTlsVerify {
			*flTls = true
			certPool := x509.NewCertPool()
			file, err := ioutil.ReadFile(*flCa)
			if err != nil {
				log.Fatalf("Couldn't read ca cert %s: %s", *flCa, err)
			}
			certPool.AppendCertsFromPEM(file)
			tlsConfig.RootCAs = certPool
			tlsConfig.InsecureSkipVerify = false
		}

		// If tls is enabled, try to load and send client certificates
		if *flTls || *flTlsVerify {
			_, errCert := os.Stat(*flCert)
			_, errKey := os.Stat(*flKey)
			if errCert == nil && errKey == nil {
				*flTls = true
				cert, err := tls.LoadX509KeyPair(*flCert, *flKey)
				if err != nil {
					log.Fatalf("Couldn't load X509 key pair: %s. Key encrypted?", err)
				}
				tlsConfig.Certificates = []tls.Certificate{cert}
			}
		}

		if *flTls || *flTlsVerify {
			cli = client.NewDockerCli(os.Stdin, os.Stdout, os.Stderr, protoAddrParts[0], protoAddrParts[1], &tlsConfig)
		} else {
			cli = client.NewDockerCli(os.Stdin, os.Stdout, os.Stderr, protoAddrParts[0], protoAddrParts[1], nil)
		}

		if err := cli.ParseCommands(flag.Args()...); err != nil {
			if sterr, ok := err.(*utils.StatusError); ok {
				if sterr.Status != "" {
					log.Println(sterr.Status)
				}
				os.Exit(sterr.StatusCode)
			}
			log.Fatal(err)
		}
	}
}

func showVersion() {
	fmt.Printf("Docker version %s, build %s\n", dockerversion.VERSION, dockerversion.GITCOMMIT)
}

func checkKernelAndArch() error {
	// Check for unsupported architectures
	if runtime.GOARCH != "amd64" {
		return fmt.Errorf("The Docker runtime currently only supports amd64 (not %s). This will change in the future. Aborting.", runtime.GOARCH)
	}
	// Check for unsupported kernel versions
	// FIXME: it would be cleaner to not test for specific versions, but rather
	// test for specific functionalities.
	// Unfortunately we can't test for the feature "does not cause a kernel panic"
	// without actually causing a kernel panic, so we need this workaround until
	// the circumstances of pre-3.8 crashes are clearer.
	// For details see http://github.com/dotcloud/docker/issues/407
	if k, err := utils.GetKernelVersion(); err != nil {
		log.Printf("WARNING: %s\n", err)
	} else {
		if utils.CompareKernelVersion(k, &utils.KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0}) < 0 {
			if os.Getenv("DOCKER_NOWARN_KERNEL_VERSION") == "" {
				log.Printf("WARNING: You are running linux kernel version %s, which might be unstable running docker. Please upgrade your kernel to 3.8.0.", k.String())
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/url"
	"os"
	"strconv"

	"github.com/PuerkitoBio/goquery"
	log "github.com/Sirupsen/logrus"
	"github.com/docopt/docopt-go"
	"github.com/headzoo/surf"
	"github.com/headzoo/surf/browser"
)

func init() {
	log.SetOutput(os.Stderr)
	log.SetLevel(log.InfoLevel)
}

// A Clinet provides access to manage automated builds on https://hub.docker.com.
type Client struct {
	br *browser.Browser
}

// NewClient creates a Client to https://hub.docker.com imitating a
// user logging in, with a real browser.
func NewClient(username, password string) (*Client, error) {
	c := &Client{}
	c.br = surf.NewBrowser()
	err := c.br.Open("https://hub.docker.com/account/login/")
	if err != nil {
		return nil, err
	}
	fm, err := c.br.Form("#form-login")
	if err != nil {
		return nil, err
	} else {
		log.Debug("Login form found")
	}

	fm.Input("username", username)
	fm.Input("password", password)
	err = fm.Submit()

	if err != nil {
		return nil, err
	} else {
		log.Debug("Login success")
	}
	return c, nil
}

// AddTag creates a new automated build. The branch argument can be any git reference:
// tag or branch.  Repo argument defines the full name of the image: myslef/myrepo.
// Location is the Dockerfile path inside of the repo. Use "/" if it is
// placed in root. The tagName argument is used for image name: myself/myrepo:tagName
func (c *Client) AddTag(repo, tagName, branch, location string) error {

	repoUrl := "https://registry.hub.docker.com/u/" + repo + "/"
	err := c.br.Open(repoUrl)
	if err != nil {
		return fmt.Errorf("Couldn't open repo page:%s, error:%s", repoUrl, err)
	} else {
		log.Debug("Repo page opened successfully:", repoUrl)
	}
	err = c.br.Click("ul.nav-tabs li:nth-child(3) a")
	if err != nil {
		return fmt.Errorf("Couldn't navigate to 'Build details' tab! Is it an automated image? error:%s", err)
	}
	//fmt.Println(c.br.Body())
	err = c.br.Click("#repo-info-tab div.repository a:first-child")
	if err != nil {
		return fmt.Errorf("Couldn't navigate to 'Edit Build Details' error:%s", err)
	}

	vals := url.Values{}
	inputs := c.br.Find("#mainform input")
	inputs.Each(func(i int, s *goquery.Selection) {
		type_, _ := s.Attr("type")
		if type_ == "submit" {
			return
		}
		name, _ := s.Attr("name")
		value, _ := s.Attr("value")
		checked, _ := s.Attr("checked")
		if checked == "checked" {
			value = "on"
		}
		if value == "" {
			return
		}
		vals.Set(name, value)
	})
	selects := c.br.Find("#mainform select")
	selects.Each(func(i int, s *goquery.Selection) {
		name, _ := s.Attr("name")
		selected := s.Find("option[selected=selected]")
		value, _ := selected.Attr("value")
		vals.Set(name, value)
	})
	newId, _ := c.br.Find("#id_trusted_builds-TOTAL_FORMS").Attr("value")
	data := map[string]string{
		"source_type":         "Branch",
		"source_name":         branch,
		"dockerfile_location": location,
		"name":                tagName,
	}
	for k, v := range data {
		vals.Set("trusted_builds-"+newId+"-"+k, v)
	}
	i, err := strconv.ParseInt(newId, 10, 0)
	i = i + 1
	vals.Set("trusted_builds-TOTAL_FORMS", strconv.Itoa(int(i)))
	log.Debug("trusted_build form fields:")
	for k, v := range vals {
		log.Debugf("  %s=%s", k, v)
	}

	log.Debug("Cookies")
	for _, v := range c.br.SiteCookies() {
		log.Debugf("  %s: %s", v.Name, v.Value)
	}
	//time.Sleep(1 * time.Second)
	err = c.br.PostForm(c.br.Url().String(), vals)
	//fm, err = c.br.Form("#mainform")
	if err != nil {
		return fmt.Errorf("Posting new tag failed, error:%s", err)
	}
	log.Info("Tag created: %s:%s", repo, tagName)
	return nil
}

func main() {
	usage := `Usage:
  dockerhub-tag create <repo> <tagname> <branch> <location>   [--verbose|-v]
  dockerhub-tag delete <repo> <tagname>                       [--verbose|-v]

Options:
  -h --help         this message
  -v --verbose      verbose mode`

	ver := fmt.Sprintf("DockerHub Tagger: 0.1.0")
	args, _ := docopt.Parse(usage, nil, true, ver, false)

	if args["--verbose"].(bool) {
		log.SetLevel(log.DebugLevel)
	}

	dhc, err := NewClient(
		os.Getenv("DOCKERHUB_USERNAME"),
		os.Getenv("DOCKERHUB_PASSWORD"),
	)

	if args["create"].(bool) {
		err = dhc.AddTag(
			args["<repo>"].(string),
			args["<tagname>"].(string),
			args["<branch>"].(string),
			args["<location>"].(string),
		)
		if err != nil {
			panic(err)
		}
	}

}
<commit_msg>change the general term tag to more specific dockerTag and gitTag<commit_after>package main

import (
	"fmt"
	"net/url"
	"os"
	"strconv"

	"github.com/PuerkitoBio/goquery"
	log "github.com/Sirupsen/logrus"
	"github.com/docopt/docopt-go"
	"github.com/headzoo/surf"
	"github.com/headzoo/surf/browser"
)

func init() {
	log.SetOutput(os.Stderr)
	log.SetLevel(log.InfoLevel)
}

// A Clinet provides access to manage automated builds on https://hub.docker.com.
type Client struct {
	br *browser.Browser
}

// NewClient creates a Client to https://hub.docker.com imitating a
// user logging in, with a real browser.
func NewClient(username, password string) (*Client, error) {
	c := &Client{}
	c.br = surf.NewBrowser()
	err := c.br.Open("https://hub.docker.com/account/login/")
	if err != nil {
		return nil, err
	}
	fm, err := c.br.Form("#form-login")
	if err != nil {
		return nil, err
	} else {
		log.Debug("Login form found")
	}

	fm.Input("username", username)
	fm.Input("password", password)
	err = fm.Submit()

	if err != nil {
		return nil, err
	} else {
		log.Debug("Login success")
	}
	return c, nil
}

// AddTag creates a new automated build. The gitTag argument can be any git reference:
// tag or branch.  Repo argument defines the full name of the image: myslef/myrepo.
// Location is the Dockerfile path inside of the repo. Use "/" if it is
// placed in root. The dockerTag argument is used for image name: myself/myrepo:dockerTag
func (c *Client) AddTag(repo, dockerTag, gitTag, location string) error {

	repoUrl := "https://registry.hub.docker.com/u/" + repo + "/"
	err := c.br.Open(repoUrl)
	if err != nil {
		return fmt.Errorf("Couldn't open repo page:%s, error:%s", repoUrl, err)
	} else {
		log.Debug("Repo page opened successfully:", repoUrl)
	}
	err = c.br.Click("ul.nav-tabs li:nth-child(3) a")
	if err != nil {
		return fmt.Errorf("Couldn't navigate to 'Build details' tab! Is it an automated image? error:%s", err)
	}
	//fmt.Println(c.br.Body())
	err = c.br.Click("#repo-info-tab div.repository a:first-child")
	if err != nil {
		return fmt.Errorf("Couldn't navigate to 'Edit Build Details' error:%s", err)
	}

	vals := url.Values{}
	inputs := c.br.Find("#mainform input")
	inputs.Each(func(i int, s *goquery.Selection) {
		type_, _ := s.Attr("type")
		if type_ == "submit" {
			return
		}
		name, _ := s.Attr("name")
		value, _ := s.Attr("value")
		checked, _ := s.Attr("checked")
		if checked == "checked" {
			value = "on"
		}
		if value == "" {
			return
		}
		vals.Set(name, value)
	})
	selects := c.br.Find("#mainform select")
	selects.Each(func(i int, s *goquery.Selection) {
		name, _ := s.Attr("name")
		selected := s.Find("option[selected=selected]")
		value, _ := selected.Attr("value")
		vals.Set(name, value)
	})
	newId, _ := c.br.Find("#id_trusted_builds-TOTAL_FORMS").Attr("value")
	data := map[string]string{
		"source_type":         "Tag",
		"source_name":         gitTag,
		"dockerfile_location": location,
		"name":                dockerTag,
	}
	for k, v := range data {
		vals.Set("trusted_builds-"+newId+"-"+k, v)
	}
	i, err := strconv.ParseInt(newId, 10, 0)
	i = i + 1
	vals.Set("trusted_builds-TOTAL_FORMS", strconv.Itoa(int(i)))
	log.Debug("trusted_build form fields:")
	for k, v := range vals {
		log.Debugf("  %s=%s", k, v)
	}

	log.Debug("Cookies")
	for _, v := range c.br.SiteCookies() {
		log.Debugf("  %s: %s", v.Name, v.Value)
	}
	//time.Sleep(1 * time.Second)
	err = c.br.PostForm(c.br.Url().String(), vals)
	//fm, err = c.br.Form("#mainform")
	if err != nil {
		return fmt.Errorf("Posting new tag failed, error:%s", err)
	}
	log.Info("Tag created: %s:%s", repo, dockerTag)
	return nil
}

func main() {
	usage := `Usage:
  dockerhub-tag create <repo> <dockerTag> <gitTag> <location>   [--verbose|-v]
  dockerhub-tag delete <repo> <dockerTag>                       [--verbose|-v]

Options:
  -h --help         this message
  -v --verbose      verbose mode`

	ver := fmt.Sprintf("DockerHub Tagger: 0.1.0")
	args, _ := docopt.Parse(usage, nil, true, ver, false)

	if args["--verbose"].(bool) {
		log.SetLevel(log.DebugLevel)
	}

	dhc, err := NewClient(
		os.Getenv("DOCKERHUB_USERNAME"),
		os.Getenv("DOCKERHUB_PASSWORD"),
	)

	if args["create"].(bool) {
		err = dhc.AddTag(
			args["<repo>"].(string),
			args["<dockerTag>"].(string),
			args["<gitTag>"].(string),
			args["<location>"].(string),
		)
		if err != nil {
			panic(err)
		}
	}

}
<|endoftext|>


<commit_before>package tme

import "time"

// Ack is sent by Ticker and Timer on each tick and when done (respectively
type Ack struct {
	// Time is the time the tick started or the timer was done
	Time time.Time
	// Fn is the function that the receiver of the tick or done signal may call to acknowledge receipt.
	// Some Ticker/Timer implementations provide a feedback mechanism for other goroutines
	// to be notified of the acks, which can be used for backoff or rate limiting purposes.
	// This func must never block.
	Fn func()
}
<commit_msg>docs upgrade<commit_after>package tme

import "time"

// Ack is sent by Ticker and Timer on each tick or when done (respectively)
type Ack struct {
	// Time is the time the tick started or the timer was done
	Time time.Time
	// Fn is the function that the receiver of the tick or done signal may call to acknowledge receipt.
	// Some Ticker/Timer implementations provide a feedback mechanism for other goroutines
	// to be notified of the acks, which can be used for backoff or rate limiting purposes.
	// This func must never block.
	Fn func()
}
<|endoftext|>


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

package ct

import (
	"crypto/sha256"
	"errors"
	"fmt"
	"time"

	ct "github.com/google/certificate-transparency/go"
	"github.com/google/certificate-transparency/go/tls"
	"github.com/google/certificate-transparency/go/x509"
	"github.com/google/trillian/crypto"
	"github.com/google/trillian/crypto/keys"
)

// signV1TreeHead signs a tree head for CT. The input STH should have been built from a
// backend response and already checked for validity.
func signV1TreeHead(signer *crypto.Signer, sth *ct.SignedTreeHead) error {
	sthBytes, err := ct.SerializeSTHSignatureInput(*sth)
	if err != nil {
		return err
	}

	signature, err := signer.Sign(sthBytes)
	if err != nil {
		return err
	}

	sth.TreeHeadSignature = ct.DigitallySigned{
		Algorithm: tls.SignatureAndHashAlgorithm{
			Hash: tls.SHA256,
			// This relies on the protobuf enum values matching the TLS-defined values.
			Signature: tls.SignatureAlgorithm(keys.SignatureAlgorithm(signer.Public())),
		},
		Signature: signature.Signature,
	}
	return nil
}

// signV1SCTForCertificate creates a MerkleTreeLeaf and builds and signs a V1 CT SCT for a certificate
// using the key held by a key manager.
func signV1SCTForCertificate(signer *crypto.Signer, cert, issuer *x509.Certificate, t time.Time) (*ct.MerkleTreeLeaf, *ct.SignedCertificateTimestamp, error) {
	sctInput := ct.SignedCertificateTimestamp{
		SCTVersion: ct.V1,
		Timestamp:  uint64(t.UnixNano() / millisPerNano),
		Extensions: ct.CTExtensions{},
	}

	// Build up a MerkleTreeLeaf for the cert
	leaf := ct.MerkleTreeLeaf{
		Version:  ct.V1,
		LeafType: ct.TimestampedEntryLeafType,
		TimestampedEntry: &ct.TimestampedEntry{
			Timestamp: sctInput.Timestamp,
			EntryType: ct.X509LogEntryType,
			X509Entry: &ct.ASN1Cert{Data: cert.Raw},
		},
	}
	sct, err := serializeAndSignSCT(signer, leaf, sctInput, t)
	if err != nil {
		return nil, nil, err
	}
	return &leaf, sct, nil
}

// signV1SCTForPrecertificate builds and signs a V1 CT SCT for a pre-certificate using the key
// held by a key manager.
func signV1SCTForPrecertificate(signer *crypto.Signer, cert, issuer *x509.Certificate, t time.Time) (*ct.MerkleTreeLeaf, *ct.SignedCertificateTimestamp, error) {
	if issuer == nil {
		// Need issuer for the IssuerKeyHash
		return nil, nil, errors.New("no issuer available for pre-certificate")
	}
	sctInput := ct.SignedCertificateTimestamp{
		SCTVersion: ct.V1,
		Timestamp:  uint64(t.UnixNano() / millisPerNano),
		Extensions: ct.CTExtensions{},
	}

	// Build up a LogEntry for the precert
	// For precerts we need to extract the relevant data from the Certificate container,
	// specifically the DER-encoded TBSCertificate, but with the CT poison extension removed.
	// (This is only possible using the CT specific modified version of the x509 library.)
	keyHash := sha256.Sum256(issuer.RawSubjectPublicKeyInfo)
	defangedTBS, err := x509.RemoveCTPoison(cert.RawTBSCertificate)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to remove poison extension: %v", err)
	}
	precert := ct.PreCert{
		IssuerKeyHash:  keyHash,
		TBSCertificate: defangedTBS,
	}

	timestampedEntry := ct.TimestampedEntry{
		Timestamp:    sctInput.Timestamp,
		EntryType:    ct.PrecertLogEntryType,
		PrecertEntry: &precert,
	}
	leaf := ct.MerkleTreeLeaf{
		Version:          ct.V1,
		LeafType:         ct.TimestampedEntryLeafType,
		TimestampedEntry: &timestampedEntry,
	}

	sct, err := serializeAndSignSCT(signer, leaf, sctInput, t)
	if err != nil {
		return nil, nil, err
	}
	return &leaf, sct, err
}

func serializeAndSignSCT(signer *crypto.Signer, leaf ct.MerkleTreeLeaf, sctInput ct.SignedCertificateTimestamp, t time.Time) (*ct.SignedCertificateTimestamp, error) {
	// Serialize SCT signature input to get the bytes that need to be signed
	data, err := ct.SerializeSCTSignatureInput(sctInput, ct.LogEntry{Leaf: leaf})
	if err != nil {
		return nil, fmt.Errorf("failed to serialize SCT data: %v", err)
	}

	signature, err := signer.Sign(data)
	if err != nil {
		return nil, fmt.Errorf("failed to sign SCT data: %v", err)
	}

	digitallySigned := ct.DigitallySigned{
		Algorithm: tls.SignatureAndHashAlgorithm{
			Hash: tls.SHA256,
			// This relies on the protobuf enum values matching the TLS-defined values.
			Signature: tls.SignatureAlgorithm(keys.SignatureAlgorithm(signer.Public())),
		},
		Signature: signature.Signature,
	}

	logID, err := GetCTLogID(signer.Public())
	if err != nil {
		return nil, fmt.Errorf("failed to get logID for signing: %v", err)
	}

	return &ct.SignedCertificateTimestamp{
		SCTVersion: ct.V1,
		LogID:      ct.LogID{KeyID: logID},
		Timestamp:  uint64(t.UnixNano() / millisPerNano), // spec uses millisecond timestamps
		Extensions: ct.CTExtensions{},
		Signature:  digitallySigned,
	}, nil
}
<commit_msg>examples/ct: use same timestamp in leaf and SCT<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ct

import (
	"crypto/sha256"
	"errors"
	"fmt"
	"time"

	ct "github.com/google/certificate-transparency/go"
	"github.com/google/certificate-transparency/go/tls"
	"github.com/google/certificate-transparency/go/x509"
	"github.com/google/trillian/crypto"
	"github.com/google/trillian/crypto/keys"
)

// signV1TreeHead signs a tree head for CT. The input STH should have been built from a
// backend response and already checked for validity.
func signV1TreeHead(signer *crypto.Signer, sth *ct.SignedTreeHead) error {
	sthBytes, err := ct.SerializeSTHSignatureInput(*sth)
	if err != nil {
		return err
	}

	signature, err := signer.Sign(sthBytes)
	if err != nil {
		return err
	}

	sth.TreeHeadSignature = ct.DigitallySigned{
		Algorithm: tls.SignatureAndHashAlgorithm{
			Hash: tls.SHA256,
			// This relies on the protobuf enum values matching the TLS-defined values.
			Signature: tls.SignatureAlgorithm(keys.SignatureAlgorithm(signer.Public())),
		},
		Signature: signature.Signature,
	}
	return nil
}

// signV1SCTForCertificate creates a MerkleTreeLeaf and builds and signs a V1 CT SCT for a certificate
// using the key held by a key manager.
func signV1SCTForCertificate(signer *crypto.Signer, cert, issuer *x509.Certificate, t time.Time) (*ct.MerkleTreeLeaf, *ct.SignedCertificateTimestamp, error) {
	sctInput := ct.SignedCertificateTimestamp{
		SCTVersion: ct.V1,
		Timestamp:  uint64(t.UnixNano() / millisPerNano),
		Extensions: ct.CTExtensions{},
	}

	// Build up a MerkleTreeLeaf for the cert
	leaf := ct.MerkleTreeLeaf{
		Version:  ct.V1,
		LeafType: ct.TimestampedEntryLeafType,
		TimestampedEntry: &ct.TimestampedEntry{
			Timestamp: sctInput.Timestamp,
			EntryType: ct.X509LogEntryType,
			X509Entry: &ct.ASN1Cert{Data: cert.Raw},
		},
	}
	sct, err := serializeAndSignSCT(signer, leaf, sctInput)
	if err != nil {
		return nil, nil, err
	}
	return &leaf, sct, nil
}

// signV1SCTForPrecertificate builds and signs a V1 CT SCT for a pre-certificate using the key
// held by a key manager.
func signV1SCTForPrecertificate(signer *crypto.Signer, cert, issuer *x509.Certificate, t time.Time) (*ct.MerkleTreeLeaf, *ct.SignedCertificateTimestamp, error) {
	if issuer == nil {
		// Need issuer for the IssuerKeyHash
		return nil, nil, errors.New("no issuer available for pre-certificate")
	}
	sctInput := ct.SignedCertificateTimestamp{
		SCTVersion: ct.V1,
		Timestamp:  uint64(t.UnixNano() / millisPerNano),
		Extensions: ct.CTExtensions{},
	}

	// Build up a LogEntry for the precert
	// For precerts we need to extract the relevant data from the Certificate container,
	// specifically the DER-encoded TBSCertificate, but with the CT poison extension removed.
	// (This is only possible using the CT specific modified version of the x509 library.)
	keyHash := sha256.Sum256(issuer.RawSubjectPublicKeyInfo)
	defangedTBS, err := x509.RemoveCTPoison(cert.RawTBSCertificate)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to remove poison extension: %v", err)
	}
	precert := ct.PreCert{
		IssuerKeyHash:  keyHash,
		TBSCertificate: defangedTBS,
	}

	timestampedEntry := ct.TimestampedEntry{
		Timestamp:    sctInput.Timestamp,
		EntryType:    ct.PrecertLogEntryType,
		PrecertEntry: &precert,
	}
	leaf := ct.MerkleTreeLeaf{
		Version:          ct.V1,
		LeafType:         ct.TimestampedEntryLeafType,
		TimestampedEntry: &timestampedEntry,
	}

	sct, err := serializeAndSignSCT(signer, leaf, sctInput)
	if err != nil {
		return nil, nil, err
	}
	return &leaf, sct, err
}

func serializeAndSignSCT(signer *crypto.Signer, leaf ct.MerkleTreeLeaf, sctInput ct.SignedCertificateTimestamp) (*ct.SignedCertificateTimestamp, error) {
	// Serialize SCT signature input to get the bytes that need to be signed
	data, err := ct.SerializeSCTSignatureInput(sctInput, ct.LogEntry{Leaf: leaf})
	if err != nil {
		return nil, fmt.Errorf("failed to serialize SCT data: %v", err)
	}

	signature, err := signer.Sign(data)
	if err != nil {
		return nil, fmt.Errorf("failed to sign SCT data: %v", err)
	}

	digitallySigned := ct.DigitallySigned{
		Algorithm: tls.SignatureAndHashAlgorithm{
			Hash: tls.SHA256,
			// This relies on the protobuf enum values matching the TLS-defined values.
			Signature: tls.SignatureAlgorithm(keys.SignatureAlgorithm(signer.Public())),
		},
		Signature: signature.Signature,
	}

	logID, err := GetCTLogID(signer.Public())
	if err != nil {
		return nil, fmt.Errorf("failed to get logID for signing: %v", err)
	}

	return &ct.SignedCertificateTimestamp{
		SCTVersion: ct.V1,
		LogID:      ct.LogID{KeyID: logID},
		Timestamp:  sctInput.Timestamp,
		Extensions: ct.CTExtensions{},
		Signature:  digitallySigned,
	}, nil
}
<|endoftext|>


<commit_before>package kite

import (
	"testing"
)

func testSplitVersion(t *testing.T) {
	name, version, err := splitVersion("asdf-1.2.3")
	if err != nil {
		t.Error(err)
	}
	if name != "asdf" {
		t.Error("Name is not ok:", name)
	}
	if version != "1.2.3" {
		t.Error("Version is not ok:", version)
	}

	name, version, err = splitVersion("asdf")
	if err == nil {
		t.Error(err)
	}
}
<commit_msg>fix a test<commit_after>package kite

import (
	"testing"
)

func testSplitVersion(t *testing.T) {
	name, version, err := splitVersion("asdf-1.2.3", false)
	if err != nil {
		t.Error(err)
	}
	if name != "asdf" {
		t.Error("Name is not ok:", name)
	}
	if version != "1.2.3" {
		t.Error("Version is not ok:", version)
	}

	name, version, err = splitVersion("asdf", false)
	if err == nil {
		t.Error(err)
	}
}
<|endoftext|>


<commit_before>package virtualbox

import (
	"github.com/mitchellh/packer/packer"
	"io/ioutil"
	"os"
	"reflect"
	"testing"
)

func testConfig() map[string]interface{} {
	return map[string]interface{}{
		"iso_md5":      "foo",
		"iso_url":      "http://www.google.com/",
		"ssh_username": "foo",

		packer.BuildNameConfigKey: "foo",
	}
}

func TestBuilder_ImplementsBuilder(t *testing.T) {
	var raw interface{}
	raw = &Builder{}
	if _, ok := raw.(packer.Builder); !ok {
		t.Error("Builder must implement builder.")
	}
}

func TestBuilderPrepare_Defaults(t *testing.T) {
	var b Builder
	config := testConfig()
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.GuestOSType != "Other" {
		t.Errorf("bad guest OS type: %s", b.config.GuestOSType)
	}

	if b.config.OutputDir != "output-foo" {
		t.Errorf("bad output dir: %s", b.config.OutputDir)
	}

	if b.config.SSHHostPortMin != 2222 {
		t.Errorf("bad min ssh host port: %d", b.config.SSHHostPortMin)
	}

	if b.config.SSHHostPortMax != 4444 {
		t.Errorf("bad max ssh host port: %d", b.config.SSHHostPortMax)
	}

	if b.config.SSHPort != 22 {
		t.Errorf("bad ssh port: %d", b.config.SSHPort)
	}

	if b.config.VMName != "packer-foo" {
		t.Errorf("bad vm name: %s", b.config.VMName)
	}
}

func TestBuilderPrepare_BootWait(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test a default boot_wait
	delete(config, "boot_wait")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if b.config.RawBootWait != "10s" {
		t.Fatalf("bad value: %s", b.config.RawBootWait)
	}

	// Test with a bad boot_wait
	config["boot_wait"] = "this is not good"
	err = b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Test with a good one
	config["boot_wait"] = "5s"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_DiskSize(t *testing.T) {
	var b Builder
	config := testConfig()

	delete(config, "disk_size")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("bad err: %s", err)
	}

	if b.config.DiskSize != 40000 {
		t.Fatalf("bad size: %d", b.config.DiskSize)
	}

	config["disk_size"] = 60000
	b = Builder{}
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.DiskSize != 60000 {
		t.Fatalf("bad size: %s", b.config.DiskSize)
	}
}

func TestBuilderPrepare_GuestAdditionsPath(t *testing.T) {
	var b Builder
	config := testConfig()

	delete(config, "disk_size")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("bad err: %s", err)
	}

	if b.config.GuestAdditionsPath != "VBoxGuestAdditions.iso" {
		t.Fatalf("bad: %s", b.config.GuestAdditionsPath)
	}

	config["guest_additions_path"] = "foo"
	b = Builder{}
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.GuestAdditionsPath != "foo" {
		t.Fatalf("bad size: %s", b.config.GuestAdditionsPath)
	}
}

func TestBuilderPrepare_HTTPPort(t *testing.T) {
	var b Builder
	config := testConfig()

	// Bad
	config["http_port_min"] = 1000
	config["http_port_max"] = 500
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Bad
	config["http_port_min"] = -500
	err = b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Good
	config["http_port_min"] = 500
	config["http_port_max"] = 1000
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_ISOMD5(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test bad
	config["iso_md5"] = ""
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Test good
	config["iso_md5"] = "FOo"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.ISOMD5 != "foo" {
		t.Fatalf("should've lowercased: %s", b.config.ISOMD5)
	}
}

func TestBuilderPrepare_ISOUrl(t *testing.T) {
	var b Builder
	config := testConfig()

	config["iso_url"] = ""
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	config["iso_url"] = "i/am/a/file/that/doesnt/exist"
	err = b.Prepare(config)
	if err == nil {
		t.Error("should have error")
	}

	config["iso_url"] = "file:i/am/a/file/that/doesnt/exist"
	err = b.Prepare(config)
	if err == nil {
		t.Error("should have error")
	}

	config["iso_url"] = "http://www.packer.io"
	err = b.Prepare(config)
	if err != nil {
		t.Errorf("should not have error: %s", err)
	}

	tf, err := ioutil.TempFile("", "packer")
	if err != nil {
		t.Fatalf("error tempfile: %s", err)
	}
	defer os.Remove(tf.Name())

	config["iso_url"] = tf.Name()
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.ISOUrl != "file://"+tf.Name() {
		t.Fatalf("iso_url should be modified: %s", b.config.ISOUrl)
	}
}

func TestBuilderPrepare_OutputDir(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test with existing dir
	dir, err := ioutil.TempDir("", "packer")
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	defer os.RemoveAll(dir)

	config["output_directory"] = dir
	err = b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Test with a good one
	config["output_directory"] = "i-hope-i-dont-exist"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_ShutdownTimeout(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test with a bad value
	config["shutdown_timeout"] = "this is not good"
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Test with a good one
	config["shutdown_timeout"] = "5s"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_SSHHostPort(t *testing.T) {
	var b Builder
	config := testConfig()

	// Bad
	config["ssh_host_port_min"] = 1000
	config["ssh_host_port_max"] = 500
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Bad
	config["ssh_host_port_min"] = -500
	err = b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Good
	config["ssh_host_port_min"] = 500
	config["ssh_host_port_max"] = 1000
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_SSHUser(t *testing.T) {
	var b Builder
	config := testConfig()

	config["ssh_username"] = ""
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	config["ssh_username"] = "exists"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_SSHWaitTimeout(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test a default boot_wait
	delete(config, "ssh_wait_timeout")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if b.config.RawSSHWaitTimeout != "20m" {
		t.Fatalf("bad value: %s", b.config.RawSSHWaitTimeout)
	}

	// Test with a bad value
	config["ssh_wait_timeout"] = "this is not good"
	err = b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Test with a good one
	config["ssh_wait_timeout"] = "5s"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_VBoxManage(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test with empty
	delete(config, "vboxmanage")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if !reflect.DeepEqual(b.config.VBoxManage, [][]string{}) {
		t.Fatalf("bad: %#v", b.config.VBoxManage)
	}

	// Test with a good one
	config["vboxmanage"] = [][]interface{}{
		[]interface{}{"foo", "bar", "baz"},
	}

	b = Builder{}
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	expected := [][]string{
		[]string{"foo", "bar", "baz"},
	}

	if !reflect.DeepEqual(b.config.VBoxManage, expected) {
		t.Fatalf("bad: %#v", b.config.VBoxManage)
	}
}

func TestBuilderPrepare_VBoxVersionFile(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test empty
	delete(config, "virtualbox_version_file")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if b.config.VBoxVersionFile != ".vbox_version" {
		t.Fatalf("bad value: %s", b.config.VBoxVersionFile)
	}

	// Test with a good one
	config["virtualbox_version_file"] = "foo"
	b = Builder{}
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.VBoxVersionFile != "foo" {
		t.Fatalf("bad value: %s", b.config.VBoxVersionFile)
	}
}
<commit_msg>builder/virtualbox: typo in test<commit_after>package virtualbox

import (
	"github.com/mitchellh/packer/packer"
	"io/ioutil"
	"os"
	"reflect"
	"testing"
)

func testConfig() map[string]interface{} {
	return map[string]interface{}{
		"iso_md5":      "foo",
		"iso_url":      "http://www.google.com/",
		"ssh_username": "foo",

		packer.BuildNameConfigKey: "foo",
	}
}

func TestBuilder_ImplementsBuilder(t *testing.T) {
	var raw interface{}
	raw = &Builder{}
	if _, ok := raw.(packer.Builder); !ok {
		t.Error("Builder must implement builder.")
	}
}

func TestBuilderPrepare_Defaults(t *testing.T) {
	var b Builder
	config := testConfig()
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.GuestOSType != "Other" {
		t.Errorf("bad guest OS type: %s", b.config.GuestOSType)
	}

	if b.config.OutputDir != "output-foo" {
		t.Errorf("bad output dir: %s", b.config.OutputDir)
	}

	if b.config.SSHHostPortMin != 2222 {
		t.Errorf("bad min ssh host port: %d", b.config.SSHHostPortMin)
	}

	if b.config.SSHHostPortMax != 4444 {
		t.Errorf("bad max ssh host port: %d", b.config.SSHHostPortMax)
	}

	if b.config.SSHPort != 22 {
		t.Errorf("bad ssh port: %d", b.config.SSHPort)
	}

	if b.config.VMName != "packer-foo" {
		t.Errorf("bad vm name: %s", b.config.VMName)
	}
}

func TestBuilderPrepare_BootWait(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test a default boot_wait
	delete(config, "boot_wait")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if b.config.RawBootWait != "10s" {
		t.Fatalf("bad value: %s", b.config.RawBootWait)
	}

	// Test with a bad boot_wait
	config["boot_wait"] = "this is not good"
	err = b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Test with a good one
	config["boot_wait"] = "5s"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_DiskSize(t *testing.T) {
	var b Builder
	config := testConfig()

	delete(config, "disk_size")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("bad err: %s", err)
	}

	if b.config.DiskSize != 40000 {
		t.Fatalf("bad size: %d", b.config.DiskSize)
	}

	config["disk_size"] = 60000
	b = Builder{}
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.DiskSize != 60000 {
		t.Fatalf("bad size: %s", b.config.DiskSize)
	}
}

func TestBuilderPrepare_GuestAdditionsPath(t *testing.T) {
	var b Builder
	config := testConfig()

	delete(config, "guest_additions_path")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("bad err: %s", err)
	}

	if b.config.GuestAdditionsPath != "VBoxGuestAdditions.iso" {
		t.Fatalf("bad: %s", b.config.GuestAdditionsPath)
	}

	config["guest_additions_path"] = "foo"
	b = Builder{}
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.GuestAdditionsPath != "foo" {
		t.Fatalf("bad size: %s", b.config.GuestAdditionsPath)
	}
}

func TestBuilderPrepare_HTTPPort(t *testing.T) {
	var b Builder
	config := testConfig()

	// Bad
	config["http_port_min"] = 1000
	config["http_port_max"] = 500
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Bad
	config["http_port_min"] = -500
	err = b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Good
	config["http_port_min"] = 500
	config["http_port_max"] = 1000
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_ISOMD5(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test bad
	config["iso_md5"] = ""
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Test good
	config["iso_md5"] = "FOo"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.ISOMD5 != "foo" {
		t.Fatalf("should've lowercased: %s", b.config.ISOMD5)
	}
}

func TestBuilderPrepare_ISOUrl(t *testing.T) {
	var b Builder
	config := testConfig()

	config["iso_url"] = ""
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	config["iso_url"] = "i/am/a/file/that/doesnt/exist"
	err = b.Prepare(config)
	if err == nil {
		t.Error("should have error")
	}

	config["iso_url"] = "file:i/am/a/file/that/doesnt/exist"
	err = b.Prepare(config)
	if err == nil {
		t.Error("should have error")
	}

	config["iso_url"] = "http://www.packer.io"
	err = b.Prepare(config)
	if err != nil {
		t.Errorf("should not have error: %s", err)
	}

	tf, err := ioutil.TempFile("", "packer")
	if err != nil {
		t.Fatalf("error tempfile: %s", err)
	}
	defer os.Remove(tf.Name())

	config["iso_url"] = tf.Name()
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.ISOUrl != "file://"+tf.Name() {
		t.Fatalf("iso_url should be modified: %s", b.config.ISOUrl)
	}
}

func TestBuilderPrepare_OutputDir(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test with existing dir
	dir, err := ioutil.TempDir("", "packer")
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	defer os.RemoveAll(dir)

	config["output_directory"] = dir
	err = b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Test with a good one
	config["output_directory"] = "i-hope-i-dont-exist"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_ShutdownTimeout(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test with a bad value
	config["shutdown_timeout"] = "this is not good"
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Test with a good one
	config["shutdown_timeout"] = "5s"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_SSHHostPort(t *testing.T) {
	var b Builder
	config := testConfig()

	// Bad
	config["ssh_host_port_min"] = 1000
	config["ssh_host_port_max"] = 500
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Bad
	config["ssh_host_port_min"] = -500
	err = b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Good
	config["ssh_host_port_min"] = 500
	config["ssh_host_port_max"] = 1000
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_SSHUser(t *testing.T) {
	var b Builder
	config := testConfig()

	config["ssh_username"] = ""
	err := b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	config["ssh_username"] = "exists"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_SSHWaitTimeout(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test a default boot_wait
	delete(config, "ssh_wait_timeout")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if b.config.RawSSHWaitTimeout != "20m" {
		t.Fatalf("bad value: %s", b.config.RawSSHWaitTimeout)
	}

	// Test with a bad value
	config["ssh_wait_timeout"] = "this is not good"
	err = b.Prepare(config)
	if err == nil {
		t.Fatal("should have error")
	}

	// Test with a good one
	config["ssh_wait_timeout"] = "5s"
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}
}

func TestBuilderPrepare_VBoxManage(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test with empty
	delete(config, "vboxmanage")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if !reflect.DeepEqual(b.config.VBoxManage, [][]string{}) {
		t.Fatalf("bad: %#v", b.config.VBoxManage)
	}

	// Test with a good one
	config["vboxmanage"] = [][]interface{}{
		[]interface{}{"foo", "bar", "baz"},
	}

	b = Builder{}
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	expected := [][]string{
		[]string{"foo", "bar", "baz"},
	}

	if !reflect.DeepEqual(b.config.VBoxManage, expected) {
		t.Fatalf("bad: %#v", b.config.VBoxManage)
	}
}

func TestBuilderPrepare_VBoxVersionFile(t *testing.T) {
	var b Builder
	config := testConfig()

	// Test empty
	delete(config, "virtualbox_version_file")
	err := b.Prepare(config)
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if b.config.VBoxVersionFile != ".vbox_version" {
		t.Fatalf("bad value: %s", b.config.VBoxVersionFile)
	}

	// Test with a good one
	config["virtualbox_version_file"] = "foo"
	b = Builder{}
	err = b.Prepare(config)
	if err != nil {
		t.Fatalf("should not have error: %s", err)
	}

	if b.config.VBoxVersionFile != "foo" {
		t.Fatalf("bad value: %s", b.config.VBoxVersionFile)
	}
}
<|endoftext|>