<commit_before>// +build linux

package mount

import (
	"os"
	"path"
	"testing"

	"github.com/pkg/errors"
	"golang.org/x/sys/unix"
)

// nothing is propagated in or out
func TestSubtreePrivate(t *testing.T) {
	if os.Getuid() != 0 {
		t.Skip("root required")
	}

	tmp := path.Join(os.TempDir(), "mount-tests")
	if err := os.MkdirAll(tmp, 0777); err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmp)

	var (
		sourceDir   = path.Join(tmp, "source")
		targetDir   = path.Join(tmp, "target")
		outside1Dir = path.Join(tmp, "outside1")
		outside2Dir = path.Join(tmp, "outside2")

		outside1Path      = path.Join(outside1Dir, "file.txt")
		outside2Path      = path.Join(outside2Dir, "file.txt")
		outside1CheckPath = path.Join(targetDir, "a", "file.txt")
		outside2CheckPath = path.Join(sourceDir, "b", "file.txt")
	)
	if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.MkdirAll(path.Join(sourceDir, "b"), 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(targetDir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(outside1Dir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(outside2Dir, 0777); err != nil {
		t.Fatal(err)
	}

	if err := createFile(outside1Path); err != nil {
		t.Fatal(err)
	}
	if err := createFile(outside2Path); err != nil {
		t.Fatal(err)
	}

	// mount the shared directory to a target
	if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()

	// next, make the target private
	if err := MakePrivate(targetDir); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()

	// mount in an outside path to a mounted path inside the _source_
	if err := Mount(outside1Dir, path.Join(sourceDir, "a"), "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(path.Join(sourceDir, "a")); err != nil {
			t.Fatal(err)
		}
	}()

	// check that this file _does_not_ show in the _target_
	if _, err := os.Stat(outside1CheckPath); err != nil && !os.IsNotExist(err) {
		t.Fatal(err)
	} else if err == nil {
		t.Fatalf("%q should not be visible, but is", outside1CheckPath)
	}

	// next mount outside2Dir into the _target_
	if err := Mount(outside2Dir, path.Join(targetDir, "b"), "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(path.Join(targetDir, "b")); err != nil {
			t.Fatal(err)
		}
	}()

	// check that this file _does_not_ show in the _source_
	if _, err := os.Stat(outside2CheckPath); err != nil && !os.IsNotExist(err) {
		t.Fatal(err)
	} else if err == nil {
		t.Fatalf("%q should not be visible, but is", outside2CheckPath)
	}
}

// Testing that when a target is a shared mount,
// then child mounts propagate to the source
func TestSubtreeShared(t *testing.T) {
	if os.Getuid() != 0 {
		t.Skip("root required")
	}

	tmp := path.Join(os.TempDir(), "mount-tests")
	if err := os.MkdirAll(tmp, 0777); err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmp)

	var (
		sourceDir  = path.Join(tmp, "source")
		targetDir  = path.Join(tmp, "target")
		outsideDir = path.Join(tmp, "outside")

		outsidePath     = path.Join(outsideDir, "file.txt")
		sourceCheckPath = path.Join(sourceDir, "a", "file.txt")
	)

	if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(targetDir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(outsideDir, 0777); err != nil {
		t.Fatal(err)
	}

	if err := createFile(outsidePath); err != nil {
		t.Fatal(err)
	}

	// mount the source as shared
	if err := MakeShared(sourceDir); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(sourceDir); err != nil {
			t.Fatal(err)
		}
	}()

	// mount the shared directory to a target
	if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()

	// mount in an outside path to a mounted path inside the target
	if err := Mount(outsideDir, path.Join(targetDir, "a"), "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(path.Join(targetDir, "a")); err != nil {
			t.Fatal(err)
		}
	}()

	// NOW, check that the file from the outside directory is available in the source directory
	if _, err := os.Stat(sourceCheckPath); err != nil {
		t.Fatal(err)
	}
}

// testing that mounts to a shared source show up in the slave target,
// and that mounts into a slave target do _not_ show up in the shared source
func TestSubtreeSharedSlave(t *testing.T) {
	if os.Getuid() != 0 {
		t.Skip("root required")
	}

	tmp := path.Join(os.TempDir(), "mount-tests")
	if err := os.MkdirAll(tmp, 0777); err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmp)

	var (
		sourceDir   = path.Join(tmp, "source")
		targetDir   = path.Join(tmp, "target")
		outside1Dir = path.Join(tmp, "outside1")
		outside2Dir = path.Join(tmp, "outside2")

		outside1Path      = path.Join(outside1Dir, "file.txt")
		outside2Path      = path.Join(outside2Dir, "file.txt")
		outside1CheckPath = path.Join(targetDir, "a", "file.txt")
		outside2CheckPath = path.Join(sourceDir, "b", "file.txt")
	)
	if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.MkdirAll(path.Join(sourceDir, "b"), 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(targetDir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(outside1Dir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(outside2Dir, 0777); err != nil {
		t.Fatal(err)
	}

	if err := createFile(outside1Path); err != nil {
		t.Fatal(err)
	}
	if err := createFile(outside2Path); err != nil {
		t.Fatal(err)
	}

	// mount the source as shared
	if err := MakeShared(sourceDir); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(sourceDir); err != nil {
			t.Fatal(err)
		}
	}()

	// mount the shared directory to a target
	if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()

	// next, make the target slave
	if err := MakeSlave(targetDir); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()

	// mount in an outside path to a mounted path inside the _source_
	if err := Mount(outside1Dir, path.Join(sourceDir, "a"), "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(path.Join(sourceDir, "a")); err != nil {
			t.Fatal(err)
		}
	}()

	// check that this file _does_ show in the _target_
	if _, err := os.Stat(outside1CheckPath); err != nil {
		t.Fatal(err)
	}

	// next mount outside2Dir into the _target_
	if err := Mount(outside2Dir, path.Join(targetDir, "b"), "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(path.Join(targetDir, "b")); err != nil {
			t.Fatal(err)
		}
	}()

	// check that this file _does_not_ show in the _source_
	if _, err := os.Stat(outside2CheckPath); err != nil && !os.IsNotExist(err) {
		t.Fatal(err)
	} else if err == nil {
		t.Fatalf("%q should not be visible, but is", outside2CheckPath)
	}
}

func TestSubtreeUnbindable(t *testing.T) {
	if os.Getuid() != 0 {
		t.Skip("root required")
	}

	tmp := path.Join(os.TempDir(), "mount-tests")
	if err := os.MkdirAll(tmp, 0777); err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmp)

	var (
		sourceDir = path.Join(tmp, "source")
		targetDir = path.Join(tmp, "target")
	)
	if err := os.MkdirAll(sourceDir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.MkdirAll(targetDir, 0777); err != nil {
		t.Fatal(err)
	}

	// next, make the source unbindable
	if err := MakeUnbindable(sourceDir); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(sourceDir); err != nil {
			t.Fatal(err)
		}
	}()

	// then attempt to mount it to target. It should fail
	if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil && errors.Cause(err) != unix.EINVAL {
		t.Fatal(err)
	} else if err == nil {
		t.Fatalf("%q should not have been bindable", sourceDir)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()
}

func createFile(path string) error {
	f, err := os.Create(path)
	if err != nil {
		return err
	}
	f.WriteString("hello world!")
	return f.Close()
}
<commit_msg>mount: rm pkg/errors use<commit_after>// +build linux,go1.13

package mount

import (
	"errors"
	"os"
	"path"
	"testing"

	"golang.org/x/sys/unix"
)

// nothing is propagated in or out
func TestSubtreePrivate(t *testing.T) {
	if os.Getuid() != 0 {
		t.Skip("root required")
	}

	tmp := path.Join(os.TempDir(), "mount-tests")
	if err := os.MkdirAll(tmp, 0777); err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmp)

	var (
		sourceDir   = path.Join(tmp, "source")
		targetDir   = path.Join(tmp, "target")
		outside1Dir = path.Join(tmp, "outside1")
		outside2Dir = path.Join(tmp, "outside2")

		outside1Path      = path.Join(outside1Dir, "file.txt")
		outside2Path      = path.Join(outside2Dir, "file.txt")
		outside1CheckPath = path.Join(targetDir, "a", "file.txt")
		outside2CheckPath = path.Join(sourceDir, "b", "file.txt")
	)
	if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.MkdirAll(path.Join(sourceDir, "b"), 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(targetDir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(outside1Dir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(outside2Dir, 0777); err != nil {
		t.Fatal(err)
	}

	if err := createFile(outside1Path); err != nil {
		t.Fatal(err)
	}
	if err := createFile(outside2Path); err != nil {
		t.Fatal(err)
	}

	// mount the shared directory to a target
	if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()

	// next, make the target private
	if err := MakePrivate(targetDir); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()

	// mount in an outside path to a mounted path inside the _source_
	if err := Mount(outside1Dir, path.Join(sourceDir, "a"), "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(path.Join(sourceDir, "a")); err != nil {
			t.Fatal(err)
		}
	}()

	// check that this file _does_not_ show in the _target_
	if _, err := os.Stat(outside1CheckPath); err != nil && !os.IsNotExist(err) {
		t.Fatal(err)
	} else if err == nil {
		t.Fatalf("%q should not be visible, but is", outside1CheckPath)
	}

	// next mount outside2Dir into the _target_
	if err := Mount(outside2Dir, path.Join(targetDir, "b"), "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(path.Join(targetDir, "b")); err != nil {
			t.Fatal(err)
		}
	}()

	// check that this file _does_not_ show in the _source_
	if _, err := os.Stat(outside2CheckPath); err != nil && !os.IsNotExist(err) {
		t.Fatal(err)
	} else if err == nil {
		t.Fatalf("%q should not be visible, but is", outside2CheckPath)
	}
}

// Testing that when a target is a shared mount,
// then child mounts propagate to the source
func TestSubtreeShared(t *testing.T) {
	if os.Getuid() != 0 {
		t.Skip("root required")
	}

	tmp := path.Join(os.TempDir(), "mount-tests")
	if err := os.MkdirAll(tmp, 0777); err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmp)

	var (
		sourceDir  = path.Join(tmp, "source")
		targetDir  = path.Join(tmp, "target")
		outsideDir = path.Join(tmp, "outside")

		outsidePath     = path.Join(outsideDir, "file.txt")
		sourceCheckPath = path.Join(sourceDir, "a", "file.txt")
	)

	if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(targetDir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(outsideDir, 0777); err != nil {
		t.Fatal(err)
	}

	if err := createFile(outsidePath); err != nil {
		t.Fatal(err)
	}

	// mount the source as shared
	if err := MakeShared(sourceDir); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(sourceDir); err != nil {
			t.Fatal(err)
		}
	}()

	// mount the shared directory to a target
	if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()

	// mount in an outside path to a mounted path inside the target
	if err := Mount(outsideDir, path.Join(targetDir, "a"), "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(path.Join(targetDir, "a")); err != nil {
			t.Fatal(err)
		}
	}()

	// NOW, check that the file from the outside directory is available in the source directory
	if _, err := os.Stat(sourceCheckPath); err != nil {
		t.Fatal(err)
	}
}

// testing that mounts to a shared source show up in the slave target,
// and that mounts into a slave target do _not_ show up in the shared source
func TestSubtreeSharedSlave(t *testing.T) {
	if os.Getuid() != 0 {
		t.Skip("root required")
	}

	tmp := path.Join(os.TempDir(), "mount-tests")
	if err := os.MkdirAll(tmp, 0777); err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmp)

	var (
		sourceDir   = path.Join(tmp, "source")
		targetDir   = path.Join(tmp, "target")
		outside1Dir = path.Join(tmp, "outside1")
		outside2Dir = path.Join(tmp, "outside2")

		outside1Path      = path.Join(outside1Dir, "file.txt")
		outside2Path      = path.Join(outside2Dir, "file.txt")
		outside1CheckPath = path.Join(targetDir, "a", "file.txt")
		outside2CheckPath = path.Join(sourceDir, "b", "file.txt")
	)
	if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.MkdirAll(path.Join(sourceDir, "b"), 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(targetDir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(outside1Dir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.Mkdir(outside2Dir, 0777); err != nil {
		t.Fatal(err)
	}

	if err := createFile(outside1Path); err != nil {
		t.Fatal(err)
	}
	if err := createFile(outside2Path); err != nil {
		t.Fatal(err)
	}

	// mount the source as shared
	if err := MakeShared(sourceDir); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(sourceDir); err != nil {
			t.Fatal(err)
		}
	}()

	// mount the shared directory to a target
	if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()

	// next, make the target slave
	if err := MakeSlave(targetDir); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()

	// mount in an outside path to a mounted path inside the _source_
	if err := Mount(outside1Dir, path.Join(sourceDir, "a"), "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(path.Join(sourceDir, "a")); err != nil {
			t.Fatal(err)
		}
	}()

	// check that this file _does_ show in the _target_
	if _, err := os.Stat(outside1CheckPath); err != nil {
		t.Fatal(err)
	}

	// next mount outside2Dir into the _target_
	if err := Mount(outside2Dir, path.Join(targetDir, "b"), "none", "bind,rw"); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(path.Join(targetDir, "b")); err != nil {
			t.Fatal(err)
		}
	}()

	// check that this file _does_not_ show in the _source_
	if _, err := os.Stat(outside2CheckPath); err != nil && !os.IsNotExist(err) {
		t.Fatal(err)
	} else if err == nil {
		t.Fatalf("%q should not be visible, but is", outside2CheckPath)
	}
}

func TestSubtreeUnbindable(t *testing.T) {
	if os.Getuid() != 0 {
		t.Skip("root required")
	}

	tmp := path.Join(os.TempDir(), "mount-tests")
	if err := os.MkdirAll(tmp, 0777); err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmp)

	var (
		sourceDir = path.Join(tmp, "source")
		targetDir = path.Join(tmp, "target")
	)
	if err := os.MkdirAll(sourceDir, 0777); err != nil {
		t.Fatal(err)
	}
	if err := os.MkdirAll(targetDir, 0777); err != nil {
		t.Fatal(err)
	}

	// next, make the source unbindable
	if err := MakeUnbindable(sourceDir); err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := Unmount(sourceDir); err != nil {
			t.Fatal(err)
		}
	}()

	// then attempt to mount it to target. It should fail
	if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil && errors.Unwrap(err) != unix.EINVAL {
		t.Fatal(err)
	} else if err == nil {
		t.Fatalf("%q should not have been bindable", sourceDir)
	}
	defer func() {
		if err := Unmount(targetDir); err != nil {
			t.Fatal(err)
		}
	}()
}

func createFile(path string) error {
	f, err := os.Create(path)
	if err != nil {
		return err
	}
	f.WriteString("hello world!")
	return f.Close()
}
<|endoftext|>


<commit_before>package hypervisor

import (
	"net"
	"time"

	"github.com/Symantec/Dominator/lib/tags"
)

const (
	StateStarting      = 0
	StateRunning       = 1
	StateFailedToStart = 2
	StateStopping      = 3
	StateStopped       = 4
	StateDestroying    = 5
	StateMigrating     = 6

	VolumeFormatRaw   = 0
	VolumeFormatQCOW2 = 1
)

type AcknowledgeVmRequest struct {
	IpAddress net.IP
}

type AcknowledgeVmResponse struct {
	Error string
}

type Address struct {
	IpAddress  net.IP `json:",omitempty"`
	MacAddress string
}

type BecomePrimaryVmOwnerRequest struct {
	IpAddress net.IP
}

type BecomePrimaryVmOwnerResponse struct {
	Error string
}

type ChangeAddressPoolRequest struct {
	AddressesToAdd       []Address       // Will be added to free pool.
	AddressesToRemove    []Address       // Will be removed from free pool.
	MaximumFreeAddresses map[string]uint // Key: subnet ID.
}

type ChangeAddressPoolResponse struct {
	Error string
}

type ChangeOwnersRequest struct {
	OwnerGroups []string `json:",omitempty"`
	OwnerUsers  []string `json:",omitempty"`
}

type ChangeOwnersResponse struct {
	Error string
}

type ChangeVmDestroyProtectionRequest struct {
	DestroyProtection bool
	IpAddress         net.IP
}

type ChangeVmDestroyProtectionResponse struct {
	Error string
}

type ChangeVmOwnerUsersRequest struct {
	IpAddress  net.IP
	OwnerUsers []string
}

type ChangeVmOwnerUsersResponse struct {
	Error string
}

type ChangeVmTagsRequest struct {
	IpAddress net.IP
	Tags      tags.Tags
}

type ChangeVmTagsResponse struct {
	Error string
}

type CommitImportedVmRequest struct {
	IpAddress net.IP
}

type CommitImportedVmResponse struct {
	Error string
}

type CreateVmRequest struct {
	DhcpTimeout      time.Duration
	ImageDataSize    uint64
	ImageTimeout     time.Duration
	MinimumFreeBytes uint64
	RoundupPower     uint64
	SecondaryVolumes []Volume
	SkipBootloader   bool
	UserDataSize     uint64
	VmInfo
} // RAW image data (length=ImageDataSize) and user data (length=UserDataSize)
// are streamed afterwards.

type CreateVmResponse struct { // Multiple responses are sent.
	DhcpTimedOut    bool
	Final           bool // If true, this is the final response.
	IpAddress       net.IP
	ProgressMessage string
	Error           string
}

type DeleteVmVolumeRequest struct {
	AccessToken []byte
	IpAddress   net.IP
	VolumeIndex uint
}

type DeleteVmVolumeResponse struct {
	Error string
}

type DestroyVmRequest struct {
	AccessToken []byte
	IpAddress   net.IP
}

type DestroyVmResponse struct {
	Error string
}

type DiscardVmAccessTokenRequest struct {
	AccessToken []byte
	IpAddress   net.IP
}

type DiscardVmAccessTokenResponse struct {
	Error string
}

type DiscardVmOldImageRequest struct {
	IpAddress net.IP
}

type DiscardVmOldImageResponse struct {
	Error string
}

type DiscardVmOldUserDataRequest struct {
	IpAddress net.IP
}

type DiscardVmOldUserDataResponse struct {
	Error string
}

type DiscardVmSnapshotRequest struct {
	IpAddress net.IP
}

type DiscardVmSnapshotResponse struct {
	Error string
}

// The GetUpdates() RPC is fully streamed.
// The client may or may not send GetUpdateRequest messages to the server.
// The server sends a stream of Update messages.

type GetUpdateRequest struct{}

type Update struct {
	HaveAddressPool  bool               `json:",omitempty"`
	AddressPool      []Address          `json:",omitempty"` // Used & free.
	NumFreeAddresses map[string]uint    `json:",omitempty"` // Key: subnet ID.
	HealthStatus     string             `json:",omitempty"`
	HaveSerialNumber bool               `json:",omitempty"`
	SerialNumber     string             `json:",omitempty"`
	HaveSubnets      bool               `json:",omitempty"`
	Subnets          []Subnet           `json:",omitempty"`
	HaveVMs          bool               `json:",omitempty"`
	VMs              map[string]*VmInfo `json:",omitempty"` // Key: IP address.
}

type GetVmAccessTokenRequest struct {
	IpAddress net.IP
	Lifetime  time.Duration
}

type GetVmAccessTokenResponse struct {
	Token []byte `json:",omitempty"`
	Error string
}

type GetVmInfoRequest struct {
	IpAddress net.IP
}

type GetVmInfoResponse struct {
	VmInfo VmInfo
	Error  string
}

type GetVmUserDataRequest struct {
	AccessToken []byte
	IpAddress   net.IP
}

type GetVmUserDataResponse struct {
	Error  string
	Length uint64
} // Data (length=Length) are streamed afterwards.

// The GetVmVolume() RPC is followed by the proto/rsync.GetBlocks message.

type GetVmVolumeRequest struct {
	AccessToken []byte
	IpAddress   net.IP
	VolumeIndex uint
}

type GetVmVolumeResponse struct {
	Error string
}

type ImportLocalVmRequest struct {
	VerificationCookie []byte `json:",omitempty"`
	VmInfo
	VolumeFilenames []string
}

type ImportLocalVmResponse struct {
	Error string
}

type ListVMsRequest struct {
	Sort bool
}

type ListVMsResponse struct {
	IpAddresses []net.IP
}

type ListVolumeDirectoriesRequest struct{}

type ListVolumeDirectoriesResponse struct {
	Directories []string
	Error       string
}

type MigrateVmRequest struct {
	AccessToken      []byte
	DhcpTimeout      time.Duration
	IpAddress        net.IP
	SourceHypervisor string
}

type MigrateVmResponse struct { // Multiple responses are sent.
	Error           string
	Final           bool // If true, this is the final response.
	ProgressMessage string
	RequestCommit   bool
}

type MigrateVmResponseResponse struct {
	Commit bool
}

type NetbootMachineRequest struct {
	Address                      Address
	Files                        map[string][]byte
	FilesExpiration              time.Duration
	Hostname                     string
	NumAcknowledgementsToWaitFor uint
	OfferExpiration              time.Duration
	Subnet                       *Subnet
	WaitTimeout                  time.Duration
}

type NetbootMachineResponse struct {
	Error string
}

type PrepareVmForMigrationRequest struct {
	AccessToken []byte
	Enable      bool
	IpAddress   net.IP
}

type PrepareVmForMigrationResponse struct {
	Error string
}

type ProbeVmPortRequest struct {
	IpAddress  net.IP
	PortNumber uint
	Timeout    time.Duration
}

type ProbeVmPortResponse struct {
	PortIsOpen bool
	Error      string
}

type ReplaceVmImageRequest struct {
	DhcpTimeout      time.Duration
	ImageDataSize    uint64
	ImageName        string `json:",omitempty"`
	ImageTimeout     time.Duration
	ImageURL         string `json:",omitempty"`
	IpAddress        net.IP
	MinimumFreeBytes uint64
	RoundupPower     uint64
	SkipBootloader   bool
} // RAW image data (length=ImageDataSize) is streamed afterwards.

type ReplaceVmImageResponse struct { // Multiple responses are sent.
	DhcpTimedOut    bool
	Final           bool // If true, this is the final response.
	ProgressMessage string
	Error           string
}

type ReplaceVmUserDataRequest struct {
	IpAddress net.IP
	Size      uint64
} // User data (length=Size) are streamed afterwards.

type ReplaceVmUserDataResponse struct {
	Error string
}

type RestoreVmFromSnapshotRequest struct {
	IpAddress         net.IP
	ForceIfNotStopped bool
}

type RestoreVmFromSnapshotResponse struct {
	Error string
}

type RestoreVmImageRequest struct {
	IpAddress net.IP
}

type RestoreVmImageResponse struct {
	Error string
}

type RestoreVmUserDataRequest struct {
	IpAddress net.IP
}

type RestoreVmUserDataResponse struct {
	Error string
}

type SnapshotVmRequest struct {
	IpAddress         net.IP
	ForceIfNotStopped bool
	RootOnly          bool
}

type SnapshotVmResponse struct {
	Error string
}

type StartVmRequest struct {
	AccessToken []byte
	DhcpTimeout time.Duration
	IpAddress   net.IP
}

type StartVmResponse struct {
	DhcpTimedOut bool
	Error        string
}

type StopVmRequest struct {
	AccessToken []byte
	IpAddress   net.IP
}

type StopVmResponse struct {
	Error string
}

type State uint

type Subnet struct {
	Id                string
	IpGateway         net.IP
	IpMask            net.IP // net.IPMask can't be JSON {en,de}coded.
	DomainName        string `json:",omitempty"`
	DomainNameServers []net.IP
	Manage            bool     `json:",omitempty"`
	VlanId            uint     `json:",omitempty"`
	AllowedGroups     []string `json:",omitempty"`
	AllowedUsers      []string `json:",omitempty"`
}

type TraceVmMetadataRequest struct {
	IpAddress net.IP
}

type TraceVmMetadataResponse struct {
	Error string
} // A stream of strings (trace paths) follow.

type UpdateSubnetsRequest struct {
	Add    []Subnet
	Change []Subnet
	Delete []string
}

type UpdateSubnetsResponse struct {
	Error string
}

type VmInfo struct {
	Address            Address
	DestroyProtection  bool   `json:",omitempty"`
	Hostname           string `json:",omitempty"`
	ImageName          string `json:",omitempty"`
	ImageURL           string `json:",omitempty"`
	MemoryInMiB        uint64
	MilliCPUs          uint
	OwnerGroups        []string `json:",omitempty"`
	OwnerUsers         []string `json:",omitempty"`
	SpreadVolumes      bool     `json:",omitempty"`
	State              State
	Tags               tags.Tags `json:",omitempty"`
	SecondaryAddresses []Address `json:",omitempty"`
	SecondarySubnetIDs []string  `json:",omitempty"`
	SubnetId           string    `json:",omitempty"`
	Uncommitted        bool      `json:",omitempty"`
	Volumes            []Volume  `json:",omitempty"`
}

type Volume struct {
	Size   uint64
	Format VolumeFormat
}

type VolumeFormat uint
<commit_msg>Add proto/hypervisor.CopyVm messages.<commit_after>package hypervisor

import (
	"net"
	"time"

	"github.com/Symantec/Dominator/lib/tags"
)

const (
	StateStarting      = 0
	StateRunning       = 1
	StateFailedToStart = 2
	StateStopping      = 3
	StateStopped       = 4
	StateDestroying    = 5
	StateMigrating     = 6

	VolumeFormatRaw   = 0
	VolumeFormatQCOW2 = 1
)

type AcknowledgeVmRequest struct {
	IpAddress net.IP
}

type AcknowledgeVmResponse struct {
	Error string
}

type Address struct {
	IpAddress  net.IP `json:",omitempty"`
	MacAddress string
}

type BecomePrimaryVmOwnerRequest struct {
	IpAddress net.IP
}

type BecomePrimaryVmOwnerResponse struct {
	Error string
}

type ChangeAddressPoolRequest struct {
	AddressesToAdd       []Address       // Will be added to free pool.
	AddressesToRemove    []Address       // Will be removed from free pool.
	MaximumFreeAddresses map[string]uint // Key: subnet ID.
}

type ChangeAddressPoolResponse struct {
	Error string
}

type ChangeOwnersRequest struct {
	OwnerGroups []string `json:",omitempty"`
	OwnerUsers  []string `json:",omitempty"`
}

type ChangeOwnersResponse struct {
	Error string
}

type ChangeVmDestroyProtectionRequest struct {
	DestroyProtection bool
	IpAddress         net.IP
}

type ChangeVmDestroyProtectionResponse struct {
	Error string
}

type ChangeVmOwnerUsersRequest struct {
	IpAddress  net.IP
	OwnerUsers []string
}

type ChangeVmOwnerUsersResponse struct {
	Error string
}

type ChangeVmTagsRequest struct {
	IpAddress net.IP
	Tags      tags.Tags
}

type ChangeVmTagsResponse struct {
	Error string
}

type CommitImportedVmRequest struct {
	IpAddress net.IP
}

type CommitImportedVmResponse struct {
	Error string
}

type CopyVmRequest struct {
	AccessToken      []byte
	DhcpTimeout      time.Duration
	IpAddress        net.IP
	SourceHypervisor string
}

type CopyVmResponse struct { // Multiple responses are sent.
	DhcpTimedOut    bool
	Error           string
	Final           bool // If true, this is the final response.
	IpAddress       net.IP
	ProgressMessage string
}

type CreateVmRequest struct {
	DhcpTimeout      time.Duration
	ImageDataSize    uint64
	ImageTimeout     time.Duration
	MinimumFreeBytes uint64
	RoundupPower     uint64
	SecondaryVolumes []Volume
	SkipBootloader   bool
	UserDataSize     uint64
	VmInfo
} // RAW image data (length=ImageDataSize) and user data (length=UserDataSize)
// are streamed afterwards.

type CreateVmResponse struct { // Multiple responses are sent.
	DhcpTimedOut    bool
	Final           bool // If true, this is the final response.
	IpAddress       net.IP
	ProgressMessage string
	Error           string
}

type DeleteVmVolumeRequest struct {
	AccessToken []byte
	IpAddress   net.IP
	VolumeIndex uint
}

type DeleteVmVolumeResponse struct {
	Error string
}

type DestroyVmRequest struct {
	AccessToken []byte
	IpAddress   net.IP
}

type DestroyVmResponse struct {
	Error string
}

type DiscardVmAccessTokenRequest struct {
	AccessToken []byte
	IpAddress   net.IP
}

type DiscardVmAccessTokenResponse struct {
	Error string
}

type DiscardVmOldImageRequest struct {
	IpAddress net.IP
}

type DiscardVmOldImageResponse struct {
	Error string
}

type DiscardVmOldUserDataRequest struct {
	IpAddress net.IP
}

type DiscardVmOldUserDataResponse struct {
	Error string
}

type DiscardVmSnapshotRequest struct {
	IpAddress net.IP
}

type DiscardVmSnapshotResponse struct {
	Error string
}

// The GetUpdates() RPC is fully streamed.
// The client may or may not send GetUpdateRequest messages to the server.
// The server sends a stream of Update messages.

type GetUpdateRequest struct{}

type Update struct {
	HaveAddressPool  bool               `json:",omitempty"`
	AddressPool      []Address          `json:",omitempty"` // Used & free.
	NumFreeAddresses map[string]uint    `json:",omitempty"` // Key: subnet ID.
	HealthStatus     string             `json:",omitempty"`
	HaveSerialNumber bool               `json:",omitempty"`
	SerialNumber     string             `json:",omitempty"`
	HaveSubnets      bool               `json:",omitempty"`
	Subnets          []Subnet           `json:",omitempty"`
	HaveVMs          bool               `json:",omitempty"`
	VMs              map[string]*VmInfo `json:",omitempty"` // Key: IP address.
}

type GetVmAccessTokenRequest struct {
	IpAddress net.IP
	Lifetime  time.Duration
}

type GetVmAccessTokenResponse struct {
	Token []byte `json:",omitempty"`
	Error string
}

type GetVmInfoRequest struct {
	IpAddress net.IP
}

type GetVmInfoResponse struct {
	VmInfo VmInfo
	Error  string
}

type GetVmUserDataRequest struct {
	AccessToken []byte
	IpAddress   net.IP
}

type GetVmUserDataResponse struct {
	Error  string
	Length uint64
} // Data (length=Length) are streamed afterwards.

// The GetVmVolume() RPC is followed by the proto/rsync.GetBlocks message.

type GetVmVolumeRequest struct {
	AccessToken []byte
	IpAddress   net.IP
	VolumeIndex uint
}

type GetVmVolumeResponse struct {
	Error string
}

type ImportLocalVmRequest struct {
	VerificationCookie []byte `json:",omitempty"`
	VmInfo
	VolumeFilenames []string
}

type ImportLocalVmResponse struct {
	Error string
}

type ListVMsRequest struct {
	Sort bool
}

type ListVMsResponse struct {
	IpAddresses []net.IP
}

type ListVolumeDirectoriesRequest struct{}

type ListVolumeDirectoriesResponse struct {
	Directories []string
	Error       string
}

type MigrateVmRequest struct {
	AccessToken      []byte
	DhcpTimeout      time.Duration
	IpAddress        net.IP
	SourceHypervisor string
}

type MigrateVmResponse struct { // Multiple responses are sent.
	Error           string
	Final           bool // If true, this is the final response.
	ProgressMessage string
	RequestCommit   bool
}

type MigrateVmResponseResponse struct {
	Commit bool
}

type NetbootMachineRequest struct {
	Address                      Address
	Files                        map[string][]byte
	FilesExpiration              time.Duration
	Hostname                     string
	NumAcknowledgementsToWaitFor uint
	OfferExpiration              time.Duration
	Subnet                       *Subnet
	WaitTimeout                  time.Duration
}

type NetbootMachineResponse struct {
	Error string
}

type PrepareVmForMigrationRequest struct {
	AccessToken []byte
	Enable      bool
	IpAddress   net.IP
}

type PrepareVmForMigrationResponse struct {
	Error string
}

type ProbeVmPortRequest struct {
	IpAddress  net.IP
	PortNumber uint
	Timeout    time.Duration
}

type ProbeVmPortResponse struct {
	PortIsOpen bool
	Error      string
}

type ReplaceVmImageRequest struct {
	DhcpTimeout      time.Duration
	ImageDataSize    uint64
	ImageName        string `json:",omitempty"`
	ImageTimeout     time.Duration
	ImageURL         string `json:",omitempty"`
	IpAddress        net.IP
	MinimumFreeBytes uint64
	RoundupPower     uint64
	SkipBootloader   bool
} // RAW image data (length=ImageDataSize) is streamed afterwards.

type ReplaceVmImageResponse struct { // Multiple responses are sent.
	DhcpTimedOut    bool
	Final           bool // If true, this is the final response.
	ProgressMessage string
	Error           string
}

type ReplaceVmUserDataRequest struct {
	IpAddress net.IP
	Size      uint64
} // User data (length=Size) are streamed afterwards.

type ReplaceVmUserDataResponse struct {
	Error string
}

type RestoreVmFromSnapshotRequest struct {
	IpAddress         net.IP
	ForceIfNotStopped bool
}

type RestoreVmFromSnapshotResponse struct {
	Error string
}

type RestoreVmImageRequest struct {
	IpAddress net.IP
}

type RestoreVmImageResponse struct {
	Error string
}

type RestoreVmUserDataRequest struct {
	IpAddress net.IP
}

type RestoreVmUserDataResponse struct {
	Error string
}

type SnapshotVmRequest struct {
	IpAddress         net.IP
	ForceIfNotStopped bool
	RootOnly          bool
}

type SnapshotVmResponse struct {
	Error string
}

type StartVmRequest struct {
	AccessToken []byte
	DhcpTimeout time.Duration
	IpAddress   net.IP
}

type StartVmResponse struct {
	DhcpTimedOut bool
	Error        string
}

type StopVmRequest struct {
	AccessToken []byte
	IpAddress   net.IP
}

type StopVmResponse struct {
	Error string
}

type State uint

type Subnet struct {
	Id                string
	IpGateway         net.IP
	IpMask            net.IP // net.IPMask can't be JSON {en,de}coded.
	DomainName        string `json:",omitempty"`
	DomainNameServers []net.IP
	Manage            bool     `json:",omitempty"`
	VlanId            uint     `json:",omitempty"`
	AllowedGroups     []string `json:",omitempty"`
	AllowedUsers      []string `json:",omitempty"`
}

type TraceVmMetadataRequest struct {
	IpAddress net.IP
}

type TraceVmMetadataResponse struct {
	Error string
} // A stream of strings (trace paths) follow.

type UpdateSubnetsRequest struct {
	Add    []Subnet
	Change []Subnet
	Delete []string
}

type UpdateSubnetsResponse struct {
	Error string
}

type VmInfo struct {
	Address            Address
	DestroyProtection  bool   `json:",omitempty"`
	Hostname           string `json:",omitempty"`
	ImageName          string `json:",omitempty"`
	ImageURL           string `json:",omitempty"`
	MemoryInMiB        uint64
	MilliCPUs          uint
	OwnerGroups        []string `json:",omitempty"`
	OwnerUsers         []string `json:",omitempty"`
	SpreadVolumes      bool     `json:",omitempty"`
	State              State
	Tags               tags.Tags `json:",omitempty"`
	SecondaryAddresses []Address `json:",omitempty"`
	SecondarySubnetIDs []string  `json:",omitempty"`
	SubnetId           string    `json:",omitempty"`
	Uncommitted        bool      `json:",omitempty"`
	Volumes            []Volume  `json:",omitempty"`
}

type Volume struct {
	Size   uint64
	Format VolumeFormat
}

type VolumeFormat uint
<|endoftext|>


<commit_before>package main

import (
	"errors"
	flapjack "github.com/flapjack/flapjack/src/flapjack"
	Url "net/url"
	"strconv"
)

func NotifyFlapjackRedis(nc *NotifierConf) func(*Log) {

	return func(l *Log) {

		Hurl, err := Url.Parse(l.Monitor.Conf.Url)
		if err != nil {
			errors.New("Unable to parse " + l.Monitor.Conf.Url)
			return
		}

		duration := " [" + strconv.FormatInt(l.Duration/1000000, 10) + "ms]"

		event := flapjack.Event{
			Entity:  Hurl.Host,
			Check:   l.Monitor.Conf.Name,
			State:   NewState(l),
			Summary: l.Message + duration,
			Type:    "service",
			Time:    l.Time.Unix(),
		}

		address := nc.Address
		database := 0 //production
		transport, err := flapjack.Dial(address, database)

		if err != nil {
			errors.New("Unable to connect to redis")
			return
		}

		transport.Send(event)

	}

}

func NewState(l *Log) string {
	ns := "critical"
	if l.Up {
		ns = "ok"
	}
	return ns
}
<commit_msg>error out if can't connect to flapjack redis<commit_after>package main

import (
	flapjack "github.com/flapjack/flapjack/src/flapjack"
	"log"
	Url "net/url"
	"strconv"
)

func NotifyFlapjackRedis(nc *NotifierConf) func(*Log) {

	return func(l *Log) {

		Hurl, err := Url.Parse(l.Monitor.Conf.Url)
		if err != nil {
			log.Printf("Flapjack Notifier: Unable to parse %s", l.Monitor.Conf.Url)
			return
		}

		duration := " [" + strconv.FormatInt(l.Duration/1000000, 10) + "ms]"

		event := flapjack.Event{
			Entity:  Hurl.Host,
			Check:   l.Monitor.Conf.Name,
			State:   NewState(l),
			Summary: l.Message + duration,
			Type:    "service",
			Time:    l.Time.Unix(),
		}

		address := nc.Address
		database := 0 //production
		transport, err := flapjack.Dial(address, database)

		if err != nil {
			log.Printf("FlapjackNotifier: unable to connect to redis %s", address)
			return
		}

		transport.Send(event)

	}

}

func NewState(l *Log) string {
	ns := "critical"
	if l.Up {
		ns = "ok"
	}
	return ns
}
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package common

import (
	"fmt"
	"io"
	"net"
	"os"
	"os/signal"
	"sync"
	"time"

	"launchpad.net/loggo"
	"launchpad.net/tomb"

	coreCloudinit "launchpad.net/juju-core/cloudinit"
	"launchpad.net/juju-core/cloudinit/sshinit"
	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/bootstrap"
	"launchpad.net/juju-core/environs/cloudinit"
	"launchpad.net/juju-core/instance"
	coretools "launchpad.net/juju-core/tools"
)

var logger = loggo.GetLogger("juju.provider.common")

// Bootstrap is a common implementation of the Bootstrap method defined on
// environs.Environ; we strongly recommend that this implementation be used
// when writing a new provider.
func Bootstrap(env environs.Environ, cons constraints.Value) (err error) {
	// TODO make safe in the case of racing Bootstraps
	// If two Bootstraps are called concurrently, there's
	// no way to make sure that only one succeeds.

	// TODO(axw) 2013-11-22 #1237736
	// Modify environs/Environ Bootstrap method signature
	// to take a new context structure, which contains
	// Std{in,out,err}, and interrupt signal handling.
	ctx := BootstrapContext{Stderr: os.Stderr}

	var inst instance.Instance
	defer func() { handleBootstrapError(err, &ctx, inst, env) }()

	// Create an empty bootstrap state file so we can get its URL.
	// It will be updated with the instance id and hardware characteristics
	// after the bootstrap instance is started.
	stateFileURL, err := bootstrap.CreateStateFile(env.Storage())
	if err != nil {
		return err
	}
	machineConfig := environs.NewBootstrapMachineConfig(stateFileURL)

	selectedTools, err := EnsureBootstrapTools(env, env.Config().DefaultSeries(), cons.Arch)
	if err != nil {
		return err
	}

	fmt.Fprintln(ctx.Stderr, "Launching instance")
	inst, hw, err := env.StartInstance(cons, selectedTools, machineConfig)
	if err != nil {
		return fmt.Errorf("cannot start bootstrap instance: %v", err)
	}
	fmt.Fprintf(ctx.Stderr, " - %s\n", inst.Id())

	var characteristics []instance.HardwareCharacteristics
	if hw != nil {
		characteristics = []instance.HardwareCharacteristics{*hw}
	}
	err = bootstrap.SaveState(
		env.Storage(),
		&bootstrap.BootstrapState{
			StateInstances:  []instance.Id{inst.Id()},
			Characteristics: characteristics,
		})
	if err != nil {
		return fmt.Errorf("cannot save state: %v", err)
	}
	return FinishBootstrap(&ctx, inst, machineConfig)
}

// handelBootstrapError cleans up after a failed bootstrap.
func handleBootstrapError(err error, ctx *BootstrapContext, inst instance.Instance, env environs.Environ) {
	if err == nil {
		return
	}
	logger.Errorf("bootstrap failed: %v", err)
	ctx.SetInterruptHandler(func() {
		fmt.Fprintln(ctx.Stderr, "Cleaning up failed bootstrap")
	})
	if inst != nil {
		fmt.Fprintln(ctx.Stderr, "Stopping instance...")
		if stoperr := env.StopInstances([]instance.Instance{inst}); stoperr != nil {
			logger.Errorf("cannot stop failed bootstrap instance %q: %v", inst.Id(), stoperr)
		} else {
			// set to nil so we know we can safely delete the state file
			inst = nil
		}
	}
	// We only delete the bootstrap state file if either we didn't
	// start an instance, or we managed to cleanly stop it.
	if inst == nil {
		if rmerr := bootstrap.DeleteStateFile(env.Storage()); rmerr != nil {
			logger.Errorf("cannot delete bootstrap state file: %v", rmerr)
		}
	}
	ctx.SetInterruptHandler(nil)
}

// FinishBootstrap completes the bootstrap process by connecting
// to the instance via SSH and carrying out the cloud-config.
//
// Note: FinishBootstrap is exposed so it can be replaced for testing.
var FinishBootstrap = func(ctx *BootstrapContext, inst instance.Instance, machineConfig *cloudinit.MachineConfig) error {
	var t tomb.Tomb
	ctx.SetInterruptHandler(func() { t.Killf("interrupted") })
	// TODO: jam 2013-12-04 bug #1257649
	// It would be nice if users had some controll over their bootstrap
	// timeout, since it is unlikely to be a perfect match for all clouds.
	dnsName, err := waitSSH(ctx, inst, &t, DefaultBootstrapSSHTimeout())
	if err != nil {
		return err
	}
	// Bootstrap is synchronous, and will spawn a subprocess
	// to complete the procedure. If the user hits Ctrl-C,
	// SIGINT is sent to the foreground process attached to
	// the terminal, which will be the ssh subprocess at that
	// point.
	ctx.SetInterruptHandler(func() {})
	cloudcfg := coreCloudinit.New()
	if err := cloudinit.ConfigureJuju(machineConfig, cloudcfg); err != nil {
		return err
	}
	return sshinit.Configure("ubuntu@"+dnsName, cloudcfg)
}

// SSHTimeoutOpts lists the amount of time we will wait for various parts of
// the SSH connection to complete. This is similar to DialOpts, see
// http://pad.lv/1258889 about possibly deduplicating them.
type SSHTimeoutOpts struct {
	// Timeout is the amount of time to wait contacting
	// a state server.
	Timeout time.Duration

	// DNSNameDelay is the amount of time between refreshing the DNS name
	DNSNameDelay time.Duration
}

// DefaultBootstrapSSHTimeout is the time we'll wait for SSH to come up on the bootstrap node
func DefaultBootstrapSSHTimeout() SSHTimeoutOpts {
	return SSHTimeoutOpts{
		Timeout:      10 * time.Minute,
		DNSNameDelay: 1 * time.Second,
	}
}

type dnsNamer interface {
	// DNSName returns the DNS name for the instance.
	// If the name is not yet allocated, it will return
	// an ErrNoDNSName error.
	DNSName() (string, error)
}

// waitSSH waits for the instance to be assigned a DNS
// entry, then waits until we can connect to it via SSH.
func waitSSH(ctx *BootstrapContext, inst dnsNamer, t *tomb.Tomb, timeout SSHTimeoutOpts) (dnsName string, err error) {
	defer t.Done()
	globalTimeout := time.After(timeout.Timeout)
	pollDNS := time.NewTimer(0)
	fmt.Fprintln(ctx.Stderr, "Waiting for DNS name")
	var dialResultChan chan error
	for {
		if dnsName != "" && dialResultChan == nil {
			addr := dnsName + ":22"
			fmt.Fprintf(ctx.Stderr, "Attempting to connect to %s\n", addr)
			dialResultChan = make(chan error, 1)
			go func() {
				c, err := net.Dial("tcp", addr)
				if err == nil {
					c.Close()
				}
				dialResultChan <- err
			}()
		}
		select {
		case <-pollDNS.C:
			pollDNS.Reset(timeout.DNSNameDelay)
			var newDNSName string
			newDNSName, dnsNameErr := inst.DNSName()
			if dnsNameErr != nil && dnsNameErr != instance.ErrNoDNSName {
				return "", t.Killf("getting DNS name: %v", dnsNameErr)
			} else if dnsNameErr != nil {
				err = dnsNameErr
			} else if newDNSName != dnsName {
				dnsName = newDNSName
				dialResultChan = nil
			}
		case err = <-dialResultChan:
			if err == nil {
				return dnsName, nil
			}
			logger.Debugf("connection failed: %v", err)
			dialResultChan = nil // retry
		case <-globalTimeout:
			format := "waited for %s "
			args := []interface{}{timeout.Timeout}
			if dnsName == "" {
				format += "without getting a DNS name"
			} else {
				format += "without being able to connect to %q"
				args = append(args, dnsName)
			}
			if err != nil {
				format += ": %s"
				args = append(args, err)
			}
			return "", t.Killf(format, args...)
		case <-t.Dying():
			return "", t.Err()
		}
	}
}

// TODO(axw) move this to environs; see
// comment near the top of common.Bootstrap.
type BootstrapContext struct {
	once        sync.Once
	handlerchan chan func()

	Stderr io.Writer
}

func (ctx *BootstrapContext) SetInterruptHandler(f func()) {
	ctx.once.Do(ctx.initHandler)
	ctx.handlerchan <- f
}

func (ctx *BootstrapContext) initHandler() {
	ctx.handlerchan = make(chan func())
	go ctx.handleInterrupt()
}

func (ctx *BootstrapContext) handleInterrupt() {
	signalchan := make(chan os.Signal, 1)
	var s chan os.Signal
	var handler func()
	for {
		select {
		case handler = <-ctx.handlerchan:
			if handler == nil {
				if s != nil {
					signal.Stop(signalchan)
					s = nil
				}
			} else {
				if s == nil {
					s = signalchan
					signal.Notify(signalchan, os.Interrupt)
				}
			}
		case <-s:
			handler()
		}
	}
}

// EnsureBootstrapTools finds tools, syncing with an external tools source as
// necessary; it then selects the newest tools to bootstrap with, and sets
// agent-version.
func EnsureBootstrapTools(env environs.Environ, series string, arch *string) (coretools.List, error) {
	possibleTools, err := bootstrap.EnsureToolsAvailability(env, series, arch)
	if err != nil {
		return nil, err
	}
	return bootstrap.SetBootstrapTools(env, possibleTools)
}

// EnsureNotBootstrapped returns null if the environment is not bootstrapped,
// and an error if it is or if the function was not able to tell.
func EnsureNotBootstrapped(env environs.Environ) error {
	_, err := bootstrap.LoadState(env.Storage())
	// If there is no error loading the bootstrap state, then we are
	// bootstrapped.
	if err == nil {
		return fmt.Errorf("environment is already bootstrapped")
	}
	if err == environs.ErrNotBootstrapped {
		return nil
	}
	return err
}
<commit_msg>Address review comments<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package common

import (
	"fmt"
	"io"
	"net"
	"os"
	"os/signal"
	"sync"
	"time"

	"launchpad.net/loggo"
	"launchpad.net/tomb"

	coreCloudinit "launchpad.net/juju-core/cloudinit"
	"launchpad.net/juju-core/cloudinit/sshinit"
	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/bootstrap"
	"launchpad.net/juju-core/environs/cloudinit"
	"launchpad.net/juju-core/instance"
	coretools "launchpad.net/juju-core/tools"
)

var logger = loggo.GetLogger("juju.provider.common")

// Bootstrap is a common implementation of the Bootstrap method defined on
// environs.Environ; we strongly recommend that this implementation be used
// when writing a new provider.
func Bootstrap(env environs.Environ, cons constraints.Value) (err error) {
	// TODO make safe in the case of racing Bootstraps
	// If two Bootstraps are called concurrently, there's
	// no way to make sure that only one succeeds.

	// TODO(axw) 2013-11-22 #1237736
	// Modify environs/Environ Bootstrap method signature
	// to take a new context structure, which contains
	// Std{in,out,err}, and interrupt signal handling.
	ctx := BootstrapContext{Stderr: os.Stderr}

	var inst instance.Instance
	defer func() { handleBootstrapError(err, &ctx, inst, env) }()

	// Create an empty bootstrap state file so we can get its URL.
	// It will be updated with the instance id and hardware characteristics
	// after the bootstrap instance is started.
	stateFileURL, err := bootstrap.CreateStateFile(env.Storage())
	if err != nil {
		return err
	}
	machineConfig := environs.NewBootstrapMachineConfig(stateFileURL)

	selectedTools, err := EnsureBootstrapTools(env, env.Config().DefaultSeries(), cons.Arch)
	if err != nil {
		return err
	}

	fmt.Fprintln(ctx.Stderr, "Launching instance")
	inst, hw, err := env.StartInstance(cons, selectedTools, machineConfig)
	if err != nil {
		return fmt.Errorf("cannot start bootstrap instance: %v", err)
	}
	fmt.Fprintf(ctx.Stderr, " - %s\n", inst.Id())

	var characteristics []instance.HardwareCharacteristics
	if hw != nil {
		characteristics = []instance.HardwareCharacteristics{*hw}
	}
	err = bootstrap.SaveState(
		env.Storage(),
		&bootstrap.BootstrapState{
			StateInstances:  []instance.Id{inst.Id()},
			Characteristics: characteristics,
		})
	if err != nil {
		return fmt.Errorf("cannot save state: %v", err)
	}
	return FinishBootstrap(&ctx, inst, machineConfig)
}

// handelBootstrapError cleans up after a failed bootstrap.
func handleBootstrapError(err error, ctx *BootstrapContext, inst instance.Instance, env environs.Environ) {
	if err == nil {
		return
	}
	logger.Errorf("bootstrap failed: %v", err)
	ctx.SetInterruptHandler(func() {
		fmt.Fprintln(ctx.Stderr, "Cleaning up failed bootstrap")
	})
	if inst != nil {
		fmt.Fprintln(ctx.Stderr, "Stopping instance...")
		if stoperr := env.StopInstances([]instance.Instance{inst}); stoperr != nil {
			logger.Errorf("cannot stop failed bootstrap instance %q: %v", inst.Id(), stoperr)
		} else {
			// set to nil so we know we can safely delete the state file
			inst = nil
		}
	}
	// We only delete the bootstrap state file if either we didn't
	// start an instance, or we managed to cleanly stop it.
	if inst == nil {
		if rmerr := bootstrap.DeleteStateFile(env.Storage()); rmerr != nil {
			logger.Errorf("cannot delete bootstrap state file: %v", rmerr)
		}
	}
	ctx.SetInterruptHandler(nil)
}

// FinishBootstrap completes the bootstrap process by connecting
// to the instance via SSH and carrying out the cloud-config.
//
// Note: FinishBootstrap is exposed so it can be replaced for testing.
var FinishBootstrap = func(ctx *BootstrapContext, inst instance.Instance, machineConfig *cloudinit.MachineConfig) error {
	var t tomb.Tomb
	ctx.SetInterruptHandler(func() { t.Killf("interrupted") })
	// TODO: jam 2013-12-04 bug #1257649
	// It would be nice if users had some controll over their bootstrap
	// timeout, since it is unlikely to be a perfect match for all clouds.
	dnsName, err := waitSSH(ctx, inst, &t, DefaultBootstrapSSHTimeout())
	if err != nil {
		return err
	}
	// Bootstrap is synchronous, and will spawn a subprocess
	// to complete the procedure. If the user hits Ctrl-C,
	// SIGINT is sent to the foreground process attached to
	// the terminal, which will be the ssh subprocess at that
	// point.
	ctx.SetInterruptHandler(func() {})
	cloudcfg := coreCloudinit.New()
	if err := cloudinit.ConfigureJuju(machineConfig, cloudcfg); err != nil {
		return err
	}
	return sshinit.Configure("ubuntu@"+dnsName, cloudcfg)
}

// SSHTimeoutOpts lists the amount of time we will wait for various parts of
// the SSH connection to complete. This is similar to DialOpts, see
// http://pad.lv/1258889 about possibly deduplicating them.
type SSHTimeoutOpts struct {
	// Timeout is the amount of time to wait contacting
	// a state server.
	Timeout time.Duration

	// DNSNameDelay is the amount of time between refreshing the DNS name
	DNSNameDelay time.Duration
}

// DefaultBootstrapSSHTimeout is the time we'll wait for SSH to come up on the bootstrap node
func DefaultBootstrapSSHTimeout() SSHTimeoutOpts {
	return SSHTimeoutOpts{
		Timeout:      10 * time.Minute,
		DNSNameDelay: 1 * time.Second,
	}
}

type dnsNamer interface {
	// DNSName returns the DNS name for the instance.
	// If the name is not yet allocated, it will return
	// an ErrNoDNSName error.
	DNSName() (string, error)
}

// waitSSH waits for the instance to be assigned a DNS
// entry, then waits until we can connect to it via SSH.
func waitSSH(ctx *BootstrapContext, inst dnsNamer, t *tomb.Tomb, timeout SSHTimeoutOpts) (dnsName string, err error) {
	defer t.Done()
	globalTimeout := time.After(timeout.Timeout)
	pollDNS := time.NewTimer(0)
	fmt.Fprintln(ctx.Stderr, "Waiting for DNS name")
	var dialResultChan chan error
	var lastErr error
	for {
		if dnsName != "" && dialResultChan == nil {
			addr := dnsName + ":22"
			fmt.Fprintf(ctx.Stderr, "Attempting to connect to %s\n", addr)
			dialResultChan = make(chan error, 1)
			go func() {
				c, err := net.Dial("tcp", addr)
				if err == nil {
					c.Close()
				}
				dialResultChan <- err
			}()
		}
		select {
		case <-pollDNS.C:
			pollDNS.Reset(timeout.DNSNameDelay)
			newDNSName, err := inst.DNSName()
			if err != nil && err != instance.ErrNoDNSName {
				return "", t.Killf("getting DNS name: %v", err)
			} else if err != nil {
				lastErr = err
			} else if newDNSName != dnsName {
				dnsName = newDNSName
				dialResultChan = nil
			}
		case lastErr = <-dialResultChan:
			if lastErr == nil {
				return dnsName, nil
			}
			logger.Debugf("connection failed: %v", lastErr)
			dialResultChan = nil // retry
		case <-globalTimeout:
			format := "waited for %v "
			args := []interface{}{timeout.Timeout}
			if dnsName == "" {
				format += "without getting a DNS name"
			} else {
				format += "without being able to connect to %q"
				args = append(args, dnsName)
			}
			if lastErr != nil {
				format += ": %v"
				args = append(args, lastErr)
			}
			return "", t.Killf(format, args...)
		case <-t.Dying():
			return "", t.Err()
		}
	}
}

// TODO(axw) move this to environs; see
// comment near the top of common.Bootstrap.
type BootstrapContext struct {
	once        sync.Once
	handlerchan chan func()

	Stderr io.Writer
}

func (ctx *BootstrapContext) SetInterruptHandler(f func()) {
	ctx.once.Do(ctx.initHandler)
	ctx.handlerchan <- f
}

func (ctx *BootstrapContext) initHandler() {
	ctx.handlerchan = make(chan func())
	go ctx.handleInterrupt()
}

func (ctx *BootstrapContext) handleInterrupt() {
	signalchan := make(chan os.Signal, 1)
	var s chan os.Signal
	var handler func()
	for {
		select {
		case handler = <-ctx.handlerchan:
			if handler == nil {
				if s != nil {
					signal.Stop(signalchan)
					s = nil
				}
			} else {
				if s == nil {
					s = signalchan
					signal.Notify(signalchan, os.Interrupt)
				}
			}
		case <-s:
			handler()
		}
	}
}

// EnsureBootstrapTools finds tools, syncing with an external tools source as
// necessary; it then selects the newest tools to bootstrap with, and sets
// agent-version.
func EnsureBootstrapTools(env environs.Environ, series string, arch *string) (coretools.List, error) {
	possibleTools, err := bootstrap.EnsureToolsAvailability(env, series, arch)
	if err != nil {
		return nil, err
	}
	return bootstrap.SetBootstrapTools(env, possibleTools)
}

// EnsureNotBootstrapped returns null if the environment is not bootstrapped,
// and an error if it is or if the function was not able to tell.
func EnsureNotBootstrapped(env environs.Environ) error {
	_, err := bootstrap.LoadState(env.Storage())
	// If there is no error loading the bootstrap state, then we are
	// bootstrapped.
	if err == nil {
		return fmt.Errorf("environment is already bootstrapped")
	}
	if err == environs.ErrNotBootstrapped {
		return nil
	}
	return err
}
<|endoftext|>


<commit_before>package ovh

import (
	"encoding/json"
	"fmt"
	"sort"
	"strings"

	"github.com/StackExchange/dnscontrol/models"
	"github.com/StackExchange/dnscontrol/providers"
	"github.com/StackExchange/dnscontrol/providers/diff"
	"github.com/pkg/errors"
	"github.com/xlucas/go-ovh/ovh"
)

type ovhProvider struct {
	client *ovh.Client
	zones  map[string]bool
}

var features = providers.DocumentationNotes{
	providers.CanUseAlias:            providers.Cannot(),
	providers.CanUseCAA:              providers.Cannot(),
	providers.CanUsePTR:              providers.Cannot(),
	providers.CanUseSRV:              providers.Can(),
	providers.CanUseTLSA:             providers.Can(),
	providers.DocCreateDomains:       providers.Cannot("New domains require registration"),
	providers.DocDualHost:            providers.Can(),
	providers.DocOfficiallySupported: providers.Cannot(),
}

func newOVH(m map[string]string, metadata json.RawMessage) (*ovhProvider, error) {
	appKey, appSecretKey, consumerKey := m["app-key"], m["app-secret-key"], m["consumer-key"]

	c := ovh.NewClient(ovh.ENDPOINT_EU_OVHCOM, appKey, appSecretKey, consumerKey, false)

	// Check for time lag
	if err := c.PollTimeshift(); err != nil {
		return nil, err
	}

	return &ovhProvider{client: c}, nil
}

func newDsp(conf map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
	return newOVH(conf, metadata)
}

func newReg(conf map[string]string) (providers.Registrar, error) {
	return newOVH(conf, nil)
}

func init() {
	providers.RegisterRegistrarType("OVH", newReg)
	providers.RegisterDomainServiceProviderType("OVH", newDsp, features)
}

func (c *ovhProvider) GetNameservers(domain string) ([]*models.Nameserver, error) {
	if err := c.fetchZones(); err != nil {
		return nil, err
	}
	_, ok := c.zones[domain]
	if !ok {
		return nil, errors.Errorf("%s not listed in zones for ovh account", domain)
	}

	ns, err := c.fetchNS(domain)
	if err != nil {
		return nil, err
	}

	return models.StringsToNameservers(ns), nil
}

type errNoExist struct {
	domain string
}

func (e errNoExist) Error() string {
	return fmt.Sprintf("Domain %s not found in your ovh account", e.domain)
}

func (c *ovhProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
	dc.Punycode()
	//dc.CombineMXs()

	if !c.zones[dc.Name] {
		return nil, errNoExist{dc.Name}
	}

	records, err := c.fetchRecords(dc.Name)
	if err != nil {
		return nil, err
	}

	var actual []*models.RecordConfig
	for _, r := range records {
		rec := nativeToRecord(r, dc.Name)
		if rec != nil {
			actual = append(actual, rec)
		}
	}

	// Normalize
	models.PostProcessRecords(actual)

	differ := diff.New(dc)
	_, create, delete, modify := differ.IncrementalDiff(actual)

	corrections := []*models.Correction{}

	for _, del := range delete {
		rec := del.Existing.Original.(*Record)
		corrections = append(corrections, &models.Correction{
			Msg: del.String(),
			F:   c.deleteRecordFunc(rec.ID, dc.Name),
		})
	}

	for _, cre := range create {
		rec := cre.Desired
		corrections = append(corrections, &models.Correction{
			Msg: cre.String(),
			F:   c.createRecordFunc(rec, dc.Name),
		})
	}

	for _, mod := range modify {
		oldR := mod.Existing.Original.(*Record)
		newR := mod.Desired
		corrections = append(corrections, &models.Correction{
			Msg: mod.String(),
			F:   c.updateRecordFunc(oldR, newR, dc.Name),
		})
	}

	if len(corrections) > 0 {
		corrections = append(corrections, &models.Correction{
			Msg: "REFRESH zone " + dc.Name,
			F: func() error {
				return c.refreshZone(dc.Name)
			},
		})
	}

	return corrections, nil
}

func nativeToRecord(r *Record, origin string) *models.RecordConfig {
	if r.FieldType == "SOA" {
		return nil
	}
	rec := &models.RecordConfig{
		TTL:      uint32(r.TTL),
		Original: r,
	}
	rtype := r.FieldType
	rec.SetLabel(r.SubDomain, origin)
	if err := rec.PopulateFromString(rtype, r.Target, origin); err != nil {
		panic(errors.Wrap(err, "unparsable record received from ovh"))
	}

	// ovh uses a custom type for SPF and DKIM
	if rtype == "SPF" || rtype == "DKIM" {
		rec.Type = "TXT"
	}

	// ovh default is 3600
	if rec.TTL == 0 {
		rec.TTL = 3600
	}

	return rec
}

func (c *ovhProvider) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {

	ns, err := c.fetchRegistrarNS(dc.Name)
	if err != nil {
		return nil, err
	}

	sort.Strings(ns)
	found := strings.Join(ns, ",")

	desiredNs := []string{}
	for _, d := range dc.Nameservers {
		desiredNs = append(desiredNs, d.Name)
	}
	sort.Strings(desiredNs)
	desired := strings.Join(desiredNs, ",")

	if found != desired {
		return []*models.Correction{
			{
				Msg: fmt.Sprintf("Change Nameservers from '%s' to '%s'", found, desired),
				F: func() error {
					err := c.updateNS(dc.Name, desiredNs)
					if err != nil {
						return err
					}
					return nil
				}},
		}, nil
	}
	return nil, nil
}
<commit_msg>OVH: panic on SPF and DKIM record types (#340)<commit_after>package ovh

import (
	"encoding/json"
	"fmt"
	"sort"
	"strings"

	"github.com/StackExchange/dnscontrol/models"
	"github.com/StackExchange/dnscontrol/providers"
	"github.com/StackExchange/dnscontrol/providers/diff"
	"github.com/pkg/errors"
	"github.com/xlucas/go-ovh/ovh"
)

type ovhProvider struct {
	client *ovh.Client
	zones  map[string]bool
}

var features = providers.DocumentationNotes{
	providers.CanUseAlias:            providers.Cannot(),
	providers.CanUseCAA:              providers.Cannot(),
	providers.CanUsePTR:              providers.Cannot(),
	providers.CanUseSRV:              providers.Can(),
	providers.CanUseTLSA:             providers.Can(),
	providers.DocCreateDomains:       providers.Cannot("New domains require registration"),
	providers.DocDualHost:            providers.Can(),
	providers.DocOfficiallySupported: providers.Cannot(),
}

func newOVH(m map[string]string, metadata json.RawMessage) (*ovhProvider, error) {
	appKey, appSecretKey, consumerKey := m["app-key"], m["app-secret-key"], m["consumer-key"]

	c := ovh.NewClient(ovh.ENDPOINT_EU_OVHCOM, appKey, appSecretKey, consumerKey, false)

	// Check for time lag
	if err := c.PollTimeshift(); err != nil {
		return nil, err
	}

	return &ovhProvider{client: c}, nil
}

func newDsp(conf map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
	return newOVH(conf, metadata)
}

func newReg(conf map[string]string) (providers.Registrar, error) {
	return newOVH(conf, nil)
}

func init() {
	providers.RegisterRegistrarType("OVH", newReg)
	providers.RegisterDomainServiceProviderType("OVH", newDsp, features)
}

func (c *ovhProvider) GetNameservers(domain string) ([]*models.Nameserver, error) {
	if err := c.fetchZones(); err != nil {
		return nil, err
	}
	_, ok := c.zones[domain]
	if !ok {
		return nil, errors.Errorf("%s not listed in zones for ovh account", domain)
	}

	ns, err := c.fetchNS(domain)
	if err != nil {
		return nil, err
	}

	return models.StringsToNameservers(ns), nil
}

type errNoExist struct {
	domain string
}

func (e errNoExist) Error() string {
	return fmt.Sprintf("Domain %s not found in your ovh account", e.domain)
}

func (c *ovhProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
	dc.Punycode()
	//dc.CombineMXs()

	if !c.zones[dc.Name] {
		return nil, errNoExist{dc.Name}
	}

	records, err := c.fetchRecords(dc.Name)
	if err != nil {
		return nil, err
	}

	var actual []*models.RecordConfig
	for _, r := range records {
		rec := nativeToRecord(r, dc.Name)
		if rec != nil {
			actual = append(actual, rec)
		}
	}

	// Normalize
	models.PostProcessRecords(actual)

	differ := diff.New(dc)
	_, create, delete, modify := differ.IncrementalDiff(actual)

	corrections := []*models.Correction{}

	for _, del := range delete {
		rec := del.Existing.Original.(*Record)
		corrections = append(corrections, &models.Correction{
			Msg: del.String(),
			F:   c.deleteRecordFunc(rec.ID, dc.Name),
		})
	}

	for _, cre := range create {
		rec := cre.Desired
		corrections = append(corrections, &models.Correction{
			Msg: cre.String(),
			F:   c.createRecordFunc(rec, dc.Name),
		})
	}

	for _, mod := range modify {
		oldR := mod.Existing.Original.(*Record)
		newR := mod.Desired
		corrections = append(corrections, &models.Correction{
			Msg: mod.String(),
			F:   c.updateRecordFunc(oldR, newR, dc.Name),
		})
	}

	if len(corrections) > 0 {
		corrections = append(corrections, &models.Correction{
			Msg: "REFRESH zone " + dc.Name,
			F: func() error {
				return c.refreshZone(dc.Name)
			},
		})
	}

	return corrections, nil
}

func nativeToRecord(r *Record, origin string) *models.RecordConfig {
	if r.FieldType == "SOA" {
		return nil
	}
	rec := &models.RecordConfig{
		TTL:      uint32(r.TTL),
		Original: r,
	}

	rtype := r.FieldType

	// ovh uses a custom type for SPF and DKIM
	if rtype == "SPF" || rtype == "DKIM" {
		rtype = "TXT"
	}

	rec.SetLabel(r.SubDomain, origin)
	if err := rec.PopulateFromString(rtype, r.Target, origin); err != nil {
		panic(errors.Wrap(err, "unparsable record received from ovh"))
	}

	// ovh default is 3600
	if rec.TTL == 0 {
		rec.TTL = 3600
	}

	return rec
}

func (c *ovhProvider) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {

	ns, err := c.fetchRegistrarNS(dc.Name)
	if err != nil {
		return nil, err
	}

	sort.Strings(ns)
	found := strings.Join(ns, ",")

	desiredNs := []string{}
	for _, d := range dc.Nameservers {
		desiredNs = append(desiredNs, d.Name)
	}
	sort.Strings(desiredNs)
	desired := strings.Join(desiredNs, ",")

	if found != desired {
		return []*models.Correction{
			{
				Msg: fmt.Sprintf("Change Nameservers from '%s' to '%s'", found, desired),
				F: func() error {
					err := c.updateNS(dc.Name, desiredNs)
					if err != nil {
						return err
					}
					return nil
				}},
		}, nil
	}
	return nil, nil
}
<|endoftext|>


<commit_before>package num

import "time"

var (
	// Default size of statistical window over which the rolling number is defined.
	DefaultWindowSize time.Duration = 10000 * time.Millisecond
	// number of buckets in the statistical window.
	DefaultWindowBuckets uint = 10
)

// RollingNumber is an implementation of a number that is defined for a specified
// window. Value changes that fall out of the sliding window are discarded.
type RollingNumber struct {
	bucketSize        time.Duration
	currentBucket     uint
	currentBucketTime time.Time
	buckets           []uint64
}

// NewRollingNumber constructs a new RollingNumber with a default value of zero.
func NewRollingNumber(windowSize time.Duration, windowBuckets uint) *RollingNumber {
	return &RollingNumber{
		bucketSize:        calculateBucketSize(windowSize, windowBuckets),
		currentBucket:     0,
		currentBucketTime: time.Now(),
		buckets:           make([]uint64, windowBuckets),
	}
}

// calculatebucketsize calculates a bucket size based on requested window size
// and number of buckets. The smallest bucket size is 1 millisecond.`
// Actual window size can be larger if the requested number of buckets does not fit in
// the window size.
func calculateBucketSize(windowSize time.Duration, windowBuckets uint) time.Duration {
	bucketSize := windowSize / time.Duration(windowBuckets)
	if bucketSize < time.Millisecond {
		// Calculated bucket size is smaller thatn the minimum.
		return time.Millisecond
	}
	return bucketSize
}

// BucketSize returns the calculated bucket size based on requested sliding window parameters.
func (n *RollingNumber) BucketSize() time.Duration {
	return n.bucketSize
}

// Increment increments the number by one.
func (n *RollingNumber) Increment() {
	n.buckets[n.findCurrentBucket()] += 1
}

// Sum sums all the bucket values of the sliding window and returns the result.
func (n *RollingNumber) Sum() uint64 {
	// We don't need the current bucket but we must still recalculate which bucket is current
	// and reset values that are no longer valid.
	n.findCurrentBucket()
	sum := uint64(0)
	for _, v := range n.buckets {
		sum += v
	}
	return sum
}

// Reset resets a number to a default value.
func (n *RollingNumber) Reset() {
	n.currentBucket = 0
	n.currentBucketTime = time.Now()
	for i, _ := range n.buckets {
		n.buckets[i] = 0
	}
}

// findCurrentBucket returns an index of the current bucket and updates the buckets
// that should be reset for reuse based on the time elapsed since last access.
func (n *RollingNumber) findCurrentBucket() uint {
	now := time.Now()
	timeDiffFromFirstBucket := now.Sub(n.currentBucketTime)
	bucketsBehind := uint(timeDiffFromFirstBucket / n.bucketSize)
	if bucketsBehind > 0 {
		// We are not in the current bucket so we must reset the values of
		// buckets that fell out of the sliding window.
		for i := uint(1); i <= bucketsBehind; i++ {
			n.buckets[(n.currentBucket+i)%uint(len(n.buckets))] = 0
		}
		n.currentBucket = (n.currentBucket + bucketsBehind) % uint(len(n.buckets))
		n.currentBucketTime = now
	}
	return n.currentBucket
}
<commit_msg>Small optimization to RollingNumber.<commit_after>package num

import "time"

var (
	// Default size of statistical window over which the rolling number is defined.
	DefaultWindowSize time.Duration = 10000 * time.Millisecond
	// number of buckets in the statistical window.
	DefaultWindowBuckets uint = 10
)

// RollingNumber is an implementation of a number that is defined for a specified
// window. Value changes that fall out of the sliding window are discarded.
type RollingNumber struct {
	bucketSize        time.Duration
	currentBucket     uint
	currentBucketTime time.Time
	buckets           []uint64
}

// NewRollingNumber constructs a new RollingNumber with a default value of zero.
func NewRollingNumber(windowSize time.Duration, windowBuckets uint) *RollingNumber {
	return &RollingNumber{
		bucketSize:        calculateBucketSize(windowSize, windowBuckets),
		currentBucket:     0,
		currentBucketTime: time.Now(),
		buckets:           make([]uint64, windowBuckets),
	}
}

// calculatebucketsize calculates a bucket size based on requested window size
// and number of buckets. The smallest bucket size is 1 millisecond.`
// Actual window size can be larger if the requested number of buckets does not fit in
// the window size.
func calculateBucketSize(windowSize time.Duration, windowBuckets uint) time.Duration {
	bucketSize := windowSize / time.Duration(windowBuckets)
	if bucketSize < time.Millisecond {
		// Calculated bucket size is smaller thatn the minimum.
		return time.Millisecond
	}
	return bucketSize
}

// BucketSize returns the calculated bucket size based on requested sliding window parameters.
func (n *RollingNumber) BucketSize() time.Duration {
	return n.bucketSize
}

// Increment increments the number by one.
func (n *RollingNumber) Increment() {
	n.buckets[n.findCurrentBucket()] += 1
}

// Sum sums all the bucket values of the sliding window and returns the result.
func (n *RollingNumber) Sum() uint64 {
	// We don't need the current bucket but we must still recalculate which bucket is current
	// and reset values that are no longer valid.
	n.findCurrentBucket()
	sum := uint64(0)
	for _, v := range n.buckets {
		sum += v
	}
	return sum
}

// Reset resets a number to a default value.
func (n *RollingNumber) Reset() {
	n.currentBucket = 0
	n.currentBucketTime = time.Now()
	for i, _ := range n.buckets {
		n.buckets[i] = 0
	}
}

// findCurrentBucket returns an index of the current bucket and updates the buckets
// that should be reset for reuse based on the time elapsed since last access.
func (n *RollingNumber) findCurrentBucket() uint {
	now := time.Now()
	timeDiffFromFirstBucket := now.Sub(n.currentBucketTime)
	bucketsBehind := uint(timeDiffFromFirstBucket / n.bucketSize)
	if bucketsBehind > 0 {
		// We are not in the current bucket so we must reset the values of
		// buckets that fell out of the sliding window.
		numBuckets := uint(len(n.buckets))
		for i := uint(1); i <= bucketsBehind%numBuckets; i++ {
			n.buckets[(n.currentBucket+i)%numBuckets] = 0
		}
		n.currentBucket = (n.currentBucket + bucketsBehind) % numBuckets
		n.currentBucketTime = now
	}
	return n.currentBucket
}
<|endoftext|>


<commit_before>package object

import (
	"fmt"
)

/* Structs */
type (
	Number struct {
		Value float64
	}

	Boolean struct {
		Value bool
	}

	String struct {
		Value string
	}

	Char struct {
		Value rune
	}

	Null struct{}
)

/* Type() methods */
func (_ *Number) Type() Type  { return NUMBER }
func (_ *Boolean) Type() Type { return BOOLEAN }
func (_ *String) Type() Type  { return STRING }
func (_ *Char) Type() Type    { return CHAR }
func (_ *Null) Type() Type    { return NULL }

/* Equals() methods */
func (n *Number) Equals(o Object) bool {
	if other, ok := o.(*Number); ok {
		return n.Value == other.Value
	}

	return false
}

func (b *Boolean) Equals(o Object) bool {
	if other, ok := o.(*Boolean); ok {
		return b.Value == other.Value
	}

	return false
}

func (s *String) Equals(o Object) bool {
	if other, ok := o.(*String); ok {
		return s.Value == other.Value
	}

	return false
}

func (c *Char) Equals(o Object) bool {
	if other, ok := o.(*Char); ok {
		return c.Value == other.Value
	}

	return false
}

func (_ *Null) Equals(o Object) bool {
	_, ok := o.(*Null)
	return ok
}

/* Stringer implementations */
func (n *Number) String() string {
	return fmt.Sprintf("%g", n.Value)
}

func (b *Boolean) String() string {
	return fmt.Sprintf("%t", b.Value)
}

func (s *String) String() string {
	return s.Value
}

func (c *Char) String() string {
	return string(c.Value)
}

func (_ *Null) String() string {
	return "null"
}

/* Collection implementations */
func (s *String) Elements() []Object {
	chars := make([]Object, len(s.Value))

	for i, ch := range s.Value {
		chars[i] = &Char{ch}
	}

	return chars
}

func (s *String) GetIndex(i int) Object {
	return &Char{Value: rune(s.Value[i])}
}

func (s *String) SetIndex(i int, o Object) {
	fmt.Println(o)

	if ch, ok := o.(*Char); ok {
		bytes := []byte(s.Value)
		bytes[i] = byte(ch.Value)
		s.Value = string(bytes)
	}
}

/* Hasher implementations */
func (n *Number) Hash() string {
	return fmt.Sprintf("number %g", n.Value)
}

func (b *Boolean) Hash() string {
	return fmt.Sprintf("boolean %t", b.Value)
}

func (s *String) Hash() string {
	return fmt.Sprintf("string %s", s.Value)
}

func (c *Char) Hash() string {
	return fmt.Sprintf("char %s", string(c.Value))
}

func (n *Null) Hash() string {
	return "null"
}
<commit_msg>Remove a debug print<commit_after>package object

import (
	"fmt"
)

/* Structs */
type (
	Number struct {
		Value float64
	}

	Boolean struct {
		Value bool
	}

	String struct {
		Value string
	}

	Char struct {
		Value rune
	}

	Null struct{}
)

/* Type() methods */
func (_ *Number) Type() Type  { return NUMBER }
func (_ *Boolean) Type() Type { return BOOLEAN }
func (_ *String) Type() Type  { return STRING }
func (_ *Char) Type() Type    { return CHAR }
func (_ *Null) Type() Type    { return NULL }

/* Equals() methods */
func (n *Number) Equals(o Object) bool {
	if other, ok := o.(*Number); ok {
		return n.Value == other.Value
	}

	return false
}

func (b *Boolean) Equals(o Object) bool {
	if other, ok := o.(*Boolean); ok {
		return b.Value == other.Value
	}

	return false
}

func (s *String) Equals(o Object) bool {
	if other, ok := o.(*String); ok {
		return s.Value == other.Value
	}

	return false
}

func (c *Char) Equals(o Object) bool {
	if other, ok := o.(*Char); ok {
		return c.Value == other.Value
	}

	return false
}

func (_ *Null) Equals(o Object) bool {
	_, ok := o.(*Null)
	return ok
}

/* Stringer implementations */
func (n *Number) String() string {
	return fmt.Sprintf("%g", n.Value)
}

func (b *Boolean) String() string {
	return fmt.Sprintf("%t", b.Value)
}

func (s *String) String() string {
	return s.Value
}

func (c *Char) String() string {
	return string(c.Value)
}

func (_ *Null) String() string {
	return "null"
}

/* Collection implementations */
func (s *String) Elements() []Object {
	chars := make([]Object, len(s.Value))

	for i, ch := range s.Value {
		chars[i] = &Char{ch}
	}

	return chars
}

func (s *String) GetIndex(i int) Object {
	return &Char{Value: rune(s.Value[i])}
}

func (s *String) SetIndex(i int, o Object) {
	if ch, ok := o.(*Char); ok {
		bytes := []byte(s.Value)
		bytes[i] = byte(ch.Value)
		s.Value = string(bytes)
	}
}

/* Hasher implementations */
func (n *Number) Hash() string {
	return fmt.Sprintf("number %g", n.Value)
}

func (b *Boolean) Hash() string {
	return fmt.Sprintf("boolean %t", b.Value)
}

func (s *String) Hash() string {
	return fmt.Sprintf("string %s", s.Value)
}

func (c *Char) Hash() string {
	return fmt.Sprintf("char %s", string(c.Value))
}

func (n *Null) Hash() string {
	return "null"
}
<|endoftext|>


<commit_before>package nomad

import (
	"fmt"

	"github.com/hashicorp/vault/logical"
	"github.com/hashicorp/vault/logical/framework"
)

func pathListRoles(b *backend) *framework.Path {
	return &framework.Path{
		Pattern: "role/?$",

		Callbacks: map[logical.Operation]framework.OperationFunc{
			logical.ListOperation: b.pathRoleList,
		},
	}
}

func pathRoles(b *backend) *framework.Path {
	return &framework.Path{
		Pattern: "role/" + framework.GenericNameRegex("name"),
		Fields: map[string]*framework.FieldSchema{
			"name": &framework.FieldSchema{
				Type:        framework.TypeString,
				Description: "Name of the role",
			},

			"policy": &framework.FieldSchema{
				Type:        framework.TypeCommaStringSlice,
				Description: "Policy name as previously created in Nomad. Required",
			},

			"global": &framework.FieldSchema{
				Type:        framework.TypeBool,
				Description: "Policy name as previously created in Nomad. Required",
			},

			"type": &framework.FieldSchema{
				Type:    framework.TypeString,
				Default: "client",
				Description: `Which type of token to create: 'client'
or 'management'. If a 'management' token,
the "policy" parameter is not required.
Defaults to 'client'.`,
			},
		},

		Callbacks: map[logical.Operation]framework.OperationFunc{
			logical.ReadOperation:   b.pathRolesRead,
			logical.UpdateOperation: b.pathRolesWrite,
			logical.DeleteOperation: b.pathRolesDelete,
		},
	}
}

func (b *backend) Role(storage logical.Storage, name string) (*roleConfig, error) {
	entry, err := storage.Get("role/" + name)
	if err != nil {
		return nil, fmt.Errorf("error retrieving role: %s", err)
	}
	if entry == nil {
		return nil, nil
	}

	var result roleConfig
	if err := entry.DecodeJSON(&result); err != nil {
		return nil, err
	}
	return &result, nil
}

func (b *backend) pathRoleList(
	req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
	entries, err := req.Storage.List("role/")
	if err != nil {
		return nil, err
	}

	return logical.ListResponse(entries), nil
}

func (b *backend) pathRolesRead(
	req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
	name := d.Get("name").(string)

	role, err := b.Role(req.Storage, name)
	if err != nil {
		return nil, err
	}
	if role == nil {
		return nil, nil
	}

	// Generate the response
	resp := &logical.Response{
		Data: map[string]interface{}{
			"type":   role.TokenType,
			"global": role.Global,
		},
	}
	if len(role.Policy) > 0 {
		resp.Data["policy"] = role.Policy
	}
	return resp, nil
}

func (b *backend) pathRolesWrite(
	req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
	tokenType := d.Get("type").(string)
	name := d.Get("name").(string)
	global := d.Get("global").(bool)
	policy := d.Get("policy").([]string)

	switch tokenType {
	case "client":
		if len(policy) == 0 {
			return logical.ErrorResponse(
				"policy cannot be empty when using client tokens"), nil
		}
	case "management":
		if len(policy) != 0 {
			return logical.ErrorResponse(
				"policy should be empty when using management tokens"), nil
		}
	default:
		return logical.ErrorResponse(
			"type must be \"client\" or \"management\""), nil
	}

	entry, err := logical.StorageEntryJSON("role/"+name, roleConfig{
		Policy:    policy,
		TokenType: tokenType,
		Global:    global,
	})
	if err != nil {
		return nil, err
	}

	if err := req.Storage.Put(entry); err != nil {
		return nil, err
	}

	return nil, nil
}

func (b *backend) pathRolesDelete(
	req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
	name := d.Get("name").(string)
	if err := req.Storage.Delete("role/" + name); err != nil {
		return nil, err
	}
	return nil, nil
}

type roleConfig struct {
	Policy    []string `json:"policy"`
	TokenType string   `json:"type"`
	Global    bool     `json:"global"`
}
<commit_msg>Updating descriptions, defaults for roles<commit_after>package nomad

import (
	"fmt"

	"github.com/hashicorp/vault/logical"
	"github.com/hashicorp/vault/logical/framework"
)

func pathListRoles(b *backend) *framework.Path {
	return &framework.Path{
		Pattern: "role/?$",

		Callbacks: map[logical.Operation]framework.OperationFunc{
			logical.ListOperation: b.pathRoleList,
		},
	}
}

func pathRoles(b *backend) *framework.Path {
	return &framework.Path{
		Pattern: "role/" + framework.GenericNameRegex("name"),
		Fields: map[string]*framework.FieldSchema{
			"name": &framework.FieldSchema{
				Type:        framework.TypeString,
				Description: "Name of the role",
			},

			"policy": &framework.FieldSchema{
				Type:        framework.TypeCommaStringSlice,
				Description: "Comma separated list of policies as previously created in Nomad. Required",
			},

			"global": &framework.FieldSchema{
				Type:        framework.TypeBool,
				Default:     false,
				Description: "Boolean value describing if the token should be global or not. Defaults to false",
			},

			"type": &framework.FieldSchema{
				Type:    framework.TypeString,
				Default: "client",
				Description: `Which type of token to create: 'client'
or 'management'. If a 'management' token,
the "policy" parameter is not required.
Defaults to 'client'.`,
			},
		},

		Callbacks: map[logical.Operation]framework.OperationFunc{
			logical.ReadOperation:   b.pathRolesRead,
			logical.UpdateOperation: b.pathRolesWrite,
			logical.DeleteOperation: b.pathRolesDelete,
		},
	}
}

func (b *backend) Role(storage logical.Storage, name string) (*roleConfig, error) {
	entry, err := storage.Get("role/" + name)
	if err != nil {
		return nil, fmt.Errorf("error retrieving role: %s", err)
	}
	if entry == nil {
		return nil, nil
	}

	var result roleConfig
	if err := entry.DecodeJSON(&result); err != nil {
		return nil, err
	}
	return &result, nil
}

func (b *backend) pathRoleList(
	req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
	entries, err := req.Storage.List("role/")
	if err != nil {
		return nil, err
	}

	return logical.ListResponse(entries), nil
}

func (b *backend) pathRolesRead(
	req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
	name := d.Get("name").(string)

	role, err := b.Role(req.Storage, name)
	if err != nil {
		return nil, err
	}
	if role == nil {
		return nil, nil
	}

	// Generate the response
	resp := &logical.Response{
		Data: map[string]interface{}{
			"type":   role.TokenType,
			"global": role.Global,
			"policy": role.Policy,
		},
	}
	return resp, nil
}

func (b *backend) pathRolesWrite(
	req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
	tokenType := d.Get("type").(string)
	name := d.Get("name").(string)
	global := d.Get("global").(bool)
	policy := d.Get("policy").([]string)

	switch tokenType {
	case "client":
		if len(policy) == 0 {
			return logical.ErrorResponse(
				"policy cannot be empty when using client tokens"), nil
		}
	case "management":
		if len(policy) != 0 {
			return logical.ErrorResponse(
				"policy should be empty when using management tokens"), nil
		}
	default:
		return logical.ErrorResponse(
			"type must be \"client\" or \"management\""), nil
	}

	entry, err := logical.StorageEntryJSON("role/"+name, roleConfig{
		Policy:    policy,
		TokenType: tokenType,
		Global:    global,
	})
	if err != nil {
		return nil, err
	}

	if err := req.Storage.Put(entry); err != nil {
		return nil, err
	}

	return nil, nil
}

func (b *backend) pathRolesDelete(
	req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
	name := d.Get("name").(string)
	if err := req.Storage.Delete("role/" + name); err != nil {
		return nil, err
	}
	return nil, nil
}

type roleConfig struct {
	Policy    []string `json:"policy"`
	TokenType string   `json:"type"`
	Global    bool     `json:"global"`
}
<|endoftext|>


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

package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"

	"github.com/spf13/pflag"
)

var (
	argPort          = pflag.Int("port", 9090, "The port to listen to for incoming HTTP requests")
	argApiserverHost = pflag.String("apiserver-host", "", "The address of the Kubernetes Apiserver "+
		"to connect to in the format of protocol://address:port, e.g., "+
		"http://localhost:8080. If not specified, the assumption is that the binary runs inside a"+
		"Kubernetes cluster and local discovery is attempted.")
	argHeapsterHost = pflag.String("heapster-host", "", "The address of the Heapster Apiserver "+
		"to connect to in the format of protocol://address:port, e.g., "+
		"http://localhost:8082. If not specified, the assumption is that the binary runs inside a"+
		"Kubernetes cluster and service proxy will be used.")
)

func main() {
	pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
	pflag.Parse()

	log.Printf("Starting HTTP server on port %d", *argPort)

	apiserverClient, config, err := CreateApiserverClient(*argApiserverHost)
	if err != nil {
		log.Fatalf("Error while initializing connection to Kubernetes master: %s. Quitting.", err)
	}

	heapsterRESTClient, err := CreateHeapsterRESTClient(*argHeapsterHost, apiserverClient)
	if err != nil {
		log.Print(err)
	}

	// Run a HTTP server that serves static public files from './public' and handles API calls.
	// TODO(bryk): Disable directory listing.
	http.Handle("/", http.FileServer(http.Dir("./public")))
	http.Handle("/api/", CreateHttpApiHandler(apiserverClient, heapsterRESTClient, config))
	log.Print(http.ListenAndServe(fmt.Sprintf(":%d", *argPort), nil))
}
<commit_msg>Validate connection setup on backend startup<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"

	"github.com/spf13/pflag"
)

var (
	argPort          = pflag.Int("port", 9090, "The port to listen to for incoming HTTP requests")
	argApiserverHost = pflag.String("apiserver-host", "", "The address of the Kubernetes Apiserver "+
		"to connect to in the format of protocol://address:port, e.g., "+
		"http://localhost:8080. If not specified, the assumption is that the binary runs inside a"+
		"Kubernetes cluster and local discovery is attempted.")
	argHeapsterHost = pflag.String("heapster-host", "", "The address of the Heapster Apiserver "+
		"to connect to in the format of protocol://address:port, e.g., "+
		"http://localhost:8082. If not specified, the assumption is that the binary runs inside a"+
		"Kubernetes cluster and service proxy will be used.")
)

func main() {
	pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
	pflag.Parse()

	log.Printf("Starting HTTP server on port %d", *argPort)

	apiserverClient, config, err := CreateApiserverClient(*argApiserverHost)
	if err != nil {
		handleFatalInitError(err)
	}

	versionInfo, err := apiserverClient.ServerVersion()
	if err != nil {
		handleFatalInitError(err)
	}
	log.Printf("Successful initial request to the apiserver, version: %s", versionInfo.String())

	heapsterRESTClient, err := CreateHeapsterRESTClient(*argHeapsterHost, apiserverClient)
	if err != nil {
		log.Print("Could not create heapster client: %s. Continuing.", err)
	}

	// Run a HTTP server that serves static public files from './public' and handles API calls.
	// TODO(bryk): Disable directory listing.
	http.Handle("/", http.FileServer(http.Dir("./public")))
	http.Handle("/api/", CreateHttpApiHandler(apiserverClient, heapsterRESTClient, config))
	log.Print(http.ListenAndServe(fmt.Sprintf(":%d", *argPort), nil))
}

/**
 * Handles fatal init error that prevents server from doing any work. Prints verbose error
 * message and quits the server.
 */
func handleFatalInitError(err error) {
	log.Fatalf("Error while initializing connection to Kubernetes apiserver. "+
		"This most likely means that the cluster is misconfigured (e.g., it has "+
		"invalid apiserver certificates or service accounts configuration) or the "+
		"--apiserver-host param points to a server that does not exist. Reason: %s", err)
}
<|endoftext|>


<commit_before>package nats

import (
	"testing"
	"time"
)

func startReconnectServer(t *testing.T) *server {
	return startServer(t, 22222, "")
}

func TestReconnectDisallowedFlags(t *testing.T) {
	ts := startReconnectServer(t)
	ch := make(chan bool)
	opts := DefaultOptions
	opts.Url = "nats://localhost:22222"
	opts.AllowReconnect = false
	opts.ClosedCB = func(_ *Conn) {
		ch <- true
	}
	nc, err := opts.Connect()
	if err != nil {
		t.Fatalf("Should have connected ok: %v", err)
	}

	ts.stopServer()
	if e := wait(ch); e != nil {
		t.Fatal("Did not trigger ClosedCB correctly")
	}
	nc.Close()
}

func TestReconnectAllowedFlags(t *testing.T) {
	ts := startReconnectServer(t)
	ch := make(chan bool)
	opts := DefaultOptions
	opts.Url = "nats://localhost:22222"
	opts.AllowReconnect = true
	opts.ClosedCB = func(_ *Conn) {
		println("INSIDE CLOSED CB in TEST")
		ch <- true
		println("Exiting CB")
	}
	nc, err := opts.Connect();
	if err != nil {
		t.Fatalf("Should have connected ok: %v", err)
	}

	ts.stopServer()
	if e := wait(ch); e == nil {
		t.Fatal("Triggered ClosedCB incorrectly")
	}
	// clear the CloseCB since ch will block
	nc.opts.ClosedCB = nil
	nc.Close()
}

var reconnectOpts =  Options{
	Url: "nats://localhost:22222",
	AllowReconnect: true,
	MaxReconnect:   10,
	ReconnectWait:  100 * time.Millisecond,
	Timeout:        DefaultTimeout,
}

func TestBasicReconnectFunctionality(t *testing.T) {
	ts := startReconnectServer(t)
	ch := make(chan bool)

	opts := reconnectOpts
	nc, _ := opts.Connect()
	ec, err := NewEncodedConn(nc, "default")
	if err != nil {
		t.Fatalf("Failed to create an encoded connection: %v\n", err)
	}

	testString := "bar"
	ec.Subscribe("foo", func(s string) {
		if s != testString {
			t.Fatal("String don't match")
		}
		ch <- true
	})
	ec.Flush()

	ts.stopServer()

	// server is stopped here..
	ec.Publish("foo", testString)

	ts = startReconnectServer(t)
	defer ts.stopServer()

	if e := wait(ch); e != nil {
		t.Fatal("Did not receive our message")
	}
	nc.Close()
}

func TestExtendedReconnectFunctionality(t *testing.T) {
	ts := startReconnectServer(t)
	cbCalled := false
	rcbCalled := false

	opts := reconnectOpts
	opts.DisconnectedCB = func(_ *Conn) {
		cbCalled = true
	}
	opts.ReconnectedCB = func(_ *Conn) {
		rcbCalled = true
	}
	nc, err := opts.Connect()
	if err != nil {
		t.Fatalf("Should have connected ok: %v", err)
	}
	ec, err := NewEncodedConn(nc, "default")
	if err != nil {
		t.Fatalf("Failed to create an encoded connection: %v\n", err)
	}
	testString := "bar"
	received := 0

	ec.Subscribe("foo", func(s string) {
		received += 1
	})

	sub, _ := ec.Subscribe("foobar", func(s string) {
		received += 1
	})

	ec.Publish("foo", testString)
	ec.Flush()

	ts.stopServer()
	// server is stopped here..

	// Sub while disconnected
	ec.Subscribe("bar", func(s string) {
		received += 1
	})

	// Unsub while disconnected
	sub.Unsubscribe()

	if err = ec.Publish("foo", testString); err != nil {
		t.Fatalf("Got an error after disconnect: %v\n", err)
	}

	if err = ec.Publish("bar", testString); err != nil {
		t.Fatalf("Got an error after disconnect: %v\n", err)
	}

	ts = startReconnectServer(t)
	defer ts.stopServer()
	// server is restarted here..

	if err = ec.Publish("foobar", testString); err != nil {
		t.Fatalf("Got an error after server restarted: %v\n", err)
	}

	if err = ec.Publish("foo", testString); err != nil {
		t.Fatalf("Got an error after server restarted: %v\n", err)
	}

	ch := make(chan bool)
	ec.Subscribe("done", func(b bool) {
		ch <- true
	})
	ec.Publish("done", true)

	if e := wait(ch); e != nil {
		t.Fatal("Did not receive our message")
	}

	if received != 4 {
		t.Fatalf("Received != %d, equals %d\n", 4, received)
	}
	if !cbCalled {
		t.Fatal("Did not have DisconnectedCB called")
	}
	if !rcbCalled {
		t.Fatal("Did not have ReconnectedCB called")
	}
}
<commit_msg>More sync, use log file<commit_after>package nats

import (
	"fmt"
	"os"
	"testing"
	"time"
)

var logFile = "/tmp/reconnect_test.log"

func startReconnectServer(t *testing.T) *server {
	args := fmt.Sprintf("-DV -l %s", logFile)
	return startServer(t, 22222, args)
}

func TestReconnectDisallowedFlags(t *testing.T) {
	ts := startReconnectServer(t)
	ch := make(chan bool)
	opts := DefaultOptions
	opts.Url = "nats://localhost:22222"
	opts.AllowReconnect = false
	opts.ClosedCB = func(_ *Conn) {
		ch <- true
	}
	nc, err := opts.Connect()
	if err != nil {
		t.Fatalf("Should have connected ok: %v", err)
	}

	ts.stopServer()
	if e := wait(ch); e != nil {
		t.Fatal("Did not trigger ClosedCB correctly")
	}
	nc.Close()
}

func TestReconnectAllowedFlags(t *testing.T) {
	ts := startReconnectServer(t)
	ch := make(chan bool)
	opts := DefaultOptions
	opts.Url = "nats://localhost:22222"
	opts.AllowReconnect = true
	opts.ClosedCB = func(_ *Conn) {
		println("INSIDE CLOSED CB in TEST")
		ch <- true
		println("Exiting CB")
	}
	nc, err := opts.Connect()
	if err != nil {
		t.Fatalf("Should have connected ok: %v", err)
	}

	ts.stopServer()
	if e := wait(ch); e == nil {
		t.Fatal("Triggered ClosedCB incorrectly")
	}
	// clear the CloseCB since ch will block
	nc.Opts.ClosedCB = nil
	nc.Close()
}

var reconnectOpts = Options{
	Url:            "nats://localhost:22222",
	AllowReconnect: true,
	MaxReconnect:   10,
	ReconnectWait:  100 * time.Millisecond,
	Timeout:        DefaultTimeout,
}

func TestBasicReconnectFunctionality(t *testing.T) {
	ts := startReconnectServer(t)
	ch := make(chan bool)

	opts := reconnectOpts
	nc, _ := opts.Connect()
	ec, err := NewEncodedConn(nc, "default")
	if err != nil {
		t.Fatalf("Failed to create an encoded connection: %v\n", err)
	}

	testString := "bar"
	ec.Subscribe("foo", func(s string) {
		if s != testString {
			t.Fatal("String don't match")
		}
		ch <- true
	})
	ec.Flush()

	ts.stopServer()
	// server is stopped here..

	dch := make(chan bool)
	opts.DisconnectedCB = func(_ *Conn) {
		dch <- true
	}
	wait(dch)

	if err := ec.Publish("foo", testString); err != nil {
		t.Fatalf("Failed to publish message: %v\n", err)
	}

	ts = startReconnectServer(t)
	defer ts.stopServer()

	if err := ec.FlushTimeout(5 * time.Second); err != nil {
		t.Fatal("Error on Flush: %v", err)
	}

	if e := wait(ch); e != nil {
		t.Fatal("Did not receive our message")
	}
	nc.Close()
}

func TestExtendedReconnectFunctionality(t *testing.T) {
	ts := startReconnectServer(t)
	cbCalled := false
	rcbCalled := false

	opts := reconnectOpts
	opts.DisconnectedCB = func(_ *Conn) {
		cbCalled = true
	}
	rch := make(chan bool)
	opts.ReconnectedCB = func(_ *Conn) {
		rcbCalled = true
		rch <- true
	}
	nc, err := opts.Connect()
	if err != nil {
		t.Fatalf("Should have connected ok: %v", err)
	}
	ec, err := NewEncodedConn(nc, "default")
	if err != nil {
		t.Fatalf("Failed to create an encoded connection: %v\n", err)
	}
	testString := "bar"
	received := 0

	ec.Subscribe("foo", func(s string) {
		received += 1
	})

	sub, _ := ec.Subscribe("foobar", func(s string) {
		received += 1
	})

	ec.Publish("foo", testString)
	ec.Flush()

	ts.stopServer()
	// server is stopped here..

	// Sub while disconnected
	ec.Subscribe("bar", func(s string) {
		received += 1
	})

	// Unsub while disconnected
	sub.Unsubscribe()

	if err = ec.Publish("foo", testString); err != nil {
		t.Fatalf("Got an error after disconnect: %v\n", err)
	}

	if err = ec.Publish("bar", testString); err != nil {
		t.Fatalf("Got an error after disconnect: %v\n", err)
	}

	ts = startReconnectServer(t)
	defer ts.stopServer()

	// server is restarted here..
	// wait for reconnect
	wait(rch)

	if err = ec.Publish("foobar", testString); err != nil {
		t.Fatalf("Got an error after server restarted: %v\n", err)
	}

	if err = ec.Publish("foo", testString); err != nil {
		t.Fatalf("Got an error after server restarted: %v\n", err)
	}

	ch := make(chan bool)
	ec.Subscribe("done", func(b bool) {
		ch <- true
	})
	ec.Publish("done", true)

	if e := wait(ch); e != nil {
		t.Fatal("Did not receive our message")
	}

	if received != 4 {
		t.Fatalf("Received != %d, equals %d\n", 4, received)
	}
	if !cbCalled {
		t.Fatal("Did not have DisconnectedCB called")
	}
	if !rcbCalled {
		t.Fatal("Did not have ReconnectedCB called")
	}
}

func TestRemoveLogFile(t *testing.T) {
	if logFile != _EMPTY_ {
		os.Remove(logFile)
	}
}
<|endoftext|>