<commit_before>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"
)

func main() {

	path := "."
	if len(os.Args) > 1 {
		path = os.Args[1]
	}

	absPath, err := filepath.Abs(path)
	if err != nil {
		panic(err)
	}

	if _, err := os.Stat(absPath); os.IsNotExist(err) {
		fmt.Printf("no such file or directory: %s\n", absPath)
	}

	os.Chdir(absPath)

	url := retrieveURL()
	if url != "" {
		openByBrowser(url)
	}

	readmeFileName := "README.md" // Should be configurable
	readmeFile, err := filepath.Abs(readmeFileName)
	if err != nil {
		panic(err)
	}

	if _, err := os.Stat(readmeFile); os.IsNotExist(err) {
		fmt.Printf("%s is not found, create it ? [Y/n]: ", readmeFile)

		var ans string
		_, err := fmt.Scanf("%s", &ans)

		if err != nil {
			panic(err)
		}

		if ans != "Y" {
			os.Exit(0)
		}
	}

	openByEdior(readmeFile)
}

func retrieveURL() string {

	urlPattern := "remote.origin.url" // Should be configurable
	gitConfigCmd := exec.Command("git", "config", "--local", urlPattern)

	url, err := gitConfigCmd.Output()
	if err != nil || len(url) == 0 {
		return ""
	}

	trimedURL := strings.TrimRight(string(url), "\n")
	fmt.Println("url: " + trimedURL)
	return trimedURL
}

func openByBrowser(url string) {
	openCmd := "open" // Only OSX or Linux
	execOpen(openCmd, url)
}

func openByEdior(filename string) {
	openCmd := os.Getenv("EDITOR")
	execOpen(openCmd, filename)
}

func execOpen(cmd string, target string) {

	binary, lookErr := exec.LookPath(cmd)
	if lookErr != nil {
		panic(lookErr)
	}

	args := []string{cmd, target}
	env := os.Environ()

	execErr := syscall.Exec(binary, args, env)
	if execErr != nil {
		panic(execErr)
	}
}
<commit_msg>Add flag option<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"

	flag "github.com/dotcloud/docker/pkg/mflag"
)

func main() {

	var (
		flVersion = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit")
		flHelp    = flag.Bool([]string{"h", "-help"}, false, "Print this message")
		flDebug   = flag.Bool([]string{"-debug"}, false, "Run as DEBUG mode")
		flEditor  = flag.Bool([]string{"e", "-editor"}, false, "Use Editor by default")
		flForce   = flag.Bool([]string{"f", "-force"}, false, "Create README file without prompting")
	)

	flag.Parse()

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

	if *flVersion {
		showVersion()
		fmt.Println(os.Args[1])
		os.Exit(0)
	}

	if *flHelp {
		flag.Usage()
		os.Exit(0)
	}

	path := "."
	if len(os.Args) > 1 {
		path = flag.Arg(0)
	}
	debug("path:", path)

	absPath, err := filepath.Abs(path)
	if err != nil {
		panic(err)
	}
	debug("url:", absPath)

	if _, err := os.Stat(absPath); os.IsNotExist(err) {
		fmt.Printf("no such file or directory: %s\n", absPath)
		os.Exit(1)
	}

	os.Chdir(absPath)

	url := retrieveURL()
	if !*flEditor && url != "" {
		openByBrowser(url)
	}

	readmeFile := retrieveReadmeFile(*flForce)
	if readmeFile != "" {
		openByEdior(readmeFile)
	}

	os.Exit(0)
}

func showVersion() {
	fmt.Println("docc version 0.1.0")
}

func debug(v ...interface{}) {
	if os.Getenv("DEBUG") != "" {
		log.Println(v...)
	}
}

func assert(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func retrieveURL() string {

	urlPattern := "remote.origin.url" // Should be configurable
	gitConfigCmd := exec.Command("git", "config", "--local", urlPattern)

	url, err := gitConfigCmd.Output()
	if err != nil || len(url) == 0 {
		return ""
	}

	trimedURL := strings.TrimRight(string(url), "\n")
	fmt.Println("url: " + trimedURL)
	return trimedURL
}

func retrieveReadmeFile(forceCreate bool) string {

	readmeFileName := "README.md" // Should be configurable
	readmeFile, err := filepath.Abs(readmeFileName)
	if err != nil {
		panic(err)
	}
	debug("readme:", readmeFile)

	if _, err := os.Stat(readmeFile); os.IsNotExist(err) && !forceCreate {
		fmt.Printf("%s is not found, create it ? [Y/n]: ", readmeFile)

		var ans string
		_, err := fmt.Scanf("%s", &ans)

		if err != nil {
			panic(err)
		}

		if ans != "Y" {
			return ""
		}
	}

	return readmeFile
}

func openByBrowser(url string) {
	openCmd := "open" // Only OSX or Linux
	execOpen(openCmd, url)
}

func openByEdior(filename string) {
	openCmd := os.Getenv("EDITOR")
	execOpen(openCmd, filename)
}

func execOpen(cmd string, target string) {

	binary, lookErr := exec.LookPath(cmd)
	if lookErr != nil {
		panic(lookErr)
	}

	args := []string{cmd, target}
	env := os.Environ()

	execErr := syscall.Exec(binary, args, env)
	if execErr != nil {
		panic(execErr)
	}
}
<|endoftext|>


<commit_before>//Simple string manipulation for Go
package stringfy
<commit_msg>improve doc.go<commit_after>//Simple string manipulation for Go
package stringfy

//Importing only for improving docs.
import (
	_ "github.com/hgsigner/stringfy/underscore"
)
<|endoftext|>


<commit_before>package sendgrid

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"net/mail"
	"time"

	"github.com/VividCortex/smtpapi-go"
)

// SGMail is representation of a valid SendGrid Mail
type SGMail struct {
	To       []string
	ToName   []string
	Cc       []string
	Subject  string
	Text     string
	HTML     string
	From     string
	Bcc      []string
	FromName string
	ReplyTo  string
	Date     string
	Files    map[string]string
	Content  map[string]string
	Headers  map[string]string
	smtpapi.SMTPAPIHeader
}

// NewMail returns a new *SGMail
func NewMail() *SGMail {
	return &SGMail{}
}

// AddTo adds a valid email address
func (m *SGMail) AddTo(email string) error {
	address, err := mail.ParseAddress(email)
	if err != nil {
		return err
	}
	m.AddRecipient(address)
	return nil
}

// AddTos adds multiple email addresses
func (m *SGMail) AddTos(emails []string) error {
	for i := 0; i < len(emails); i++ {
		if err := m.AddTo(emails[i]); err != nil {
			return err
		}
	}
	return nil
}

// AddRecipient will add mail.Address emails to recipients.
func (m *SGMail) AddRecipient(recipient *mail.Address) {
	m.To = append(m.To, recipient.Address)
	if recipient.Name != "" {
		m.ToName = append(m.ToName, recipient.Name)
	}
}

// AddRecipients calls AddRecipient per email
func (m *SGMail) AddRecipients(recipients []*mail.Address) {
	for i := 0; i < len(recipients); i++ {
		m.AddRecipient(recipients[i])
	}
}

// AddToName sets the "pretty" name for a recipient
func (m *SGMail) AddToName(name string) {
	m.ToName = append(m.ToName, name)
}

// AddToNames sets the "pretty" name for multiple recipients
func (m *SGMail) AddToNames(names []string) {
	m.ToName = append(m.ToName, names...)
}

// AddCc ...
func (m *SGMail) AddCc(cc string) error {
	address, err := mail.ParseAddress(cc)
	if err != nil {
		return err
	}
	m.AddCcRecipient(address)
	return nil
}

// AddCcs ...
func (m *SGMail) AddCcs(ccs []string) error {
	for i := 0; i < len(ccs); i++ {
		if err := m.AddCc(ccs[i]); err != nil {
			return err
		}
	}
	return nil
}

// AddCcRecipient ...
func (m *SGMail) AddCcRecipient(recipient *mail.Address) {
	m.Cc = append(m.Cc, recipient.Address)
}

// AddCcRecipients ...
func (m *SGMail) AddCcRecipients(recipients []*mail.Address) {
	for i := 0; i < len(recipients); i++ {
		m.AddCcRecipient(recipients[i])
	}
}

// SetSubject sets the email's subject
func (m *SGMail) SetSubject(subject string) {
	m.Subject = subject
}

// SetText sets the email's text
func (m *SGMail) SetText(text string) {
	m.Text = text
}

// SetHTML sets the email's HTML
func (m *SGMail) SetHTML(html string) {
	m.HTML = html
}

// SetFrom will set the senders email property
func (m *SGMail) SetFrom(from string) error {
	address, err := mail.ParseAddress(from)
	if err != nil {
		return err
	}
	m.SetFromEmail(address)
	return nil
}

// SetFromEmail sets the senders email property
func (m *SGMail) SetFromEmail(address *mail.Address) {
	m.From = address.Address
	if address.Name != "" {
		m.SetFromName(address.Name)
	}
}

// AddBcc ...
func (m *SGMail) AddBcc(bcc string) error {
	address, err := mail.ParseAddress(bcc)
	if err != nil {
		return err
	}
	m.AddBccRecipient(address)
	return nil
}

// AddBccs ...
func (m *SGMail) AddBccs(bccs []string) error {
	for i := 0; i < len(bccs); i++ {
		if err := m.AddBcc(bccs[i]); err != nil {
			return err
		}
	}
	return nil
}

// AddBccRecipient ...
func (m *SGMail) AddBccRecipient(recipient *mail.Address) {
	m.Bcc = append(m.Bcc, recipient.Address)
}

// AddBccRecipients ...
func (m *SGMail) AddBccRecipients(recipients []*mail.Address) {
	for i := 0; i < len(recipients); i++ {
		m.AddBccRecipient(recipients[i])
	}
}

// SetFromName ...
func (m *SGMail) SetFromName(fromname string) {
	m.FromName = fromname
}

// SetReplyTo ...
func (m *SGMail) SetReplyTo(replyto string) error {
	address, err := mail.ParseAddress(replyto)
	if err != nil {
		return err
	}
	m.SetReplyToEmail(address)
	return nil
}

// SetReplyToEmail ...
func (m *SGMail) SetReplyToEmail(address *mail.Address) {
	m.ReplyTo = address.Address
}

// SetDate ...
func (m *SGMail) SetDate(date string) {
	m.Date = date
}

// SetRFCDate ...
func (m *SGMail) SetRFCDate(date time.Time) {
	m.Date = date.Format(time.RFC822)
}

// AddAttachment allows file attachments to be sent. For security reasons,
// this method doesn't take filepaths only the io.Reader interface.
func (m *SGMail) AddAttachment(filename string, file io.Reader) error {
	stream, err := ioutil.ReadAll(file)
	if err != nil {
		return err
	}
	m.AddAttachmentFromStream(filename, string(stream))
	return nil
}

// AddAttachmentFromStream ...
func (m *SGMail) AddAttachmentFromStream(filename, file string) {
	if m.Files == nil {
		m.Files = make(map[string]string)
	}
	m.Files[filename] = file
}

// AddContentID ...
func (m *SGMail) AddContentID(id, value string) {
	if m.Content == nil {
		m.Content = make(map[string]string)
	}
	m.Content[id] = value
}

// AddHeader ...
func (m *SGMail) AddHeader(header, value string) {
	if m.Headers == nil {
		m.Headers = make(map[string]string)
	}
	m.Headers[header] = value
}

func (m *SGMail) HeadersString() (string, error) {
	headers, e := json.Marshal(m.Headers)
	return string(headers), e
}
<commit_msg>Fixed another place to poin to original smtpapi-go library instead of fork.<commit_after>package sendgrid

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"net/mail"
	"time"

	"github.com/sendgrid/smtpapi-go"
)

// SGMail is representation of a valid SendGrid Mail
type SGMail struct {
	To       []string
	ToName   []string
	Cc       []string
	Subject  string
	Text     string
	HTML     string
	From     string
	Bcc      []string
	FromName string
	ReplyTo  string
	Date     string
	Files    map[string]string
	Content  map[string]string
	Headers  map[string]string
	smtpapi.SMTPAPIHeader
}

// NewMail returns a new *SGMail
func NewMail() *SGMail {
	return &SGMail{}
}

// AddTo adds a valid email address
func (m *SGMail) AddTo(email string) error {
	address, err := mail.ParseAddress(email)
	if err != nil {
		return err
	}
	m.AddRecipient(address)
	return nil
}

// AddTos adds multiple email addresses
func (m *SGMail) AddTos(emails []string) error {
	for i := 0; i < len(emails); i++ {
		if err := m.AddTo(emails[i]); err != nil {
			return err
		}
	}
	return nil
}

// AddRecipient will add mail.Address emails to recipients.
func (m *SGMail) AddRecipient(recipient *mail.Address) {
	m.To = append(m.To, recipient.Address)
	if recipient.Name != "" {
		m.ToName = append(m.ToName, recipient.Name)
	}
}

// AddRecipients calls AddRecipient per email
func (m *SGMail) AddRecipients(recipients []*mail.Address) {
	for i := 0; i < len(recipients); i++ {
		m.AddRecipient(recipients[i])
	}
}

// AddToName sets the "pretty" name for a recipient
func (m *SGMail) AddToName(name string) {
	m.ToName = append(m.ToName, name)
}

// AddToNames sets the "pretty" name for multiple recipients
func (m *SGMail) AddToNames(names []string) {
	m.ToName = append(m.ToName, names...)
}

// AddCc ...
func (m *SGMail) AddCc(cc string) error {
	address, err := mail.ParseAddress(cc)
	if err != nil {
		return err
	}
	m.AddCcRecipient(address)
	return nil
}

// AddCcs ...
func (m *SGMail) AddCcs(ccs []string) error {
	for i := 0; i < len(ccs); i++ {
		if err := m.AddCc(ccs[i]); err != nil {
			return err
		}
	}
	return nil
}

// AddCcRecipient ...
func (m *SGMail) AddCcRecipient(recipient *mail.Address) {
	m.Cc = append(m.Cc, recipient.Address)
}

// AddCcRecipients ...
func (m *SGMail) AddCcRecipients(recipients []*mail.Address) {
	for i := 0; i < len(recipients); i++ {
		m.AddCcRecipient(recipients[i])
	}
}

// SetSubject sets the email's subject
func (m *SGMail) SetSubject(subject string) {
	m.Subject = subject
}

// SetText sets the email's text
func (m *SGMail) SetText(text string) {
	m.Text = text
}

// SetHTML sets the email's HTML
func (m *SGMail) SetHTML(html string) {
	m.HTML = html
}

// SetFrom will set the senders email property
func (m *SGMail) SetFrom(from string) error {
	address, err := mail.ParseAddress(from)
	if err != nil {
		return err
	}
	m.SetFromEmail(address)
	return nil
}

// SetFromEmail sets the senders email property
func (m *SGMail) SetFromEmail(address *mail.Address) {
	m.From = address.Address
	if address.Name != "" {
		m.SetFromName(address.Name)
	}
}

// AddBcc ...
func (m *SGMail) AddBcc(bcc string) error {
	address, err := mail.ParseAddress(bcc)
	if err != nil {
		return err
	}
	m.AddBccRecipient(address)
	return nil
}

// AddBccs ...
func (m *SGMail) AddBccs(bccs []string) error {
	for i := 0; i < len(bccs); i++ {
		if err := m.AddBcc(bccs[i]); err != nil {
			return err
		}
	}
	return nil
}

// AddBccRecipient ...
func (m *SGMail) AddBccRecipient(recipient *mail.Address) {
	m.Bcc = append(m.Bcc, recipient.Address)
}

// AddBccRecipients ...
func (m *SGMail) AddBccRecipients(recipients []*mail.Address) {
	for i := 0; i < len(recipients); i++ {
		m.AddBccRecipient(recipients[i])
	}
}

// SetFromName ...
func (m *SGMail) SetFromName(fromname string) {
	m.FromName = fromname
}

// SetReplyTo ...
func (m *SGMail) SetReplyTo(replyto string) error {
	address, err := mail.ParseAddress(replyto)
	if err != nil {
		return err
	}
	m.SetReplyToEmail(address)
	return nil
}

// SetReplyToEmail ...
func (m *SGMail) SetReplyToEmail(address *mail.Address) {
	m.ReplyTo = address.Address
}

// SetDate ...
func (m *SGMail) SetDate(date string) {
	m.Date = date
}

// SetRFCDate ...
func (m *SGMail) SetRFCDate(date time.Time) {
	m.Date = date.Format(time.RFC822)
}

// AddAttachment allows file attachments to be sent. For security reasons,
// this method doesn't take filepaths only the io.Reader interface.
func (m *SGMail) AddAttachment(filename string, file io.Reader) error {
	stream, err := ioutil.ReadAll(file)
	if err != nil {
		return err
	}
	m.AddAttachmentFromStream(filename, string(stream))
	return nil
}

// AddAttachmentFromStream ...
func (m *SGMail) AddAttachmentFromStream(filename, file string) {
	if m.Files == nil {
		m.Files = make(map[string]string)
	}
	m.Files[filename] = file
}

// AddContentID ...
func (m *SGMail) AddContentID(id, value string) {
	if m.Content == nil {
		m.Content = make(map[string]string)
	}
	m.Content[id] = value
}

// AddHeader ...
func (m *SGMail) AddHeader(header, value string) {
	if m.Headers == nil {
		m.Headers = make(map[string]string)
	}
	m.Headers[header] = value
}

func (m *SGMail) HeadersString() (string, error) {
	headers, e := json.Marshal(m.Headers)
	return string(headers), e
}
<|endoftext|>


<commit_before>package terraform_vix

import (
	"fmt"
	"log"
	"os"
	"os/user"
	"path/filepath"
	"strconv"

	"github.com/c4milo/govix"
	"github.com/c4milo/terraform_vix/helper"
	"github.com/hashicorp/terraform/flatmap"
	"github.com/hashicorp/terraform/helper/config"
	"github.com/hashicorp/terraform/helper/diff"
	"github.com/hashicorp/terraform/terraform"
)

func resource_vix_vm_validation() *config.Validator {
	return &config.Validator{
		Required: []string{
			"image.*",
			"image.*.url",
			"image.*.checksum",
			"image.*.checksum_type",
		},
		Optional: []string{
			"description",
			"image.*.password",
			"cpus",
			"memory",
			"hardware_version",
			"network_driver",
			"networks.*",
			"sharedfolders",
		},
	}
}

func resource_vix_vm_create(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	// Merge the diff into the state so that we have all the attributes
	// properly.
	rs := s.MergeDiff(d)

	name := rs.ID
	description := rs.Attributes["description"]
	cpus, err := strconv.ParseUint(rs.Attributes["cpus"], 0, 8)
	memory, err := strconv.ParseUint(rs.Attributes["memory"], 0, 64)
	hwversion, err := strconv.ParseUint(rs.Attributes["hardware_version"], 0, 8)
	netdrv := rs.Attributes["network_driver"]
	sharedfolders, err := strconv.ParseBool(rs.Attributes["sharedfolders"])
	var networks []string

	if err != nil {
		return nil, err
	}

	if raw := flatmap.Expand(rs.Attributes, "networks"); raw != nil {
		if nets, ok := raw.([]interface{}); ok {
			for _, net := range nets {
				str, ok := net.(string)
				if !ok {
					continue
				}

				networks = append(networks, str)
			}
		}
	}

	// This is nasty but there doesn't seem to be a cleaner way to extract stuff
	// from the TF configuration
	image := flatmap.Expand(rs.Attributes, "image").([]interface{})[0].(map[string]interface{})

	log.Printf("[DEBUG] networks => %v", networks)

	if len(networks) == 0 {
		networks = append(networks, "bridged")
	}

	log.Printf("[DEBUG] name => %s", name)
	log.Printf("[DEBUG] description => %s", description)
	log.Printf("[DEBUG] image => %v", image)
	log.Printf("[DEBUG] cpus => %d", cpus)
	log.Printf("[DEBUG] memory => %d", memory)
	log.Printf("[DEBUG] hwversion => %d", hwversion)
	log.Printf("[DEBUG] netdrv => %s", netdrv)
	log.Printf("[DEBUG] sharedfolders => %t", sharedfolders)

	usr, err := user.Current()
	if err != nil {
		return nil, err
	}

	// FIXME(c4milo): There is an issue here whenever count is greater than 1
	// please see: https://github.com/hashicorp/terraform/issues/141
	imagePath := filepath.Join(usr.HomeDir, fmt.Sprintf(".terraform/vix/vms/%s", name))

	// Check if there is an image already in imagePath, if not, fetches it and unpacks it.
	_, err = os.Stat(imagePath)
	if err != nil {
		if os.IsNotExist(err) {
			imageGzFile, err := helper.FetchImage(image["url"].(string),
				image["checksum"].(string),
				image["checksum_type"].(string))

			if err != nil {
				return nil, err
			}

			err = helper.UnpackImage(imageGzFile, imagePath)
			if err != nil {
				return nil, err
			}
		} else {
			return nil, err
		}
	}

	// Gets VIX instance
	p := meta.(*ResourceProvider)
	client := p.client
	vm, err := client.OpenVm(imagePath, image["password"].(string))
	if err != nil {
		return nil, err
	}
	defer client.Disconnect()

	vm.SetMemorySize(uint(memory))
	vm.SetNumberVcpus(uint8(cpus))

	for _, netType := range networks {
		adapter := &vix.NetworkAdapter{
			VSwitch:        vix.VSwitch{},
			StartConnected: true,
		}

		switch netdrv {
		case "e1000":
			adapter.Vdevice = vix.NETWORK_DEVICE_E1000
		case "vmxnet3":
			adapter.Vdevice = vix.NETWORK_DEVICE_VMXNET3
		default:
			adapter.Vdevice = vix.NETWORK_DEVICE_E1000
		}

		switch netType {
		case "hostonly":
			adapter.ConnType = vix.NETWORK_HOSTONLY
		case "bridged":
			adapter.ConnType = vix.NETWORK_BRIDGED
		case "nat":
			adapter.ConnType = vix.NETWORK_NAT
		default:
			adapter.ConnType = vix.NETWORK_CUSTOM

		}

		err = vm.AddNetworkAdapter(adapter)
		if err != nil {
			return nil, err
		}
	}

	// TODO(c4milo): Set hardware version

	err = vm.PowerOn(vix.VMPOWEROP_NORMAL)
	if err != nil {
		return nil, err
	}

	// rs.ConnInfo["type"] = "ssh"
	// rs.ConnInfo["host"] = ?

	return rs, nil
}

func resource_vix_vm_update(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	//p := meta.(*ResourceProvider)

	return nil, nil
}

func resource_vix_vm_destroy(
	s *terraform.ResourceState,
	meta interface{}) error {
	// p := meta.(*ResourceProvider)
	// client := p.client

	return nil
}

func resource_vix_vm_diff(
	s *terraform.ResourceState,
	c *terraform.ResourceConfig,
	meta interface{}) (*terraform.ResourceDiff, error) {

	b := &diff.ResourceBuilder{
		// We have to choose whether a change in an attribute triggers a new
		// resource creation or updates the existing resource.
		Attrs: map[string]diff.AttrType{
			"description":      diff.AttrTypeUpdate,
			"image":            diff.AttrTypeCreate,
			"cpus":             diff.AttrTypeUpdate,
			"memory":           diff.AttrTypeUpdate,
			"networks":         diff.AttrTypeUpdate,
			"hardware_version": diff.AttrTypeUpdate,
			"network_driver":   diff.AttrTypeUpdate,
			"sharedfolders":    diff.AttrTypeUpdate,
		},

		ComputedAttrs: []string{
			"ip_address",
		},
	}

	return b.Diff(s, c)
}

func resource_vix_vm_refresh(
	s *terraform.ResourceState,
	meta interface{}) (*terraform.ResourceState, error) {

	return nil, nil
}

func resource_vix_vm_update_state(
	s *terraform.ResourceState,
	vm *vix.VM) (*terraform.ResourceState, error) {

	return nil, nil
}
<commit_msg>Parses memory size into actual megabytes<commit_after>package terraform_vix

import (
	"fmt"
	"log"
	"os"
	"os/user"
	"path/filepath"
	"strconv"

	"github.com/c4milo/govix"
	"github.com/c4milo/terraform_vix/helper"
	"github.com/dustin/go-humanize"
	"github.com/hashicorp/terraform/flatmap"
	"github.com/hashicorp/terraform/helper/config"
	"github.com/hashicorp/terraform/helper/diff"
	"github.com/hashicorp/terraform/terraform"
)

func resource_vix_vm_validation() *config.Validator {
	return &config.Validator{
		Required: []string{
			"image.*",
			"image.*.url",
			"image.*.checksum",
			"image.*.checksum_type",
		},
		Optional: []string{
			"description",
			"image.*.password",
			"cpus",
			"memory",
			"hardware_version",
			"network_driver",
			"networks.*",
			"sharedfolders",
		},
	}
}

func resource_vix_vm_create(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	// Merge the diff into the state so that we have all the attributes
	// properly.
	rs := s.MergeDiff(d)

	name := rs.ID
	description := rs.Attributes["description"]
	cpus, err := strconv.ParseUint(rs.Attributes["cpus"], 0, 8)
	memory := rs.Attributes["memory"]
	hwversion, err := strconv.ParseUint(rs.Attributes["hardware_version"], 0, 8)
	netdrv := rs.Attributes["network_driver"]
	sharedfolders, err := strconv.ParseBool(rs.Attributes["sharedfolders"])
	var networks []string

	if err != nil {
		return nil, err
	}

	if raw := flatmap.Expand(rs.Attributes, "networks"); raw != nil {
		if nets, ok := raw.([]interface{}); ok {
			for _, net := range nets {
				str, ok := net.(string)
				if !ok {
					continue
				}

				networks = append(networks, str)
			}
		}
	}

	// This is nasty but there doesn't seem to be a cleaner way to extract stuff
	// from the TF configuration
	image := flatmap.Expand(rs.Attributes, "image").([]interface{})[0].(map[string]interface{})

	log.Printf("[DEBUG] networks => %v", networks)

	if len(networks) == 0 {
		networks = append(networks, "bridged")
	}

	log.Printf("[DEBUG] name => %s", name)
	log.Printf("[DEBUG] description => %s", description)
	log.Printf("[DEBUG] image => %v", image)
	log.Printf("[DEBUG] cpus => %d", cpus)
	log.Printf("[DEBUG] memory => %d", memory)
	log.Printf("[DEBUG] hwversion => %d", hwversion)
	log.Printf("[DEBUG] netdrv => %s", netdrv)
	log.Printf("[DEBUG] sharedfolders => %t", sharedfolders)

	usr, err := user.Current()
	if err != nil {
		return nil, err
	}

	// FIXME(c4milo): There is an issue here whenever count is greater than 1
	// please see: https://github.com/hashicorp/terraform/issues/141
	imagePath := filepath.Join(usr.HomeDir, fmt.Sprintf(".terraform/vix/vms/%s", name))

	// Check if there is an image already in imagePath, if not, fetches it and unpacks it.
	_, err = os.Stat(imagePath)
	if err != nil {
		if os.IsNotExist(err) {
			imageGzFile, err := helper.FetchImage(image["url"].(string),
				image["checksum"].(string),
				image["checksum_type"].(string))

			if err != nil {
				return nil, err
			}

			err = helper.UnpackImage(imageGzFile, imagePath)
			if err != nil {
				return nil, err
			}
		} else {
			return nil, err
		}
	}

	// Gets VIX instance
	p := meta.(*ResourceProvider)
	client := p.client
	vm, err := client.OpenVm(imagePath, image["password"].(string))
	if err != nil {
		return nil, err
	}
	defer client.Disconnect()

	memoryInMb, err := humanize.ParseBytes(memory)
	if err != nil {
		log.Printf("[WARN] Unable to set memory size, defaulting to 1g: %s", err)
		memoryInMb = 1024
	} else {
		memoryInMb /= 1024
	}

	vm.SetMemorySize(uint(memoryInMb))
	vm.SetNumberVcpus(uint8(cpus))

	for _, netType := range networks {
		adapter := &vix.NetworkAdapter{
			VSwitch:        vix.VSwitch{},
			StartConnected: true,
		}

		switch netdrv {
		case "e1000":
			adapter.Vdevice = vix.NETWORK_DEVICE_E1000
		case "vmxnet3":
			adapter.Vdevice = vix.NETWORK_DEVICE_VMXNET3
		default:
			adapter.Vdevice = vix.NETWORK_DEVICE_E1000
		}

		switch netType {
		case "hostonly":
			adapter.ConnType = vix.NETWORK_HOSTONLY
		case "bridged":
			adapter.ConnType = vix.NETWORK_BRIDGED
		case "nat":
			adapter.ConnType = vix.NETWORK_NAT
		default:
			adapter.ConnType = vix.NETWORK_CUSTOM

		}

		err = vm.AddNetworkAdapter(adapter)
		if err != nil {
			return nil, err
		}
	}

	// TODO(c4milo): Set hardware version

	err = vm.PowerOn(vix.VMPOWEROP_NORMAL)
	if err != nil {
		return nil, err
	}

	// rs.ConnInfo["type"] = "ssh"
	// rs.ConnInfo["host"] = ?

	return rs, nil
}

func resource_vix_vm_update(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	//p := meta.(*ResourceProvider)

	return nil, nil
}

func resource_vix_vm_destroy(
	s *terraform.ResourceState,
	meta interface{}) error {
	// p := meta.(*ResourceProvider)
	// client := p.client

	return nil
}

func resource_vix_vm_diff(
	s *terraform.ResourceState,
	c *terraform.ResourceConfig,
	meta interface{}) (*terraform.ResourceDiff, error) {

	b := &diff.ResourceBuilder{
		// We have to choose whether a change in an attribute triggers a new
		// resource creation or updates the existing resource.
		Attrs: map[string]diff.AttrType{
			"description":      diff.AttrTypeUpdate,
			"image":            diff.AttrTypeCreate,
			"cpus":             diff.AttrTypeUpdate,
			"memory":           diff.AttrTypeUpdate,
			"networks":         diff.AttrTypeUpdate,
			"hardware_version": diff.AttrTypeUpdate,
			"network_driver":   diff.AttrTypeUpdate,
			"sharedfolders":    diff.AttrTypeUpdate,
		},

		ComputedAttrs: []string{
			"ip_address",
		},
	}

	return b.Diff(s, c)
}

func resource_vix_vm_refresh(
	s *terraform.ResourceState,
	meta interface{}) (*terraform.ResourceState, error) {

	return nil, nil
}

func resource_vix_vm_update_state(
	s *terraform.ResourceState,
	vm *vix.VM) (*terraform.ResourceState, error) {

	return nil, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/exec"
	"time"

	"gopkg.in/alecthomas/kingpin.v2"

	"github.com/ark-lang/ark/src/codegen"
	"github.com/ark-lang/ark/src/codegen/LLVMCodegen"
	"github.com/ark-lang/ark/src/doc"
	"github.com/ark-lang/ark/src/lexer"
	"github.com/ark-lang/ark/src/parser"
	"github.com/ark-lang/ark/src/semantic"
	"github.com/ark-lang/ark/src/util"
	"github.com/ark-lang/ark/src/util/log"
)

const (
	VERSION = "0.0.2"
	AUTHOR  = "The Ark Authors"
)

var startTime time.Time

func main() {
	startTime = time.Now()

	command := kingpin.MustParse(app.Parse(os.Args[1:]))
	log.SetLevel(*logLevel)
	log.SetTags(*logTags)

	switch command {
	case buildCom.FullCommand():
		if len(*buildInputs) == 0 {
			setupErr("No input files passed.")
		}

		ccArgs := []string{}
		if *buildStatic {
			ccArgs = append(ccArgs, "-static")
		}

		outputType := parseOutputType(*buildOutputType)
		build(*buildInputs, *buildOutput, *buildCodegen, ccArgs, outputType, *buildOptLevel)
		printFinishedMessage(startTime, buildCom.FullCommand(), len(*buildInputs))
		if *buildRun {
			if outputType != LLVMCodegen.OUTPUT_EXECUTABLE {
				setupErr("Can only use --run flag when building executable")
			}
			run(*buildOutput)
		}

	case docgenCom.FullCommand():
		docgen(*docgenInputs, *docgenDir)
		printFinishedMessage(startTime, docgenCom.FullCommand(), len(*docgenInputs))
	}
}

func printFinishedMessage(startTime time.Time, command string, numFiles int) {
	dur := time.Since(startTime)
	log.Info("main", "%s (%d file(s), %.2fms)\n",
		util.TEXT_GREEN+util.TEXT_BOLD+fmt.Sprintf("Finished %s", command)+util.TEXT_RESET,
		numFiles, float32(dur.Nanoseconds())/1000000)
}

func setupErr(err string, stuff ...interface{}) {
	log.Error("main", util.TEXT_RED+util.TEXT_BOLD+"Setup error:"+util.TEXT_RESET+" %s\n",
		fmt.Sprintf(err, stuff...))
	os.Exit(util.EXIT_FAILURE_SETUP)
}

func parseFiles(files []string) ([]*parser.Module, map[string]*parser.Module) {
	// read source files
	var sourcefiles []*lexer.Sourcefile
	log.Timed("reading sourcefiles", func() {
		for _, file := range files {
			sourcefile, err := lexer.NewSourcefile(file)
			if err != nil {
				setupErr("%s", err.Error())
			}
			sourcefiles = append(sourcefiles, sourcefile)
		}
	})

	// lexing
	log.Timed("lexing phase", func() {
		for _, file := range sourcefiles {
			file.Tokens = lexer.Lex(file)
		}
	})

	// parsing
	var parsedFiles []*parser.ParseTree
	parsedFileMap := make(map[string]*parser.ParseTree)
	log.Timed("parsing phase", func() {
		for _, file := range sourcefiles {
			parsedFile := parser.Parse(file)
			parsedFiles = append(parsedFiles, parsedFile)
			parsedFileMap[parsedFile.Source.Name] = parsedFile
		}
	})

	// construction
	var constructedModules []*parser.Module
	modules := make(map[string]*parser.Module)
	log.Timed("construction phase", func() {
		for _, file := range parsedFiles {
			constructedModules = append(constructedModules, parser.Construct(file, parsedFileMap, modules))
		}
	})

	return constructedModules, modules
}

func build(files []string, outputFile string, cg string, ccArgs []string, outputType LLVMCodegen.OutputType, optLevel int) {
	constructedModules, modules := parseFiles(files)

	// resolve
	log.Timed("resolve phase", func() {
		// TODO: We're looping over a map, the order we get is thus random
		for _, module := range modules {
			res := &parser.Resolver{Module: module}
			res.Resolve(modules)
		}
	})

	// type inference
	log.Timed("inference phase", func() {
		// TODO: We're looping over a map, the order we get is thus random
		for _, module := range modules {
			inf := &parser.TypeInferer{Module: module}
			inf.Infer(modules)

			// Dump AST
			log.Debugln("main", "AST of module `%s`:", module.Name)
			for _, node := range module.Nodes {
				log.Debugln("main", node.String())
			}
		}
	})

	// semantic analysis
	log.Timed("semantic analysis phase", func() {
		// TODO: We're looping over a map, the order we get is thus random
		for _, module := range modules {
			sem := &semantic.SemanticAnalyzer{Module: module}
			sem.Analyze(modules)
		}
	})

	// codegen
	if cg != "none" {
		var gen codegen.Codegen

		switch cg {
		case "llvm":
			gen = &LLVMCodegen.Codegen{
				OutputName:   outputFile,
				CompilerArgs: ccArgs,
				OutputType:   outputType,
				OptLevel:     optLevel,
			}
		default:
			log.Error("main", util.Red("error: ")+"Invalid backend choice `"+cg+"`")
			os.Exit(1)
		}

		log.Timed("codegen phase", func() {
			gen.Generate(constructedModules, modules)
		})
	}

}

func run(output string) {
	cmd := exec.Command("./" + output)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Run()
}

func docgen(input []string, dir string) {
	constructedModules, _ := parseFiles(input)

	gen := &doc.Docgen{
		Input: constructedModules,
		Dir:   dir,
	}

	gen.Generate()
}
<commit_msg>fix ast output<commit_after>package main

import (
	"fmt"
	"os"
	"os/exec"
	"time"

	"gopkg.in/alecthomas/kingpin.v2"

	"github.com/ark-lang/ark/src/codegen"
	"github.com/ark-lang/ark/src/codegen/LLVMCodegen"
	"github.com/ark-lang/ark/src/doc"
	"github.com/ark-lang/ark/src/lexer"
	"github.com/ark-lang/ark/src/parser"
	"github.com/ark-lang/ark/src/semantic"
	"github.com/ark-lang/ark/src/util"
	"github.com/ark-lang/ark/src/util/log"
)

const (
	VERSION = "0.0.2"
	AUTHOR  = "The Ark Authors"
)

var startTime time.Time

func main() {
	startTime = time.Now()

	command := kingpin.MustParse(app.Parse(os.Args[1:]))
	log.SetLevel(*logLevel)
	log.SetTags(*logTags)

	switch command {
	case buildCom.FullCommand():
		if len(*buildInputs) == 0 {
			setupErr("No input files passed.")
		}

		ccArgs := []string{}
		if *buildStatic {
			ccArgs = append(ccArgs, "-static")
		}

		outputType := parseOutputType(*buildOutputType)
		build(*buildInputs, *buildOutput, *buildCodegen, ccArgs, outputType, *buildOptLevel)
		printFinishedMessage(startTime, buildCom.FullCommand(), len(*buildInputs))
		if *buildRun {
			if outputType != LLVMCodegen.OUTPUT_EXECUTABLE {
				setupErr("Can only use --run flag when building executable")
			}
			run(*buildOutput)
		}

	case docgenCom.FullCommand():
		docgen(*docgenInputs, *docgenDir)
		printFinishedMessage(startTime, docgenCom.FullCommand(), len(*docgenInputs))
	}
}

func printFinishedMessage(startTime time.Time, command string, numFiles int) {
	dur := time.Since(startTime)
	log.Info("main", "%s (%d file(s), %.2fms)\n",
		util.TEXT_GREEN+util.TEXT_BOLD+fmt.Sprintf("Finished %s", command)+util.TEXT_RESET,
		numFiles, float32(dur.Nanoseconds())/1000000)
}

func setupErr(err string, stuff ...interface{}) {
	log.Error("main", util.TEXT_RED+util.TEXT_BOLD+"Setup error:"+util.TEXT_RESET+" %s\n",
		fmt.Sprintf(err, stuff...))
	os.Exit(util.EXIT_FAILURE_SETUP)
}

func parseFiles(files []string) ([]*parser.Module, map[string]*parser.Module) {
	// read source files
	var sourcefiles []*lexer.Sourcefile
	log.Timed("reading sourcefiles", func() {
		for _, file := range files {
			sourcefile, err := lexer.NewSourcefile(file)
			if err != nil {
				setupErr("%s", err.Error())
			}
			sourcefiles = append(sourcefiles, sourcefile)
		}
	})

	// lexing
	log.Timed("lexing phase", func() {
		for _, file := range sourcefiles {
			file.Tokens = lexer.Lex(file)
		}
	})

	// parsing
	var parsedFiles []*parser.ParseTree
	parsedFileMap := make(map[string]*parser.ParseTree)
	log.Timed("parsing phase", func() {
		for _, file := range sourcefiles {
			parsedFile := parser.Parse(file)
			parsedFiles = append(parsedFiles, parsedFile)
			parsedFileMap[parsedFile.Source.Name] = parsedFile
		}
	})

	// construction
	var constructedModules []*parser.Module
	modules := make(map[string]*parser.Module)
	log.Timed("construction phase", func() {
		for _, file := range parsedFiles {
			constructedModules = append(constructedModules, parser.Construct(file, parsedFileMap, modules))
		}
	})

	return constructedModules, modules
}

func build(files []string, outputFile string, cg string, ccArgs []string, outputType LLVMCodegen.OutputType, optLevel int) {
	constructedModules, modules := parseFiles(files)

	// resolve
	log.Timed("resolve phase", func() {
		// TODO: We're looping over a map, the order we get is thus random
		for _, module := range modules {
			res := &parser.Resolver{Module: module}
			res.Resolve(modules)
		}
	})

	// type inference
	log.Timed("inference phase", func() {
		// TODO: We're looping over a map, the order we get is thus random
		for _, module := range modules {
			inf := &parser.TypeInferer{Module: module}
			inf.Infer(modules)

			// Dump AST
			log.Debugln("main", "AST of module `%s`:", module.Name)
			for _, node := range module.Nodes {
				log.Debugln("main", "%s", node.String())
			}
		}
	})

	// semantic analysis
	log.Timed("semantic analysis phase", func() {
		// TODO: We're looping over a map, the order we get is thus random
		for _, module := range modules {
			sem := &semantic.SemanticAnalyzer{Module: module}
			sem.Analyze(modules)
		}
	})

	// codegen
	if cg != "none" {
		var gen codegen.Codegen

		switch cg {
		case "llvm":
			gen = &LLVMCodegen.Codegen{
				OutputName:   outputFile,
				CompilerArgs: ccArgs,
				OutputType:   outputType,
				OptLevel:     optLevel,
			}
		default:
			log.Error("main", util.Red("error: ")+"Invalid backend choice `"+cg+"`")
			os.Exit(1)
		}

		log.Timed("codegen phase", func() {
			gen.Generate(constructedModules, modules)
		})
	}

}

func run(output string) {
	cmd := exec.Command("./" + output)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Run()
}

func docgen(input []string, dir string) {
	constructedModules, _ := parseFiles(input)

	gen := &doc.Docgen{
		Input: constructedModules,
		Dir:   dir,
	}

	gen.Generate()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/miekg/dns"
	"net"
	"sort"
	"strings"
)

type NSCheck struct {
	NS      []NSData
	NSCheck []NSCheckData
	Report
}

type NSCheckData struct {
	Name  string
	IP    string
	NS    []dns.RR
	Error string
	Auth  bool
}

func (c *NSCheck) Scan(domain string) {
	for _, ns := range c.NS {
		for _, nsip := range ns.IP {
			data := NSCheckData{Name: ns.Name, IP: nsip.String()}
			res, err := query(domain, dns.TypeNS, nsip.String(), true)
			if err != nil {
				data.Error = fmt.Sprintf("NS check failed on %s: %s", nsip.String(), err)
				c.NSCheck = append(c.NSCheck, data)
				break
			}
			nsrr := extractRR(res.Msg.Answer, dns.TypeNS)
			if len(nsrr) == 0 {
				data.Error = fmt.Sprintf("NSCheck check failed on %s: %s", nsip.String(), "no records found")
				data.NS = nsrr
				data.Auth = res.Msg.Authoritative
				c.NSCheck = append(c.NSCheck, data)
				break
			}
			data.NS = nsrr
			data.Auth = res.Msg.Authoritative
			c.NSCheck = append(c.NSCheck, data)
		}
	}
}

func (c *NSCheck) Identical() ReportResult {
	m := make(map[string][]string)
	for _, ns := range c.NSCheck {
		nsstr := []string{}
		if ns.NS != nil && ns.Error == "" {
			for _, nsc := range ns.NS {
				nsstr = append(nsstr, nsc.String()+"\n\t ")
			}
			sort.Strings(nsstr)
			m[strings.Join(nsstr, "")] = append(m[strings.Join(nsstr, "")], ns.IP)
		}
	}
	res := ReportResult{}
	if len(m) > 1 {
		res.Result = fmt.Sprintf("FAIL: NS not identical\n")
		res.Status = false
		for k, v := range m {
			res.Result += fmt.Sprintf("\t %s\n\t %s\n", v, k)
		}
	} else {
		res.Result = "OK  : NS of all nameservers are identical"
		res.Status = true
	}
	return res
}

func (c *NSCheck) ASN() ReportResult {
	m := make(map[string][]string)
	for _, ns := range c.NSCheck {
		ip := net.ParseIP(ns.IP)
		info, _ := ipinfo(ip)
		m[info.ASN.String()] = append(m[info.ASN.String()], ns.IP)
	}
	res := ReportResult{}
	if len(m) > 1 {
		res.Result = "OK  : Nameservers are spread over multiple AS"
		res.Status = true
	} else {
		as := ""
		for k := range m {
			as = k
			break
		}
		res.Result = fmt.Sprintf("WARN: Nameservers are all on the same AS (%s). This is a single point of failure.", as)
		res.Status = false
	}
	return res
}

func (c *NSCheck) IPCheck() []ReportResult {
	m := make(map[string]int)
	for _, ns := range c.NSCheck {
		if strings.Contains(ns.IP, ":") {
			m["ipv6"]++
		} else {
			m["ipv4"]++
		}
	}

	res := []ReportResult{}
	if m["ipv6"] == 0 {
		res = append(res, ReportResult{Result: "WARN: No IPv6 nameservers found. IPv6-only users will have problems.",
			Status: false})
	}

	// I wonder when this will ever happen :)
	if m["ipv4"] == 0 {
		res = append(res, ReportResult{Result: "WARN: No IPv4 nameservers found. IPv4-only users will have problems.",
			Status: false})
	}
	if (m["ipv4"] > 0) && (m["ipv6"] > 0) {
		res = append(res, ReportResult{Result: "OK  : IPv4 and IPv6 nameservers found.",
			Status: true})
	}
	return res
}

func (c *NSCheck) Auth() []ReportResult {
	res := []ReportResult{}
	ok := true
	for _, ns := range c.NSCheck {
		if len(ns.NS) > 0 && !ns.Auth {
			res = append(res, ReportResult{Result: fmt.Sprintf("FAIL: %s (%s) is not authoritative.", ns.Name, ns.IP),
				Status: false})
			ok = false
		}
	}
	if ok {
		res = append(res, ReportResult{Result: "OK  : All nameservers are authoritative.",
			Status: true})
	}
	return res
}

func (c *NSCheck) Values() []ReportResult {
	var results []ReportResult
	var rrset []dns.RR
	for _, ns := range c.NSCheck {
		if ns.NS != nil {
			rrset = ns.NS
			break
		}
	}
	if len(rrset) > 1 {
		records := []string{}
		for _, rr := range rrset {
			records = append(records, rr.String())
		}
		results = append(results, ReportResult{Result: "OK  : Multiple nameservers found",
			Status: true, Records: records})
	} else {
		results = append(results, ReportResult{Result: fmt.Sprintf("WARN: Only %v nameserver found. Extra nameservers increases reliability", len(rrset)),
			Status: false})
	}
	return results

	//TODO
	// check NS at parent, compare with domain NS
	// check if NS actually response
	// stealth records

}

func (c *NSCheck) CreateReport(domain string) {
	c.Scan(domain)
	c.Report.Type = "NS"
	c.Report.Result = append(c.Report.Result, c.Identical())
	c.Report.Result = append(c.Report.Result, c.Values()...)
	c.Report.Result = append(c.Report.Result, c.ASN())
	c.Report.Result = append(c.Report.Result, c.IPCheck()...)
	c.Report.Result = append(c.Report.Result, c.Auth()...)
}
<commit_msg>Add cname, parentns, recursive checks (NScheck)<commit_after>package main

import (
	"fmt"
	"github.com/miekg/dns"
	"net"
	"sort"
	"strings"
)

type NSCheck struct {
	NS      []NSData
	NSCheck []NSCheckData
	Report
}

type NSCheckData struct {
	Name      string
	IP        string
	NS        []dns.RR
	CNAME     []dns.RR
	Error     string
	Auth      bool
	Recursive bool
}

func (c *NSCheck) Scan(domain string) {
	for _, ns := range c.NS {
		for _, nsip := range ns.IP {
			data := NSCheckData{Name: ns.Name, IP: nsip.String()}
			res, err := query(domain, dns.TypeNS, nsip.String(), true)
			if err != nil {
				data.Error = fmt.Sprintf("NS check failed on %s: %s", nsip.String(), err)
				c.NSCheck = append(c.NSCheck, data)
				break
			}
			nsrr := extractRR(res.Msg.Answer, dns.TypeNS)
			if len(nsrr) == 0 {
				data.Error = fmt.Sprintf("NSCheck check failed on %s: %s", nsip.String(), "no records found")
				data.NS = nsrr
				data.Auth = res.Msg.Authoritative
				c.NSCheck = append(c.NSCheck, data)
				break
			}
			data.NS = nsrr
			data.Auth = res.Msg.Authoritative
			data.Recursive = res.Msg.RecursionAvailable
			c.NSCheck = append(c.NSCheck, data)
		}
	}
}

func (c *NSCheck) CheckCNAME() []ReportResult {
	rep := []ReportResult{}
	m := make(map[string]bool)
	for _, ns := range c.NSCheck {
		// skip lookup if already done
		if _, ok := m[ns.Name]; ok {
			break
		}
		// asking recursor for now
		res, err := query(dns.Fqdn(ns.Name), dns.TypeA, resolver, true)
		if err != nil {
			break
		}
		cname := extractRR(res.Msg.Answer, dns.TypeCNAME)
		if len(cname) > 0 {
			rep = append(rep, ReportResult{Result: fmt.Sprintf("FAIL: Your nameserver (%s) is a CNAME.", ns.Name),
				Status: false})
		}
		res, err = query(dns.Fqdn(ns.Name), dns.TypeAAAA, resolver, true)
		if err != nil {
			break
		}
		cname = extractRR(res.Msg.Answer, dns.TypeCNAME)
		if len(cname) > 0 {
			rep = append(rep, ReportResult{Result: fmt.Sprintf("FAIL: Your nameserver (%s) is a CNAME.", ns.Name),
				Status: false})
		}
		m[ns.Name] = true
	}
	if len(rep) == 0 {
		rep = append(rep, ReportResult{Result: "OK  : No CNAMEs found for your NS records",
			Status: true})
	}
	return rep
}

func (c *NSCheck) CheckParent(domain string) ReportResult {
	nsdata, err := findNS(getParentDomain(domain))
	if err != nil {
		return ReportResult{}
	}
	var rrset []dns.RR
loop:
	for _, ns := range nsdata {
		for _, nsip := range ns.IP {
			res, err := query(dns.Fqdn(domain), dns.TypeNS, nsip.String(), true)
			if err != nil {
				break
			}
			rrset = extractRR(res.Msg.Ns, dns.TypeNS)
			if len(rrset) > 0 {
				break loop
			}
		}
	}
	m := make(map[string]bool)
	for _, rr := range rrset {
		m[dns.Fqdn(rr.(*dns.NS).Ns)] = true
	}
	missing := []string{}
	for _, ns := range c.NS {
		if _, ok := m[ns.Name]; !ok {
			missing = append(missing, ns.Name)
		}
	}
	if len(missing) > 0 {
		return ReportResult{Result: fmt.Sprintf("FAIL: The following nameservers are not listed at the parent nameservers: %s", missing),
			Status: false}
	} else {
		return ReportResult{Result: "OK  : Your nameservers are also listed at the parent nameservers",
			Status: true}
	}
}

func (c *NSCheck) Identical() ReportResult {
	m := make(map[string][]string)
	for _, ns := range c.NSCheck {
		nsstr := []string{}
		if ns.NS != nil && ns.Error == "" {
			for _, nsc := range ns.NS {
				nsstr = append(nsstr, nsc.String()+"\n\t ")
			}
			sort.Strings(nsstr)
			m[strings.Join(nsstr, "")] = append(m[strings.Join(nsstr, "")], ns.IP)
		}
	}
	res := ReportResult{}
	if len(m) > 1 {
		res.Result = fmt.Sprintf("FAIL: NS not identical\n")
		res.Status = false
		for k, v := range m {
			res.Result += fmt.Sprintf("\t %s\n\t %s\n", v, k)
		}
	} else {
		res.Result = "OK  : NS of all nameservers are identical"
		res.Status = true
	}
	return res
}

func (c *NSCheck) ASN() ReportResult {
	m := make(map[string][]string)
	for _, ns := range c.NSCheck {
		ip := net.ParseIP(ns.IP)
		info, _ := ipinfo(ip)
		m[info.ASN.String()] = append(m[info.ASN.String()], ns.IP)
	}
	res := ReportResult{}
	if len(m) > 1 {
		res.Result = "OK  : Nameservers are spread over multiple AS"
		res.Status = true
	} else {
		as := ""
		for k := range m {
			as = k
			break
		}
		res.Result = fmt.Sprintf("WARN: Nameservers are all on the same AS (%s). This is a single point of failure.", as)
		res.Status = false
	}
	return res
}

func (c *NSCheck) IPCheck() []ReportResult {
	m := make(map[string]int)
	for _, ns := range c.NSCheck {
		if strings.Contains(ns.IP, ":") {
			m["ipv6"]++
		} else {
			m["ipv4"]++
		}
	}

	res := []ReportResult{}
	if m["ipv6"] == 0 {
		res = append(res, ReportResult{Result: "WARN: No IPv6 nameservers found. IPv6-only users will have problems.",
			Status: false})
	}

	// I wonder when this will ever happen :)
	if m["ipv4"] == 0 {
		res = append(res, ReportResult{Result: "WARN: No IPv4 nameservers found. IPv4-only users will have problems.",
			Status: false})
	}
	if (m["ipv4"] > 0) && (m["ipv6"] > 0) {
		res = append(res, ReportResult{Result: "OK  : IPv4 and IPv6 nameservers found.",
			Status: true})
	}
	return res
}

func (c *NSCheck) Auth() []ReportResult {
	res := []ReportResult{}
	ok := true
	for _, ns := range c.NSCheck {
		if len(ns.NS) > 0 && !ns.Auth {
			res = append(res, ReportResult{Result: fmt.Sprintf("FAIL: %s (%s) is not authoritative.", ns.Name, ns.IP),
				Status: false})
			ok = false
		}
	}
	if ok {
		res = append(res, ReportResult{Result: "OK  : All nameservers are authoritative.",
			Status: true})
	}
	return res
}

func (c *NSCheck) Recursive() []ReportResult {
	res := []ReportResult{}
	ok := true
	for _, ns := range c.NSCheck {
		if len(ns.NS) > 0 && ns.Recursive {
			res = append(res, ReportResult{Result: fmt.Sprintf("WARN: %s (%s) allows recursive queries.", ns.Name, ns.IP),
				Status: false})
			ok = false
		}
	}
	if ok {
		res = append(res, ReportResult{Result: "OK  : All nameservers report they are not allowing recursive queries.",
			Status: true})
	}
	return res
}

func (c *NSCheck) Values() []ReportResult {
	var results []ReportResult
	var rrset []dns.RR
	for _, ns := range c.NSCheck {
		if ns.NS != nil {
			rrset = ns.NS
			break
		}
	}
	if len(rrset) > 1 {
		records := []string{}
		for _, rr := range rrset {
			records = append(records, rr.String())
		}
		results = append(results, ReportResult{Result: "OK  : Multiple nameservers found",
			Status: true, Records: records})
	} else {
		results = append(results, ReportResult{Result: fmt.Sprintf("WARN: Only %v nameserver found. Extra nameservers increases reliability", len(rrset)),
			Status: false})
	}

	for _, ns := range c.NSCheck {
		if ns.NS != nil {
			if len(ns.CNAME) > 1 {
				results = append(results, ReportResult{Result: fmt.Sprintf("FAIL: NS %s is a CNAME for %s", ns.Name, ns.CNAME[0].(*dns.CNAME).Target),
					Status: false})
			}
		}
	}

	return results

	//TODO
	// check if NS actually response
	// stealth records

}

func (c *NSCheck) CreateReport(domain string) {
	c.Scan(domain)
	c.Report.Type = "NS"
	c.Report.Result = append(c.Report.Result, c.Identical())
	c.Report.Result = append(c.Report.Result, c.Values()...)
	c.Report.Result = append(c.Report.Result, c.ASN())
	c.Report.Result = append(c.Report.Result, c.IPCheck()...)
	c.Report.Result = append(c.Report.Result, c.Auth()...)
	c.Report.Result = append(c.Report.Result, c.Recursive()...)
	c.Report.Result = append(c.Report.Result, c.CheckParent(domain))
	c.Report.Result = append(c.Report.Result, c.CheckCNAME()...)
}
<|endoftext|>


<commit_before><commit_msg>Avoid extra rendering work during scanline update<commit_after><|endoftext|>


<commit_before>package libvirt

import (
	"fmt"
	"regexp"
	"testing"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	libvirt "github.com/libvirt/libvirt-go"
)

func testAccCheckLibvirtVolumeDestroy(s *terraform.State) error {
	virConn := testAccProvider.Meta().(*Client).libvirt

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "libvirt_volume" {
			continue
		}

		_, err := virConn.LookupStorageVolByKey(rs.Primary.ID)
		if err == nil {
			return fmt.Errorf(
				"Error waiting for volume (%s) to be destroyed: %s",
				rs.Primary.ID, err)
		}
	}

	return nil
}

func testAccCheckLibvirtVolumeExists(n string, volume *libvirt.StorageVol) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		virConn := testAccProvider.Meta().(*Client).libvirt

		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No libvirt volume key ID is set")
		}

		retrievedVol, err := virConn.LookupStorageVolByKey(rs.Primary.ID)
		if err != nil {
			return err
		}
		fmt.Printf("The ID is %s", rs.Primary.ID)

		realID, err := retrievedVol.GetKey()
		if err != nil {
			return err
		}

		if realID != rs.Primary.ID {
			return fmt.Errorf("Resource ID and volume key does not match")
		}

		*volume = *retrievedVol

		return nil
	}
}

func testAccCheckLibvirtVolumeDoesNotExists(n string, volume *libvirt.StorageVol) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		virConn := testAccProvider.Meta().(*Client).libvirt

		key, err := volume.GetKey()
		if err != nil {
			return fmt.Errorf("Can't retrieve volume key: %s", err)
		}

		vol, err := virConn.LookupStorageVolByKey(key)
		if err == nil {
			vol.Free()
			return fmt.Errorf("Volume '%s' still exists", key)
		}

		return nil
	}
}

func TestAccLibvirtVolume_Basic(t *testing.T) {
	var volume libvirt.StorageVol

	const testAccCheckLibvirtVolumeConfigBasic = `
	resource "libvirt_volume" "terraform-acceptance-test-1" {
		name = "terraform-test"
		size =  1073741824
	}`

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckLibvirtVolumeDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccCheckLibvirtVolumeConfigBasic,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckLibvirtVolumeExists("libvirt_volume.terraform-acceptance-test-1", &volume),
					resource.TestCheckResourceAttr(
						"libvirt_volume.terraform-acceptance-test-1", "name", "terraform-test"),
					resource.TestCheckResourceAttr(
						"libvirt_volume.terraform-acceptance-test-1", "size", "1073741824"),
				),
			},
		},
	})
}

// The destroy function should always handle the case where the resource might already be destroyed
// (manually, for example). If the resource is already destroyed, this should not return an error.
// This allows Terraform users to manually delete resources without breaking Terraform.
// This test should fail without a proper "Exists" implementation
func TestAccLibvirtVolume_ManuallyDestroyed(t *testing.T) {
	var volume libvirt.StorageVol

	const testAccCheckLibvirtVolumeConfigBasic = `
	resource "libvirt_volume" "terraform-acceptance-test-1" {
		name = "terraform-test"
		size =  1073741824
	}`

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckLibvirtVolumeDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccCheckLibvirtVolumeConfigBasic,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckLibvirtVolumeExists("libvirt_volume.terraform-acceptance-test-1", &volume),
				),
			},
			{
				Config:  testAccCheckLibvirtVolumeConfigBasic,
				Destroy: true,
				PreConfig: func() {
					client := testAccProvider.Meta().(*Client)
					id, err := volume.GetKey()
					if err != nil {
						panic(err)
					}
					removeVolume(client, id)
				},
			},
		},
	})
}

func TestAccLibvirtVolume_UniqueName(t *testing.T) {
	const config = `
	resource "libvirt_volume" "terraform-acceptance-test-1" {
		name = "terraform-test"
		size =  1073741824
	}

	resource "libvirt_volume" "terraform-acceptance-test-2" {
		name = "terraform-test"
		size =  1073741824
	}
	`

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckLibvirtVolumeDestroy,
		Steps: []resource.TestStep{
			{
				Config:      config,
				ExpectError: regexp.MustCompile(`storage volume 'terraform-test' already exists`),
			},
		},
	})
}

func TestAccLibvirtVolume_DownloadFromSource(t *testing.T) {
	var volume libvirt.StorageVol

	fws := fileWebServer{}
	if err := fws.Start(); err != nil {
		t.Fatal(err)
	}
	defer fws.Stop()

	content := []byte("this is a qcow image... well, it is not")
	url, _, err := fws.AddFile(content)
	if err != nil {
		t.Fatal(err)
	}

	const testAccCheckLibvirtVolumeConfigSource = `
	resource "libvirt_volume" "terraform-acceptance-test-2" {
		name   = "terraform-test"
		source = "%s"
	}`
	config := fmt.Sprintf(testAccCheckLibvirtVolumeConfigSource, url)

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckLibvirtVolumeDestroy,
		Steps: []resource.TestStep{
			{
				Config: config,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckLibvirtVolumeExists("libvirt_volume.terraform-acceptance-test-2", &volume),
					resource.TestCheckResourceAttr(
						"libvirt_volume.terraform-acceptance-test-2", "name", "terraform-test"),
				),
			},
		},
	})
}

func TestAccLibvirtVolume_Format(t *testing.T) {
	var volume libvirt.StorageVol

	const testAccCheckLibvirtVolumeConfigFormat = `
	resource "libvirt_volume" "terraform-acceptance-test-3" {
		name   = "terraform-test"
		format = "raw"
		size   =  1073741824
	}`

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckLibvirtVolumeDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccCheckLibvirtVolumeConfigFormat,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckLibvirtVolumeExists("libvirt_volume.terraform-acceptance-test-3", &volume),
					resource.TestCheckResourceAttr(
						"libvirt_volume.terraform-acceptance-test-3", "name", "terraform-test"),
					resource.TestCheckResourceAttr(
						"libvirt_volume.terraform-acceptance-test-3", "size", "1073741824"),
					resource.TestCheckResourceAttr(
						"libvirt_volume.terraform-acceptance-test-3", "format", "raw"),
				),
			},
		},
	})
}

func TestAccLibvirtVolume_Import(t *testing.T) {
	var volume libvirt.StorageVol

	const testAccCheckLibvirtVolumeConfigImport = `
	resource "libvirt_volume" "terraform-acceptance-test-4" {
			name   = "terraform-test"
			format = "raw"
			size   =  1073741824
	}`

	resourceName := "libvirt_volume.terraform-acceptance-test-4"

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckLibvirtVolumeDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCheckLibvirtVolumeConfigImport,
			},
			resource.TestStep{
				ResourceName: resourceName,
				ImportState:  true,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckLibvirtVolumeExists("libvirt_volume.terraform-acceptance-test-4", &volume),
					resource.TestCheckResourceAttr(
						"libvirt_volume.terraform-acceptance-test-4", "name", "terraform-test"),
					resource.TestCheckResourceAttr(
						"libvirt_volume.terraform-acceptance-test-4", "size", "1073741824"),
				),
			},
		},
	})
}
<commit_msg>add backstore test<commit_after>package libvirt

import (
	"encoding/xml"
	"fmt"
	"regexp"
	"testing"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
	libvirt "github.com/libvirt/libvirt-go"
	//	"github.com/libvirt/libvirt-go-xml"
)

func testAccCheckLibvirtVolumeDestroy(state *terraform.State) error {
	virConn := testAccProvider.Meta().(*Client).libvirt

	for _, rs := range state.RootModule().Resources {
		if rs.Type != "libvirt_volume" {
			continue
		}

		_, err := virConn.LookupStorageVolByKey(rs.Primary.ID)
		if err == nil {
			return fmt.Errorf(
				"Error waiting for volume (%s) to be destroyed: %s",
				rs.Primary.ID, err)
		}
	}

	return nil
}

func testAccCheckLibvirtVolumeExists(name string, volume *libvirt.StorageVol) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		virConn := testAccProvider.Meta().(*Client).libvirt

		rs, ok := s.RootModule().Resources[name]
		if !ok {
			return fmt.Errorf("Not found: %s", name)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No libvirt volume key ID is set")
		}

		retrievedVol, err := virConn.LookupStorageVolByKey(rs.Primary.ID)
		if err != nil {
			return err
		}
		fmt.Printf("The ID is %s", rs.Primary.ID)

		realID, err := retrievedVol.GetKey()
		if err != nil {
			return err
		}

		if realID != rs.Primary.ID {
			return fmt.Errorf("Resource ID and volume key does not match")
		}

		*volume = *retrievedVol

		return nil
	}
}

func testAccCheckLibvirtVolumeDoesNotExists(n string, volume *libvirt.StorageVol) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		virConn := testAccProvider.Meta().(*Client).libvirt

		key, err := volume.GetKey()
		if err != nil {
			return fmt.Errorf("Can't retrieve volume key: %s", err)
		}

		vol, err := virConn.LookupStorageVolByKey(key)
		if err == nil {
			vol.Free()
			return fmt.Errorf("Volume '%s' still exists", key)
		}

		return nil
	}
}

func testAccCheckLibvirtVolumeIsBackingStore(name string, volume *libvirt.StorageVol) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		virConn := testAccProvider.Meta().(*Client).libvirt

		resource, ok := s.RootModule().Resources[name]
		if !ok {
			return fmt.Errorf("Not found: %s", name)
		}

		if resource.Primary.ID == "" {
			return fmt.Errorf("No libvirt volume key ID is set")
		}

		vol, err := virConn.LookupStorageVolByKey(resource.Primary.ID)
		if err != nil {
			return err
		}

		volXMLDesc, err := vol.GetXMLDesc(0)
		if err != nil {
			return fmt.Errorf("Error retrieving libvirt volume XML description: %s", err)
		}

		volumeDef := newDefVolume()
		err = xml.Unmarshal([]byte(volXMLDesc), &volumeDef)
		if err != nil {
			return fmt.Errorf("Error reading libvirt volume XML description: %s", err)
		}
		// if volume is a backing store it has some xml attributes set
		// if there is no backingstore this will panic
		value := volumeDef.BackingStore.Path
		if value == "" {
			return fmt.Errorf("FAIL: the volume was supposed to be a backingstore, but it is not")
		}
		return nil
	}
}

func TestAccLibvirtVolume_Basic(t *testing.T) {
	var volume libvirt.StorageVol

	const testAccCheckLibvirtVolumeConfigBasic = `
	resource "libvirt_volume" "terraform-acceptance-test-1" {
		name = "terraform-test"
		size =  1073741824
	}`

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckLibvirtVolumeDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccCheckLibvirtVolumeConfigBasic,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckLibvirtVolumeExists("libvirt_volume.terraform-acceptance-test-1", &volume),
					resource.TestCheckResourceAttr(
						"libvirt_volume.terraform-acceptance-test-1", "name", "terraform-test"),
					resource.TestCheckResourceAttr(
						"libvirt_volume.terraform-acceptance-test-1", "size", "1073741824"),
				),
			},
		},
	})
}

func TestAccLibvirtVolume_BackingStore(t *testing.T) {
	var volume libvirt.StorageVol
	var volume2 libvirt.StorageVol
	const testAccCheckLibvirtVolumeConfigBasic = `
	resource "libvirt_volume" "terraform-acceptance-test-3" {
		name = "terraform-test3"
		size =  1073741824
	}
	resource "libvirt_volume" "backing-store" {
		name = "backing-store"
		base_volume_id = "${libvirt_volume.terraform-acceptance-test-3.id}"
        }
	`

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckLibvirtVolumeDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccCheckLibvirtVolumeConfigBasic,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckLibvirtVolumeExists("libvirt_volume.terraform-acceptance-test-3", &volume),
					testAccCheckLibvirtVolumeIsBackingStore("libvirt_volume.backing-store", &volume2),
				),
			},
		},
	})
}

// The destroy function should always handle the case where the resource might already be destroyed
// (manually, for example). If the resource is already destroyed, this should not return an error.
// This allows Terraform users to manually delete resources without breaking Terraform.
// This test should fail without a proper "Exists" implementation
func TestAccLibvirtVolume_ManuallyDestroyed(t *testing.T) {
	var volume libvirt.StorageVol

	const testAccCheckLibvirtVolumeConfigBasic = `
	resource "libvirt_volume" "terraform-acceptance-test-1" {
		name = "terraform-test"
		size =  1073741824
	}`

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckLibvirtVolumeDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccCheckLibvirtVolumeConfigBasic,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckLibvirtVolumeExists("libvirt_volume.terraform-acceptance-test-1", &volume),
				),
			},
			{
				Config:  testAccCheckLibvirtVolumeConfigBasic,
				Destroy: true,
				PreConfig: func() {
					client := testAccProvider.Meta().(*Client)
					id, err := volume.GetKey()
					if err != nil {
						panic(err)
					}
					removeVolume(client, id)
				},
			},
		},
	})
}

func TestAccLibvirtVolume_UniqueName(t *testing.T) {
	const config = `
	resource "libvirt_volume" "terraform-acceptance-test-1" {
		name = "terraform-test"
		size =  1073741824
	}

	resource "libvirt_volume" "terraform-acceptance-test-2" {
		name = "terraform-test"
		size =  1073741824
	}
	`

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckLibvirtVolumeDestroy,
		Steps: []resource.TestStep{
			{
				Config:      config,
				ExpectError: regexp.MustCompile(`storage volume 'terraform-test' already exists`),
			},
		},
	})
}

func TestAccLibvirtVolume_DownloadFromSource(t *testing.T) {
	var volume libvirt.StorageVol

	fws := fileWebServer{}
	if err := fws.Start(); err != nil {
		t.Fatal(err)
	}
	defer fws.Stop()

	content := []byte("this is a qcow image... well, it is not")
	url, _, err := fws.AddFile(content)
	if err != nil {
		t.Fatal(err)
	}

	const testAccCheckLibvirtVolumeConfigSource = `
	resource "libvirt_volume" "terraform-acceptance-test-2" {
		name   = "terraform-test"
		source = "%s"
	}`
	config := fmt.Sprintf(testAccCheckLibvirtVolumeConfigSource, url)

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckLibvirtVolumeDestroy,
		Steps: []resource.TestStep{
			{
				Config: config,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckLibvirtVolumeExists("libvirt_volume.terraform-acceptance-test-2", &volume),
					resource.TestCheckResourceAttr(
						"libvirt_volume.terraform-acceptance-test-2", "name", "terraform-test"),
				),
			},
		},
	})
}

func TestAccLibvirtVolume_Format(t *testing.T) {
	var volume libvirt.StorageVol

	const testAccCheckLibvirtVolumeConfigFormat = `
	resource "libvirt_volume" "terraform-acceptance-test-3" {
		name   = "terraform-test"
		format = "raw"
		size   =  1073741824
	}`

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckLibvirtVolumeDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccCheckLibvirtVolumeConfigFormat,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckLibvirtVolumeExists("libvirt_volume.terraform-acceptance-test-3", &volume),
					resource.TestCheckResourceAttr(
						"libvirt_volume.terraform-acceptance-test-3", "name", "terraform-test"),
					resource.TestCheckResourceAttr(
						"libvirt_volume.terraform-acceptance-test-3", "size", "1073741824"),
					resource.TestCheckResourceAttr(
						"libvirt_volume.terraform-acceptance-test-3", "format", "raw"),
				),
			},
		},
	})
}

func TestAccLibvirtVolume_Import(t *testing.T) {
	var volume libvirt.StorageVol

	const testAccCheckLibvirtVolumeConfigImport = `
	resource "libvirt_volume" "terraform-acceptance-test-4" {
			name   = "terraform-test"
			format = "raw"
			size   =  1073741824
	}`

	resourceName := "libvirt_volume.terraform-acceptance-test-4"

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckLibvirtVolumeDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCheckLibvirtVolumeConfigImport,
			},
			resource.TestStep{
				ResourceName: resourceName,
				ImportState:  true,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckLibvirtVolumeExists("libvirt_volume.terraform-acceptance-test-4", &volume),
					resource.TestCheckResourceAttr(
						"libvirt_volume.terraform-acceptance-test-4", "name", "terraform-test"),
					resource.TestCheckResourceAttr(
						"libvirt_volume.terraform-acceptance-test-4", "size", "1073741824"),
				),
			},
		},
	})
}
<|endoftext|>


<commit_before>package command

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"os/signal"
	"runtime"
	"strings"
	"time"

	"github.com/docker/libcompose/docker"
	"github.com/docker/libcompose/project"
	"github.com/hashicorp/logutils"
	"github.com/samalba/dockerclient"
	"github.com/tcnksm/boot2kubernetes/config"
)

const (
	// CheckInterval is how often check k8s container is ready
	CheckInterval = 1 * time.Second

	// CheckTimeout is timeout for waiting k8s container is ready
	CheckTimeOut = 300 * time.Second
)

type UpCommand struct {
	Meta
}

func (c *UpCommand) Run(args []string) int {
	var insecure bool
	var logLevel string
	flags := flag.NewFlagSet("up", flag.ContinueOnError)
	flags.BoolVar(&insecure, "insecure", false, "")
	flags.StringVar(&logLevel, "log-level", "info", "")
	flags.Usage = func() { c.Ui.Error(c.Help()) }

	errR, errW := io.Pipe()
	errScanner := bufio.NewScanner(errR)
	go func() {
		for errScanner.Scan() {
			c.Ui.Error(errScanner.Text())
		}
	}()

	flags.SetOutput(errW)

	if err := flags.Parse(args); err != nil {
		return 1
	}

	compose, err := config.Asset("k8s.yml")
	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Failed to read k8s.yml: %s", err))
		return 1
	}

	context := &docker.Context{
		Context: project.Context{
			Log:          false,
			ComposeBytes: compose,
			ProjectName:  "boot2k8s",
		},
		Tls: !insecure,
	}

	// Setup new docker-compose project
	project, err := docker.NewProject(context)

	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Failed to setup project: %s", err))
		return 1
	}

	if err := project.Up(); err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Failed to start container: %s", err))
		return 1
	}

	if err := context.CreateClient(); err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Failed to create docker client", err))
		return 1
	}

	sigCh := make(chan os.Signal)
	signal.Notify(sigCh, os.Interrupt)

	select {
	case <-afterContainerReady(context.Client):
		c.Ui.Info("Successfully start kubernetes cluster")
	case <-sigCh:
		c.Ui.Error("")
		c.Ui.Error("Interrupted!")
		c.Ui.Error("It's ambiguous that boot2kubernetes could correctly start containers.")
		c.Ui.Error("So request to kubelet may be failed. Check the containers are working")
		c.Ui.Error("with `docker ps` command by yourself.")
		return 1
	case <-time.After(CheckTimeOut):
		c.Ui.Error("")
		c.Ui.Error("Timeout happened while waiting cluster containers are ready.")
		c.Ui.Error("It's ambiguous that boot2kubernetes could correctly start containers.")
		c.Ui.Error("So request to kubelet may be failed. Check the containers are working")
		c.Ui.Error("with `docker ps` command by yourself.")
		return 1
	}

	// If docker runs on boot2docker, port forwarding is needed.
	if runtime.GOOS == "darwin" {

		c.Ui.Output("")
		c.Ui.Output("==> WARNING: You're running docker on boot2docker!")
		c.Ui.Output("  To connect to master api server from local environment,")
		c.Ui.Output("  port forwarding is needed. boot2kubernetes starts ")
		c.Ui.Output("  server for that. To stop server, use ^C (Interrupt).\n")

		// Create logger with Log level
		logger := log.New(&logutils.LevelFilter{
			Levels:   []logutils.LogLevel{"DEBUG", "INFO", "WARN", "ERROR"},
			MinLevel: (logutils.LogLevel)(strings.ToUpper(logLevel)),
			Writer:   os.Stderr,
		}, "", log.LstdFlags)
		logger.Printf("[DEBUG] LogLevel: %s", logLevel)

		// Setup port forward server
		server := &PortForwardServer{
			Logger:       logger,
			LocalServer:  DefaultLocalServer,
			RemoteServer: DefaultRemoteServer,
		}

		doneCh, errCh, err := server.Start()
		if err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Failed to start port forwarding server: %s", err))
			return 1
		}

		sigCh := make(chan os.Signal)
		signal.Notify(sigCh, os.Interrupt)
		select {
		case err := <-errCh:
			c.Ui.Error(fmt.Sprintf(
				"Error while running port forwarding server: %s", err))
			close(doneCh)
			return 1
		case <-sigCh:
			c.Ui.Error("\nInterrupted!")
			close(doneCh)
			// Need some time for closing work...
			time.Sleep(ClosingTime)
		}
	}

	return 0
}

func (c *UpCommand) Synopsis() string {
	return "Up kubernetes cluster"
}

func (c *UpCommand) Help() string {
	helpText := `Up kubernetes cluseter

Options:

  -insecure    Allow insecure non-TLS connection to docker client.
`
	return strings.TrimSpace(helpText)
}

// afterContainerReady waits for the cluster ready and then sends the struct{}
// on the returned channel. Detection of cluster ready is very heuristic way,
// just checking number of container which is needed for running cluster.
func afterContainerReady(c dockerclient.Client) chan struct{} {
	doneCh := make(chan struct{})

	// Marshaling to post filter as API request
	filterLocalMasterStr, err := json.Marshal(FilterLocalMaster)
	if err != nil {
		// Should not reach here....
		panic(fmt.Sprintf(
			"Failed to marshal FilterLocalMaster: %s", err))
	}

	ticker := time.NewTicker(CheckInterval)
	go func() {
		fmt.Fprintf(os.Stderr, "Wait until containers are readly")
		for _ = range ticker.C {
			fmt.Fprintf(os.Stderr, ".")
			// Get Container info from deamon based on fileter
			localMasters, err := c.ListContainers(true, false, (string)(filterLocalMasterStr))
			if err != nil {
				// Just ignore error
				continue
			}

			if len(localMasters) > 3 {
				fmt.Fprintf(os.Stderr, "\n")
				doneCh <- struct{}{}
				ticker.Stop()
			}
		}
	}()

	return doneCh
}
<commit_msg>Add info message<commit_after>package command

import (
	"bufio"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"os/signal"
	"runtime"
	"strings"
	"time"

	"github.com/docker/libcompose/docker"
	"github.com/docker/libcompose/project"
	"github.com/hashicorp/logutils"
	"github.com/samalba/dockerclient"
	"github.com/tcnksm/boot2kubernetes/config"
)

const (
	// CheckInterval is how often check k8s container is ready
	CheckInterval = 1 * time.Second

	// CheckTimeout is timeout for waiting k8s container is ready
	CheckTimeOut = 300 * time.Second
)

type UpCommand struct {
	Meta
}

func (c *UpCommand) Run(args []string) int {
	var insecure bool
	var logLevel string
	flags := flag.NewFlagSet("up", flag.ContinueOnError)
	flags.BoolVar(&insecure, "insecure", false, "")
	flags.StringVar(&logLevel, "log-level", "info", "")
	flags.Usage = func() { c.Ui.Error(c.Help()) }

	errR, errW := io.Pipe()
	errScanner := bufio.NewScanner(errR)
	go func() {
		for errScanner.Scan() {
			c.Ui.Error(errScanner.Text())
		}
	}()

	flags.SetOutput(errW)

	if err := flags.Parse(args); err != nil {
		return 1
	}

	compose, err := config.Asset("k8s.yml")
	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Failed to read k8s.yml: %s", err))
		return 1
	}

	context := &docker.Context{
		Context: project.Context{
			Log:          false,
			ComposeBytes: compose,
			ProjectName:  "boot2k8s",
		},
		Tls: !insecure,
	}

	// Setup new docker-compose project
	project, err := docker.NewProject(context)

	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Failed to setup project: %s", err))
		return 1
	}

	c.Ui.Output("Start kubernetes cluster")
	if err := project.Up(); err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Failed to start container: %s", err))
		return 1
	}

	if err := context.CreateClient(); err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Failed to create docker client", err))
		return 1
	}

	sigCh := make(chan os.Signal)
	signal.Notify(sigCh, os.Interrupt)

	select {
	case <-afterContainerReady(context.Client):
		c.Ui.Info("Successfully start kubernetes cluster")
	case <-sigCh:
		c.Ui.Error("")
		c.Ui.Error("Interrupted!")
		c.Ui.Error("It's ambiguous that boot2kubernetes could correctly start containers.")
		c.Ui.Error("So request to kubelet may be failed. Check the containers are working")
		c.Ui.Error("with `docker ps` command by yourself.")
		return 1
	case <-time.After(CheckTimeOut):
		c.Ui.Error("")
		c.Ui.Error("Timeout happened while waiting cluster containers are ready.")
		c.Ui.Error("It's ambiguous that boot2kubernetes could correctly start containers.")
		c.Ui.Error("So request to kubelet may be failed. Check the containers are working")
		c.Ui.Error("with `docker ps` command by yourself.")
		return 1
	}

	// If docker runs on boot2docker, port forwarding is needed.
	if runtime.GOOS == "darwin" {

		c.Ui.Output("")
		c.Ui.Output("==> WARNING: You're running docker on boot2docker!")
		c.Ui.Output("  To connect to master api server from local environment,")
		c.Ui.Output("  port forwarding is needed. boot2kubernetes starts ")
		c.Ui.Output("  server for that. To stop server, use ^C (Interrupt).\n")

		// Create logger with Log level
		logger := log.New(&logutils.LevelFilter{
			Levels:   []logutils.LogLevel{"DEBUG", "INFO", "WARN", "ERROR"},
			MinLevel: (logutils.LogLevel)(strings.ToUpper(logLevel)),
			Writer:   os.Stderr,
		}, "", log.LstdFlags)
		logger.Printf("[DEBUG] LogLevel: %s", logLevel)

		// Setup port forward server
		server := &PortForwardServer{
			Logger:       logger,
			LocalServer:  DefaultLocalServer,
			RemoteServer: DefaultRemoteServer,
		}

		doneCh, errCh, err := server.Start()
		if err != nil {
			c.Ui.Error(fmt.Sprintf(
				"Failed to start port forwarding server: %s", err))
			return 1
		}

		sigCh := make(chan os.Signal)
		signal.Notify(sigCh, os.Interrupt)
		select {
		case err := <-errCh:
			c.Ui.Error(fmt.Sprintf(
				"Error while running port forwarding server: %s", err))
			close(doneCh)
			return 1
		case <-sigCh:
			c.Ui.Error("\nInterrupted!")
			close(doneCh)
			// Need some time for closing work...
			time.Sleep(ClosingTime)
		}
	}

	return 0
}

func (c *UpCommand) Synopsis() string {
	return "Up kubernetes cluster"
}

func (c *UpCommand) Help() string {
	helpText := `Up kubernetes cluseter

Options:

  -insecure    Allow insecure non-TLS connection to docker client.
`
	return strings.TrimSpace(helpText)
}

// afterContainerReady waits for the cluster ready and then sends the struct{}
// on the returned channel. Detection of cluster ready is very heuristic way,
// just checking number of container which is needed for running cluster.
func afterContainerReady(c dockerclient.Client) chan struct{} {
	doneCh := make(chan struct{})

	// Marshaling to post filter as API request
	filterLocalMasterStr, err := json.Marshal(FilterLocalMaster)
	if err != nil {
		// Should not reach here....
		panic(fmt.Sprintf(
			"Failed to marshal FilterLocalMaster: %s", err))
	}

	ticker := time.NewTicker(CheckInterval)
	go func() {
		fmt.Fprintf(os.Stderr, "Wait until containers are readly")
		for _ = range ticker.C {
			fmt.Fprintf(os.Stderr, ".")
			// Get Container info from deamon based on fileter
			localMasters, err := c.ListContainers(true, false, (string)(filterLocalMasterStr))
			if err != nil {
				// Just ignore error
				continue
			}

			if len(localMasters) > 3 {
				fmt.Fprintf(os.Stderr, "\n")
				doneCh <- struct{}{}
				ticker.Stop()
			}
		}
	}()

	return doneCh
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/mitchellh/packer/packer/plugin"
	"github.com/mitchellh/packer/packer"
	"github.com/mitchellh/packer/common"
	"github.com/mitchellh/packer/builder/docker"
	"github.com/mitchellh/packer/post-processor/docker-import"
	"encoding/json"
	"log"
	"fmt"
	"os"
	"os/exec"
	"bytes"
	"bufio"
	"text/template"
	"strings"
	"regexp"
	"errors"
)
const BuilderId = "packer.post-processor.docker-dockerfile"

func main() {
	server, err := plugin.Server()
	if err != nil {
		log.Printf("[ERR] %s", err)
		os.Exit(1)
	}
	server.RegisterPostProcessor(new(PostProcessor))
	server.Serve()
}

type PostProcessor struct {
	c Config
	t *template.Template
	docker_build_fn func(*bytes.Buffer) (string, error) // to facilitate easy testing
	tpl *packer.ConfigTemplate
}

type Config struct {
	common.PackerConfig     `mapstructure:",squash"`

	Expose []string         `mapstructure:"expose"`
	User string             `mapstructure:"user"`
	Env map[string]string   `mapstructure:"env"`
	Volume []string         `mapstructure:"volume"`
	WorkDir string          `mapstructure:"workdir"`
	Entrypoint interface{}  `mapstructure:"entrypoint"`
	Cmd interface{}         `mapstructure:"cmd"`
	ImageId string
}

func (p *PostProcessor) Configure(raw_config ...interface{}) error {
	var err error
	_, err = common.DecodeConfig(&p.c, raw_config...)
	if err != nil {
		return err
	}
	p.docker_build_fn = docker_build // configure the build function
	if err = p.prepare_config_template(); err != nil { return err }

	return nil
}

func (p *PostProcessor) prepare_config_template() error {
	tpl, err := packer.NewConfigTemplate()
	if err != nil { return err }

	tpl.UserVars = p.c.PackerUserVars
	p.tpl = tpl

	return nil
}

func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
	if artifact.BuilderId() != dockerimport.BuilderId {
		err := fmt.Errorf(
			"Unknown artifact type: %s\nCan only tag from Docker builder artifacts.",
			artifact.BuilderId())
		return nil, false, err
	}

	dockerfile, template_err := p.render_template(artifact.Id())
	if template_err != nil { // could not render template
		return nil, false, template_err
	}
	log.Printf("[DEBUG] Dockerfile: %s\n", dockerfile.String())

	if image_id, err := p.docker_build_fn(dockerfile); err != nil { // docker build command failed
		return nil, false, err
	} else {
		ui.Message("Built image: " + image_id)
		new_artifact := &docker.ImportArtifact{
			BuilderIdValue: dockerimport.BuilderId,
			Driver: &docker.DockerDriver{Ui: ui, Tpl: nil},
			IdValue: image_id,
		}
		log.Printf("[DEBUG] artifact: %#v\n", new_artifact)
		return new_artifact, true, nil
	}
}

// Render a variable template using packer.ConfigTemplate primed with user variables
// You must call p.prepare_config_template() before using this function
func (p *PostProcessor) render(var_tmpl string) string {
	rendered, err := p.tpl.Process(var_tmpl, nil)
	if err != nil {
		panic(err)
	}
	return rendered
}

// Process a variable of unknown type. This function will call render() to render any packer user variables
// This function will panic if it can't handle the variable.
func (p *PostProcessor) process_var(variable interface{}) string {
	errs := new(packer.MultiError)

	render_string_or_slice := func(field interface{}) interface{} {
		switch t := field.(type) {
		case []string:
			ary := make([]string, 0, len(t))
			for _, item := range t {
				ary = append(ary, p.render(item))
			}
			return ary
		case []interface{}:
			ary := make([]string, 0, len(t))
			for _, item := range t {
				ary = append(ary, p.render(item.(string)))
			}
			return ary
		case string: return p.render(t)
		case nil: return nil
		default:
			errs = packer.MultiErrorAppend(errs, fmt.Errorf("Error processing %s: not a string or a string array", field))
			return nil
		}
	}

	switch t := variable.(type) {
	case []string: return json_dump_slice(render_string_or_slice(t))
	case []interface{}: return json_dump_slice(render_string_or_slice(t))
	case string: return p.render(variable.(string))
	case nil: return ""
	default: panic(errors.New("not sure how to handle type"))
	}
	if len(errs.Errors) > 0 {
		panic(errs)
	}
	return ""
}

func json_dump_slice(data interface{}) string {
	if res, err := json.Marshal(data); err != nil {
		panic(err)
	} else {
		return string(res)
	}
}

func (p *PostProcessor)render_template(id string) (buf *bytes.Buffer, _err error) {
	template_str := `FROM {{ .ImageId }}
{{ if .Volume }}VOLUME {{ stringify .Volume }}
{{ end }}{{ if .Expose }}EXPOSE {{ join .Expose " " }}
{{ end }}{{ if .WorkDir }}WORKDIR {{ .WorkDir }}
{{ end }}{{ if .User }}USER {{ .User }}
{{ end }}{{ if .Env }}{{ range $k, $v := .Env }}ENV {{ $k }} {{ render $v }}
{{ end }}{{ end }}{{ if .Entrypoint }}ENTRYPOINT {{ stringify .Entrypoint }}
{{ end }}{{ if .Cmd }}{{ stringify .Cmd }}{{ end }}`
	template_buffer := new(bytes.Buffer)
	template_writer := bufio.NewWriter(template_buffer)

	p.c.ImageId = id

	defer func() {
		if err := recover(); err != nil {
			switch t_err := err.(type) {
			case error: _err = t_err // caught panic, return error to caller
			case string: _err = errors.New(t_err)
			default:
			}
		}
	}()

	t, err := template.New("dockerfile").Funcs(template.FuncMap{
		"stringify": p.process_var,
		"join": strings.Join,
		"render": func(s string) string {
			return p.render(s)
		},
	}).Parse(template_str)
	if err != nil {
		return nil, err
	}

	if err := t.Execute(template_writer, p.c); err != nil {
		return nil, err
	}
	template_writer.Flush()

	return template_buffer, nil
}

func docker_build(stdin *bytes.Buffer) (string, error) {
	var stderr bytes.Buffer
	var stdout bytes.Buffer
	cmd := exec.Command("docker", "build", "--rm", "-q", "-")
	cmd.Stdin = stdin
	cmd.Stderr = &stderr
	cmd.Stdout = &stdout

	if err := cmd.Start(); err != nil {
		return "", err
	}
	if err := cmd.Wait(); err != nil {
		log.Printf("[ERR] error while running docker build. error: %s, command output: %s", err, stderr.String())
		return "", err
	}
	log.Println("Docker build command output:\n" + stdout.String())
	lines := strings.Split(stdout.String(), "\n")
	last_line := lines[len(lines) - 2] // we seem to have a trailing empty line
	image_id_regexp := regexp.MustCompile("Successfully built ([a-f0-9]+)")
	if matches := image_id_regexp.FindStringSubmatch(last_line); len(matches) > 0 {
		image_id := matches[len(matches) - 1]
		return image_id, nil
	} else {
		return "", errors.New("Could not parse `docker build` output")
	}
}
<commit_msg>don't use cached layers and cleanup even on failed builds<commit_after>package main

import (
	"github.com/mitchellh/packer/packer/plugin"
	"github.com/mitchellh/packer/packer"
	"github.com/mitchellh/packer/common"
	"github.com/mitchellh/packer/builder/docker"
	"github.com/mitchellh/packer/post-processor/docker-import"
	"encoding/json"
	"log"
	"fmt"
	"os"
	"os/exec"
	"bytes"
	"bufio"
	"text/template"
	"strings"
	"regexp"
	"errors"
)
const BuilderId = "packer.post-processor.docker-dockerfile"

func main() {
	server, err := plugin.Server()
	if err != nil {
		log.Printf("[ERR] %s", err)
		os.Exit(1)
	}
	server.RegisterPostProcessor(new(PostProcessor))
	server.Serve()
}

type PostProcessor struct {
	c Config
	t *template.Template
	docker_build_fn func(*bytes.Buffer) (string, error) // to facilitate easy testing
	tpl *packer.ConfigTemplate
}

type Config struct {
	common.PackerConfig     `mapstructure:",squash"`

	Expose []string         `mapstructure:"expose"`
	User string             `mapstructure:"user"`
	Env map[string]string   `mapstructure:"env"`
	Volume []string         `mapstructure:"volume"`
	WorkDir string          `mapstructure:"workdir"`
	Entrypoint interface{}  `mapstructure:"entrypoint"`
	Cmd interface{}         `mapstructure:"cmd"`
	ImageId string
}

func (p *PostProcessor) Configure(raw_config ...interface{}) error {
	var err error
	_, err = common.DecodeConfig(&p.c, raw_config...)
	if err != nil {
		return err
	}
	p.docker_build_fn = docker_build // configure the build function
	if err = p.prepare_config_template(); err != nil { return err }

	return nil
}

func (p *PostProcessor) prepare_config_template() error {
	tpl, err := packer.NewConfigTemplate()
	if err != nil { return err }

	tpl.UserVars = p.c.PackerUserVars
	p.tpl = tpl

	return nil
}

func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) {
	if artifact.BuilderId() != dockerimport.BuilderId {
		err := fmt.Errorf(
			"Unknown artifact type: %s\nCan only tag from Docker builder artifacts.",
			artifact.BuilderId())
		return nil, false, err
	}

	dockerfile, template_err := p.render_template(artifact.Id())
	if template_err != nil { // could not render template
		return nil, false, template_err
	}
	log.Printf("[DEBUG] Dockerfile: %s\n", dockerfile.String())

	if image_id, err := p.docker_build_fn(dockerfile); err != nil { // docker build command failed
		return nil, false, err
	} else {
		ui.Message("Built image: " + image_id)
		new_artifact := &docker.ImportArtifact{
			BuilderIdValue: dockerimport.BuilderId,
			Driver: &docker.DockerDriver{Ui: ui, Tpl: nil},
			IdValue: image_id,
		}
		log.Printf("[DEBUG] artifact: %#v\n", new_artifact)
		return new_artifact, true, nil
	}
}

// Render a variable template using packer.ConfigTemplate primed with user variables
// You must call p.prepare_config_template() before using this function
func (p *PostProcessor) render(var_tmpl string) string {
	rendered, err := p.tpl.Process(var_tmpl, nil)
	if err != nil {
		panic(err)
	}
	return rendered
}

// Process a variable of unknown type. This function will call render() to render any packer user variables
// This function will panic if it can't handle the variable.
func (p *PostProcessor) process_var(variable interface{}) string {
	errs := new(packer.MultiError)

	render_string_or_slice := func(field interface{}) interface{} {
		switch t := field.(type) {
		case []string:
			ary := make([]string, 0, len(t))
			for _, item := range t {
				ary = append(ary, p.render(item))
			}
			return ary
		case []interface{}:
			ary := make([]string, 0, len(t))
			for _, item := range t {
				ary = append(ary, p.render(item.(string)))
			}
			return ary
		case string: return p.render(t)
		case nil: return nil
		default:
			errs = packer.MultiErrorAppend(errs, fmt.Errorf("Error processing %s: not a string or a string array", field))
			return nil
		}
	}

	switch t := variable.(type) {
	case []string: return json_dump_slice(render_string_or_slice(t))
	case []interface{}: return json_dump_slice(render_string_or_slice(t))
	case string: return p.render(variable.(string))
	case nil: return ""
	default: panic(errors.New("not sure how to handle type"))
	}
	if len(errs.Errors) > 0 {
		panic(errs)
	}
	return ""
}

func json_dump_slice(data interface{}) string {
	if res, err := json.Marshal(data); err != nil {
		panic(err)
	} else {
		return string(res)
	}
}

func (p *PostProcessor)render_template(id string) (buf *bytes.Buffer, _err error) {
	template_str := `FROM {{ .ImageId }}
{{ if .Volume }}VOLUME {{ stringify .Volume }}
{{ end }}{{ if .Expose }}EXPOSE {{ join .Expose " " }}
{{ end }}{{ if .WorkDir }}WORKDIR {{ .WorkDir }}
{{ end }}{{ if .User }}USER {{ .User }}
{{ end }}{{ if .Env }}{{ range $k, $v := .Env }}ENV {{ $k }} {{ render $v }}
{{ end }}{{ end }}{{ if .Entrypoint }}ENTRYPOINT {{ stringify .Entrypoint }}
{{ end }}{{ if .Cmd }}{{ stringify .Cmd }}{{ end }}`
	template_buffer := new(bytes.Buffer)
	template_writer := bufio.NewWriter(template_buffer)

	p.c.ImageId = id

	defer func() {
		if err := recover(); err != nil {
			switch t_err := err.(type) {
			case error: _err = t_err // caught panic, return error to caller
			case string: _err = errors.New(t_err)
			default:
			}
		}
	}()

	t, err := template.New("dockerfile").Funcs(template.FuncMap{
		"stringify": p.process_var,
		"join": strings.Join,
		"render": func(s string) string {
			return p.render(s)
		},
	}).Parse(template_str)
	if err != nil {
		return nil, err
	}

	if err := t.Execute(template_writer, p.c); err != nil {
		return nil, err
	}
	template_writer.Flush()

	return template_buffer, nil
}

func docker_build(stdin *bytes.Buffer) (string, error) {
	var stderr bytes.Buffer
	var stdout bytes.Buffer
	cmd := exec.Command("docker", "build", "--force-rm=true", "--no-cache=true", "-q", "-")
	cmd.Stdin = stdin
	cmd.Stderr = &stderr
	cmd.Stdout = &stdout

	if err := cmd.Start(); err != nil {
		return "", err
	}
	if err := cmd.Wait(); err != nil {
		log.Printf("[ERR] error while running docker build. error: %s, command output: %s", err, stderr.String())
		return "", err
	}
	log.Println("Docker build command output:\n" + stdout.String())
	lines := strings.Split(stdout.String(), "\n")
	last_line := lines[len(lines) - 2] // we seem to have a trailing empty line
	image_id_regexp := regexp.MustCompile("Successfully built ([a-f0-9]+)")
	if matches := image_id_regexp.FindStringSubmatch(last_line); len(matches) > 0 {
		image_id := matches[len(matches) - 1]
		return image_id, nil
	} else {
		return "", errors.New("Could not parse `docker build` output")
	}
}
<|endoftext|>


<commit_before>package main
import(
	"fmt"
	"bytes"
	"strconv"
)

type game struct{
	set [9]string
	size int
}

func(g *game)runner(x int, i int)bool{
	if g.set[x] == g.set[x+i] && g.set[x+i] == g.set[x+i+i]{
		return true
	}
	return false
}

func(g *game)Validate( i int )bool{
	//only works if size is odd
	if g.runner((i / g.size)*g.size, 1){
		fmt.Println("Checking: 1",i)
		return true
	}
	if g.runner(i % g.size, g.size){
		fmt.Println("Checking: 2",i)
		return true
	}

	switch i{
		case g.size - 1: fallthrough
		case g.size * 2:
			if g.runner(g.size - 1, g.size - 1){
				fmt.Println("Checking: 3",i)
				return true
			}
		case 0: fallthrough
		case g.size*g.size:
			if g.runner(0, g.size + (g.size / 2)){
				fmt.Println("Checking: 4",i)
				return true
			}
		case (g.size*g.size)/2:
			if g.runner(g.size - 1, g.size - 1) || g.runner(0, g.size + (g.size / 2)) {
				fmt.Println("Checking: 5",i)
				//diagonals
				return true
			}
	}
	return false
}

func(g *game)Set(i int, s string)bool{
	if g.set[i] != ""{
		return false
	}
	g.set[i] = s
	return true
}

func (g game) String() string{
	var buffer bytes.Buffer
	out := ""
	pi := 1
	row := 1
	new := true
	buffer.WriteString("\n   ")
	for k := 0; k < g.size; k++{
		buffer.WriteString(strconv.Itoa(k+1)+" ")
	}
	buffer.WriteString("\n")
	for k,_ := range g.set{
		if new {
			buffer.WriteString(strconv.Itoa(row)+" ")
			new = false
			row++
		}
		buffer.WriteString("|")
		if g.set[k] == ""{
			out = "_"
		}else{
			out = g.set[k]
		}
		buffer.WriteString(out)

		if pi%g.size == 0{
			buffer.WriteString("|")
			buffer.WriteString("\n")
			new = true
		}
		pi++
	}
	return buffer.String()
}

func (g *game)GetInput()int{
	var i int
	_, err := fmt.Scanf("%d", &i)

	if err != nil || i > g.size || i < 0 {
		fmt.Print("Please enter a valid number.")
		return g.GetInput()
	}
	return i
}

func main(){
	g := game{set:[9]string{}, size: 3}
	winner := false
	player := true
	count := 0
	cur := "X"
	for false == winner{
		fmt.Println(g)

		if !player{
			cur = "O"
		}else {
			cur = "X"
		}
		fmt.Println("Player ",cur,":")

		fmt.Println("Select a Row:")
		r := g.GetInput()

		fmt.Println("Select a Column:")
		c := g.GetInput()
		i := (r - 1) * 3 + c - 1

		if !g.Set( i, cur ){
			fmt.Println("Position is already taken.")
			continue
		}

		count++
		if len(g.set) == count{
			break
		}
		winner = g.Validate(i)
		player = !player
	}

	fmt.Println(g)
	if winner {
		fmt.Println(cur, "is the winner.")
	}else{
		fmt.Println("Cats")
	}
}
<commit_msg>small cleanup<commit_after>package main
import(
	"fmt"
	"bytes"
	"strconv"
)

type game struct{
	set [9]string
	size int
}

func(g *game)runner(x int, i int)bool{
	if g.set[x] == g.set[x+i] && g.set[x+i] == g.set[x+i+i]{
		return true
	}
	return false
}

func(g *game)Validate( i int )bool{
	//only works if size is odd
	if g.runner((i / g.size)*g.size, 1){
		fmt.Println("Checking: 1",i)
		return true
	}
	if g.runner(i % g.size, g.size){
		fmt.Println("Checking: 2",i)
		return true
	}

	switch i{
		case g.size - 1: fallthrough
		case g.size * 2:
			if g.runner(g.size - 1, g.size - 1){
				fmt.Println("Checking: 3",i)
				return true
			}
		case 0: fallthrough
		case g.size*g.size:
			if g.runner(0, g.size + (g.size / 2)){
				fmt.Println("Checking: 4",i)
				return true
			}
		case (g.size*g.size)/2:
			if g.runner(g.size - 1, g.size - 1) || g.runner(0, g.size + (g.size / 2)) {
				fmt.Println("Checking: 5",i)
				//diagonals
				return true
			}
	}
	return false
}

func(g *game)Set(i int, s string)bool{
	if g.set[i] != ""{
		return false
	}
	g.set[i] = s
	return true
}

func (g game) String() string{
	var buffer bytes.Buffer
	out := ""
	pi := 1
	row := 1
	new := true
	buffer.WriteString("\n   ")
	for k := 0; k < g.size; k++{
		buffer.WriteString(strconv.Itoa(k+1)+" ")
	}
	buffer.WriteString("\n")
	for k,_ := range g.set{
		if new {
			buffer.WriteString(strconv.Itoa(row)+" ")
			new = false
			row++
		}
		buffer.WriteString("|")
		if g.set[k] == ""{
			out = "_"
		}else{
			out = g.set[k]
		}
		buffer.WriteString(out)

		if pi%g.size == 0{
			buffer.WriteString("|")
			buffer.WriteString("\n")
			new = true
		}
		pi++
	}
	return buffer.String()
}

func (g *game)GetInput()int{
	var i int
	_, err := fmt.Scanf("%d", &i)

	if err != nil || i > g.size || i < 0 {
		fmt.Print("Please enter a valid number.")
		return g.GetInput()
	}
	return i
}

func main(){
	g := game{size: 3}
	winner := false
	player := true
	count := 0
	cur := "X"

	for false == winner{
		fmt.Println(g)

		if !player{
			cur = "O"
		}else {
			cur = "X"
		}
		fmt.Println("Player ",cur,":")

		fmt.Println("Select a Row:")
		r := g.GetInput()

		fmt.Println("Select a Column:")
		c := g.GetInput()
		i := (r - 1) * 3 + c - 1

		if !g.Set( i, cur ){
			fmt.Println("Position is already taken.")
			continue
		}

		count++
		if len(g.set) == count{
			break
		}
		winner = g.Validate(i)
		player = !player
	}

	fmt.Println(g)
	if winner {
		fmt.Println(cur, "is the winner.")
	}else{
		fmt.Println("Cats")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/md5"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
)

var help = `Usage: %v FIRST_DIR SECOND_DIR
`

func mapDir(name string) (map[[16]byte]string, error) {
	fullPath, err := filepath.Abs(name)
	if err != nil {
		return nil, err
	}
	dirlist, err := ioutil.ReadDir(fullPath)
	if err != nil {
		return nil, err
	}
	m := make(map[[16]byte]string, len(dirlist))
	for _, item := range dirlist {
		file, err := os.Open(filepath.Join(fullPath, item.Name()))
		if err != nil {
			return m, err
		}
		data, err := ioutil.ReadAll(file)
		m[md5.Sum(data)] = item.Name()
	}
	return m, nil

}

func main() {
	if len(os.Args) != 3 {
		fmt.Printf(help, os.Args[0])
	}
	local, err := mapDir(os.Args[1])
	remote, err := mapDir(os.Args[2])
	if err != nil {
		fmt.Print(err)
		os.Exit(1)
	}
	for k := range local {
		if _, ok := remote[k]; ok {
			fmt.Printf("%v\t%v\n", local[k], remote[k])
		}
	}
}
<commit_msg>ignore directories and write full path<commit_after>package main

import (
	"crypto/md5"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
)

var help = `Usage: %v FIRST_DIR SECOND_DIR
`

func mapDir(name string) (map[[16]byte]string, error) {
	fullPath, err := filepath.Abs(name)
	if err != nil {
		return nil, err
	}
	dirlist, err := ioutil.ReadDir(fullPath)
	if err != nil {
		return nil, err
	}
	m := make(map[[16]byte]string, len(dirlist))
	for _, item := range dirlist {
		if item.IsDir() {
			continue
		}
		longName := filepath.Join(fullPath, item.Name())
		file, err := os.Open(longName)
		if err != nil {
			return m, err
		}
		data, err := ioutil.ReadAll(file)
		m[md5.Sum(data)] = longName
	}
	return m, nil

}

func main() {
	if len(os.Args) != 3 {
		fmt.Printf(help, os.Args[0])
	}
	local, err := mapDir(os.Args[1])
	remote, err := mapDir(os.Args[2])
	if err != nil {
		fmt.Print(err)
		os.Exit(1)
	}
	for k := range local {
		if _, ok := remote[k]; ok {
			fmt.Printf("%v\t%v\n", local[k], remote[k])
		}
	}
}
<|endoftext|>