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

package lxc

import (
	"bytes"
	"github.com/globocom/commandmocker"
	"github.com/globocom/config"
	etesting "github.com/globocom/tsuru/exec/testing"
	fstesting "github.com/globocom/tsuru/fs/testing"
	"github.com/globocom/tsuru/provision"
	rtesting "github.com/globocom/tsuru/router/testing"
	"github.com/globocom/tsuru/testing"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"launchpad.net/gocheck"
	"net"
	"os"
	"runtime"
	"time"
)

func (s *S) TestShouldBeRegistered(c *gocheck.C) {
	p, err := provision.Get("lxc")
	c.Assert(err, gocheck.IsNil)
	c.Assert(p, gocheck.FitsTypeOf, &LXCProvisioner{})
}

func (s *S) TestProvisionerProvision(c *gocheck.C) {
	fexec := &etesting.FakeExecutor{}
	execut = fexec
	defer func() {
		execut = nil
	}()
	ln, err := net.Listen("tcp", ":2222")
	c.Assert(err, gocheck.IsNil)
	defer ln.Close()
	formulasPath := "/home/ubuntu/formulas"
	config.Set("lxc:formulas-path", formulasPath)
	config.Set("lxc:ip-timeout", 5)
	config.Set("lxc:ssh-port", 2222)
	config.Set("lxc:authorized-key-path", "somepath")
	rfs := &fstesting.RecordingFs{}
	fsystem = rfs
	defer func() {
		fsystem = nil
	}()
	f, _ := os.Open("testdata/dnsmasq.leases")
	data, err := ioutil.ReadAll(f)
	c.Assert(err, gocheck.IsNil)
	file, err := rfs.Create("/var/lib/misc/dnsmasq.leases")
	c.Assert(err, gocheck.IsNil)
	_, err = file.Write(data)
	c.Assert(err, gocheck.IsNil)
	var p LXCProvisioner
	app := testing.NewFakeApp("myapp", "python", 0)
	defer p.collection().Remove(bson.M{"name": "myapp"})
	c.Assert(p.Provision(app), gocheck.IsNil)
	ok := make(chan bool, 1)
	go func() {
		for {
			coll := s.conn.Collection(s.collName)
			ct, err := coll.Find(bson.M{"name": "myapp", "status": provision.StatusStarted}).Count()
			if err != nil {
				c.Fatal(err)
			}
			if ct > 0 {
				ok <- true
				return
			}
			runtime.Gosched()
		}
	}()
	select {
	case <-ok:
	case <-time.After(10e9):
		c.Fatal("Timed out waiting for the container to be provisioned (10 seconds)")
	}
	args := []string{"lxc-create", "-t", "ubuntu-cloud", "-n", "myapp", "--", "-S", "somepath"}
	c.Assert(fexec.ExecutedCmd("sudo", args), gocheck.Equals, true)
	args = []string{"lxc-start", "--daemon", "-n", "myapp"}
	c.Assert(fexec.ExecutedCmd("sudo", args), gocheck.Equals, true)
	r, err := p.router()
	c.Assert(err, gocheck.IsNil)
	fk := r.(*rtesting.FakeRouter)
	c.Assert(fk.HasRoute("myapp"), gocheck.Equals, true)
	var unit provision.Unit
	err = s.conn.Collection(s.collName).Find(bson.M{"name": "myapp"}).One(&unit)
	c.Assert(err, gocheck.IsNil)
	c.Assert(unit.Ip, gocheck.Equals, "127.0.0.1")
}

func (s *S) TestProvisionerRestart(c *gocheck.C) {
	fexec := &etesting.FakeExecutor{}
	execut = fexec
	defer func() {
		execut = nil
	}()
	var p LXCProvisioner
	app := testing.NewFakeApp("almah", "static", 1)
	err := p.Restart(app)
	c.Assert(err, gocheck.IsNil)
	args := []string{"-l", "ubuntu", "-q", "-o", "StrictHostKeyChecking no", "10.10.10.1", "/var/lib/tsuru/hooks/restart"}
	c.Assert(fexec.ExecutedCmd("ssh", args), gocheck.Equals, true)
}

// func (s *S) TestProvisionerRestartFailure(c *gocheck.C) {
// 	app := testing.NewFakeApp("cribcaged", "python", 1)
// 	p := LXCProvisioner{}
// 	err := p.Restart(app)
// 	c.Assert(err, gocheck.NotNil)
// 	_, ok := err.(*provision.Error)
// 	c.Assert(ok, gocheck.Equals, true)
// }

func (s *S) TestDeploy(c *gocheck.C) {
	tmpdir, err := commandmocker.Add("ssh", "")
	c.Assert(err, gocheck.IsNil)
	defer commandmocker.Remove(tmpdir)
	config.Set("git:unit-repo", "test/dir")
	config.Set("git:host", "gandalf.com")
	defer func() {
		config.Unset("git:unit-repo")
		config.Unset("git:host")
	}()
	app := testing.NewFakeApp("cribcaged", "python", 1)
	w := &bytes.Buffer{}
	p := LXCProvisioner{}
	err = p.Deploy(app, w)
	c.Assert(err, gocheck.IsNil)
}

func (s *S) TestProvisionerDestroy(c *gocheck.C) {
	fexec := &etesting.FakeExecutor{}
	execut = fexec
	defer func() {
		execut = nil
	}()
	var p LXCProvisioner
	app := testing.NewFakeApp("myapp", "python", 1)
	u := provision.Unit{
		Name:   "myapp",
		Status: provision.StatusStarted,
	}
	err := s.conn.Collection(s.collName).Insert(&u)
	c.Assert(err, gocheck.IsNil)
	c.Assert(p.Destroy(app), gocheck.IsNil)
	ok := make(chan bool, 1)
	go func() {
		for {
			coll := s.conn.Collection(s.collName)
			ct, err := coll.Find(bson.M{"name": "myapp", "status": provision.StatusStarted}).Count()
			if err != nil {
				c.Fatal(err)
			}
			if ct == 0 {
				ok <- true
				return
			}
			runtime.Gosched()
		}
	}()
	select {
	case <-ok:
	case <-time.After(10e9):
		c.Fatal("Timed out waiting for the container to be provisioned (10 seconds)")
	}
	c.Assert(err, gocheck.IsNil)
	args := []string{"lxc-stop", "-n", "myapp"}
	c.Assert(fexec.ExecutedCmd("sudo", args), gocheck.Equals, true)
	args = []string{"lxc-destroy", "-n", "myapp"}
	c.Assert(fexec.ExecutedCmd("sudo", args), gocheck.Equals, true)
	length, err := p.collection().Find(bson.M{"name": "myapp"}).Count()
	c.Assert(err, gocheck.IsNil)
	c.Assert(length, gocheck.Equals, 0)
}

func (s *S) TestProvisionerAddr(c *gocheck.C) {
	config.Set("router", "fake")
	var p LXCProvisioner
	app := testing.NewFakeApp("myapp", "python", 1)
	r, err := p.router()
	c.Assert(err, gocheck.IsNil)
	r.AddRoute("myapp", "http://10.10.10.10")
	a, err := r.Addr(app.GetName())
	c.Assert(err, gocheck.IsNil)
	addr, err := p.Addr(app)
	c.Assert(err, gocheck.IsNil)
	c.Assert(addr, gocheck.Equals, a)
}

func (s *S) TestProvisionerAddUnits(c *gocheck.C) {
	var p LXCProvisioner
	app := testing.NewFakeApp("myapp", "python", 0)
	units, err := p.AddUnits(app, 2)
	c.Assert(err, gocheck.IsNil)
	c.Assert(units, gocheck.DeepEquals, []provision.Unit{})
}

func (s *S) TestProvisionerRemoveUnit(c *gocheck.C) {
	var p LXCProvisioner
	app := testing.NewFakeApp("myapp", "python", 0)
	err := p.RemoveUnit(app, "")
	c.Assert(err, gocheck.IsNil)
}

func (s *S) TestProvisionerInstallDepsExecutesHook(c *gocheck.C) {
	var p LXCProvisioner
	app := testing.NewFakeApp("myapp", "python", 0)
	w := &bytes.Buffer{}
	err := p.InstallDeps(app, w)
	c.Assert(err, gocheck.IsNil)
	expected := []string{"ran /var/lib/tsuru/hooks/dependencies"}
	c.Assert(app.Commands, gocheck.DeepEquals, expected)
}

func (s *S) TestProvisionerExecuteCommand(c *gocheck.C) {
	fexec := &etesting.FakeExecutor{}
	execut = fexec
	defer func() {
		execut = nil
	}()
	var p LXCProvisioner
	var buf bytes.Buffer
	app := testing.NewFakeApp("almah", "static", 2)
	err := p.ExecuteCommand(&buf, &buf, app, "ls", "-lh")
	c.Assert(err, gocheck.IsNil)
	args := []string{"-l", "ubuntu", "-q", "-o", "StrictHostKeyChecking no", "10.10.10.1", "ls", "-lh"}
	c.Assert(fexec.ExecutedCmd("ssh", args), gocheck.Equals, true)
}

func (s *S) TestCollectStatus(c *gocheck.C) {
	var p LXCProvisioner
	expected := []provision.Unit{
		{
			Name:       "vm1",
			AppName:    "vm1",
			Type:       "django",
			Machine:    0,
			InstanceId: "vm1",
			Ip:         "10.10.10.9",
			Status:     provision.StatusStarted,
		},
		{
			Name:       "vm2",
			AppName:    "vm2",
			Type:       "gunicorn",
			Machine:    0,
			InstanceId: "vm2",
			Ip:         "10.10.10.10",
			Status:     provision.StatusInstalling,
		},
	}
	for _, u := range expected {
		err := p.collection().Insert(u)
		c.Assert(err, gocheck.IsNil)
	}
	units, err := p.CollectStatus()
	c.Assert(err, gocheck.IsNil)
	c.Assert(units, gocheck.DeepEquals, expected)
}

func (s *S) TestProvisionCollection(c *gocheck.C) {
	var p LXCProvisioner
	collection := p.collection()
	c.Assert(collection.Name, gocheck.Equals, s.collName)
}

func (s *S) TestProvisionInstall(c *gocheck.C) {
	fexec := &etesting.FakeExecutor{}
	execut = fexec
	defer func() {
		execut = nil
	}()
	p := LXCProvisioner{}
	err := p.install("10.10.10.10")
	c.Assert(err, gocheck.IsNil)
	cmd := "ssh"
	args := []string{
		"-q",
		"-o",
		"StrictHostKeyChecking no",
		"-l",
		"ubuntu",
		"10.10.10.10",
		"sudo /var/lib/tsuru/hooks/install",
	}
	c.Assert(fexec.ExecutedCmd(cmd, args), gocheck.Equals, true)
}

func (s *S) TestProvisionStart(c *gocheck.C) {
	fexec := &etesting.FakeExecutor{}
	execut = fexec
	defer func() {
		execut = nil
	}()
	p := LXCProvisioner{}
	err := p.start("10.10.10.10")
	c.Assert(err, gocheck.IsNil)
	cmd := "ssh"
	args := []string{
		"-q",
		"-o",
		"StrictHostKeyChecking no",
		"-l",
		"ubuntu",
		"10.10.10.10",
		"sudo /var/lib/tsuru/hooks/start",
	}
	c.Assert(fexec.ExecutedCmd(cmd, args), gocheck.Equals, true)
}

func (s *S) TestProvisionSetup(c *gocheck.C) {
	fexec := &etesting.FakeExecutor{}
	execut = fexec
	defer func() {
		execut = nil
	}()
	p := LXCProvisioner{}
	formulasPath := "/home/ubuntu/formulas"
	config.Set("lxc:formulas-path", formulasPath)
	err := p.setup("10.10.10.10", "static")
	c.Assert(err, gocheck.IsNil)
	cmd := "scp"
	args := []string{
		"-q",
		"-o",
		"StrictHostKeyChecking no",
		"-r",
		formulasPath + "/static/hooks",
		"ubuntu@10.10.10.10:/var/lib/tsuru",
	}
	c.Assert(fexec.ExecutedCmd(cmd, args), gocheck.Equals, true)
	cmd = "ssh"
	args = []string{
		"-q",
		"-o",
		"StrictHostKeyChecking no",
		"-l",
		"ubuntu",
		"10.10.10.10",
		"sudo mkdir -p /var/lib/tsuru/hooks",
	}
	c.Assert(fexec.ExecutedCmd(cmd, args), gocheck.Equals, true)
	args = []string{
		"-q",
		"-o",
		"StrictHostKeyChecking no",
		"-l",
		"ubuntu",
		"10.10.10.10",
		"sudo chown -R ubuntu /var/lib/tsuru/hooks",
	}
	c.Assert(fexec.ExecutedCmd(cmd, args), gocheck.Equals, true)
}
<commit_msg>provision/lxc: remove commented test<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package lxc

import (
	"bytes"
	"github.com/globocom/commandmocker"
	"github.com/globocom/config"
	etesting "github.com/globocom/tsuru/exec/testing"
	fstesting "github.com/globocom/tsuru/fs/testing"
	"github.com/globocom/tsuru/provision"
	rtesting "github.com/globocom/tsuru/router/testing"
	"github.com/globocom/tsuru/testing"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"launchpad.net/gocheck"
	"net"
	"os"
	"runtime"
	"time"
)

func (s *S) TestShouldBeRegistered(c *gocheck.C) {
	p, err := provision.Get("lxc")
	c.Assert(err, gocheck.IsNil)
	c.Assert(p, gocheck.FitsTypeOf, &LXCProvisioner{})
}

func (s *S) TestProvisionerProvision(c *gocheck.C) {
	fexec := &etesting.FakeExecutor{}
	execut = fexec
	defer func() {
		execut = nil
	}()
	ln, err := net.Listen("tcp", ":2222")
	c.Assert(err, gocheck.IsNil)
	defer ln.Close()
	formulasPath := "/home/ubuntu/formulas"
	config.Set("lxc:formulas-path", formulasPath)
	config.Set("lxc:ip-timeout", 5)
	config.Set("lxc:ssh-port", 2222)
	config.Set("lxc:authorized-key-path", "somepath")
	rfs := &fstesting.RecordingFs{}
	fsystem = rfs
	defer func() {
		fsystem = nil
	}()
	f, _ := os.Open("testdata/dnsmasq.leases")
	data, err := ioutil.ReadAll(f)
	c.Assert(err, gocheck.IsNil)
	file, err := rfs.Create("/var/lib/misc/dnsmasq.leases")
	c.Assert(err, gocheck.IsNil)
	_, err = file.Write(data)
	c.Assert(err, gocheck.IsNil)
	var p LXCProvisioner
	app := testing.NewFakeApp("myapp", "python", 0)
	defer p.collection().Remove(bson.M{"name": "myapp"})
	c.Assert(p.Provision(app), gocheck.IsNil)
	ok := make(chan bool, 1)
	go func() {
		for {
			coll := s.conn.Collection(s.collName)
			ct, err := coll.Find(bson.M{"name": "myapp", "status": provision.StatusStarted}).Count()
			if err != nil {
				c.Fatal(err)
			}
			if ct > 0 {
				ok <- true
				return
			}
			runtime.Gosched()
		}
	}()
	select {
	case <-ok:
	case <-time.After(10e9):
		c.Fatal("Timed out waiting for the container to be provisioned (10 seconds)")
	}
	args := []string{"lxc-create", "-t", "ubuntu-cloud", "-n", "myapp", "--", "-S", "somepath"}
	c.Assert(fexec.ExecutedCmd("sudo", args), gocheck.Equals, true)
	args = []string{"lxc-start", "--daemon", "-n", "myapp"}
	c.Assert(fexec.ExecutedCmd("sudo", args), gocheck.Equals, true)
	r, err := p.router()
	c.Assert(err, gocheck.IsNil)
	fk := r.(*rtesting.FakeRouter)
	c.Assert(fk.HasRoute("myapp"), gocheck.Equals, true)
	var unit provision.Unit
	err = s.conn.Collection(s.collName).Find(bson.M{"name": "myapp"}).One(&unit)
	c.Assert(err, gocheck.IsNil)
	c.Assert(unit.Ip, gocheck.Equals, "127.0.0.1")
}

func (s *S) TestProvisionerRestart(c *gocheck.C) {
	fexec := &etesting.FakeExecutor{}
	execut = fexec
	defer func() {
		execut = nil
	}()
	var p LXCProvisioner
	app := testing.NewFakeApp("almah", "static", 1)
	err := p.Restart(app)
	c.Assert(err, gocheck.IsNil)
	args := []string{"-l", "ubuntu", "-q", "-o", "StrictHostKeyChecking no", "10.10.10.1", "/var/lib/tsuru/hooks/restart"}
	c.Assert(fexec.ExecutedCmd("ssh", args), gocheck.Equals, true)
}

func (s *S) TestDeploy(c *gocheck.C) {
	tmpdir, err := commandmocker.Add("ssh", "")
	c.Assert(err, gocheck.IsNil)
	defer commandmocker.Remove(tmpdir)
	config.Set("git:unit-repo", "test/dir")
	config.Set("git:host", "gandalf.com")
	defer func() {
		config.Unset("git:unit-repo")
		config.Unset("git:host")
	}()
	app := testing.NewFakeApp("cribcaged", "python", 1)
	w := &bytes.Buffer{}
	p := LXCProvisioner{}
	err = p.Deploy(app, w)
	c.Assert(err, gocheck.IsNil)
}

func (s *S) TestProvisionerDestroy(c *gocheck.C) {
	fexec := &etesting.FakeExecutor{}
	execut = fexec
	defer func() {
		execut = nil
	}()
	var p LXCProvisioner
	app := testing.NewFakeApp("myapp", "python", 1)
	u := provision.Unit{
		Name:   "myapp",
		Status: provision.StatusStarted,
	}
	err := s.conn.Collection(s.collName).Insert(&u)
	c.Assert(err, gocheck.IsNil)
	c.Assert(p.Destroy(app), gocheck.IsNil)
	ok := make(chan bool, 1)
	go func() {
		for {
			coll := s.conn.Collection(s.collName)
			ct, err := coll.Find(bson.M{"name": "myapp", "status": provision.StatusStarted}).Count()
			if err != nil {
				c.Fatal(err)
			}
			if ct == 0 {
				ok <- true
				return
			}
			runtime.Gosched()
		}
	}()
	select {
	case <-ok:
	case <-time.After(10e9):
		c.Fatal("Timed out waiting for the container to be provisioned (10 seconds)")
	}
	c.Assert(err, gocheck.IsNil)
	args := []string{"lxc-stop", "-n", "myapp"}
	c.Assert(fexec.ExecutedCmd("sudo", args), gocheck.Equals, true)
	args = []string{"lxc-destroy", "-n", "myapp"}
	c.Assert(fexec.ExecutedCmd("sudo", args), gocheck.Equals, true)
	length, err := p.collection().Find(bson.M{"name": "myapp"}).Count()
	c.Assert(err, gocheck.IsNil)
	c.Assert(length, gocheck.Equals, 0)
}

func (s *S) TestProvisionerAddr(c *gocheck.C) {
	config.Set("router", "fake")
	var p LXCProvisioner
	app := testing.NewFakeApp("myapp", "python", 1)
	r, err := p.router()
	c.Assert(err, gocheck.IsNil)
	r.AddRoute("myapp", "http://10.10.10.10")
	a, err := r.Addr(app.GetName())
	c.Assert(err, gocheck.IsNil)
	addr, err := p.Addr(app)
	c.Assert(err, gocheck.IsNil)
	c.Assert(addr, gocheck.Equals, a)
}

func (s *S) TestProvisionerAddUnits(c *gocheck.C) {
	var p LXCProvisioner
	app := testing.NewFakeApp("myapp", "python", 0)
	units, err := p.AddUnits(app, 2)
	c.Assert(err, gocheck.IsNil)
	c.Assert(units, gocheck.DeepEquals, []provision.Unit{})
}

func (s *S) TestProvisionerRemoveUnit(c *gocheck.C) {
	var p LXCProvisioner
	app := testing.NewFakeApp("myapp", "python", 0)
	err := p.RemoveUnit(app, "")
	c.Assert(err, gocheck.IsNil)
}

func (s *S) TestProvisionerInstallDepsExecutesHook(c *gocheck.C) {
	var p LXCProvisioner
	app := testing.NewFakeApp("myapp", "python", 0)
	w := &bytes.Buffer{}
	err := p.InstallDeps(app, w)
	c.Assert(err, gocheck.IsNil)
	expected := []string{"ran /var/lib/tsuru/hooks/dependencies"}
	c.Assert(app.Commands, gocheck.DeepEquals, expected)
}

func (s *S) TestProvisionerExecuteCommand(c *gocheck.C) {
	fexec := &etesting.FakeExecutor{}
	execut = fexec
	defer func() {
		execut = nil
	}()
	var p LXCProvisioner
	var buf bytes.Buffer
	app := testing.NewFakeApp("almah", "static", 2)
	err := p.ExecuteCommand(&buf, &buf, app, "ls", "-lh")
	c.Assert(err, gocheck.IsNil)
	args := []string{"-l", "ubuntu", "-q", "-o", "StrictHostKeyChecking no", "10.10.10.1", "ls", "-lh"}
	c.Assert(fexec.ExecutedCmd("ssh", args), gocheck.Equals, true)
}

func (s *S) TestCollectStatus(c *gocheck.C) {
	var p LXCProvisioner
	expected := []provision.Unit{
		{
			Name:       "vm1",
			AppName:    "vm1",
			Type:       "django",
			Machine:    0,
			InstanceId: "vm1",
			Ip:         "10.10.10.9",
			Status:     provision.StatusStarted,
		},
		{
			Name:       "vm2",
			AppName:    "vm2",
			Type:       "gunicorn",
			Machine:    0,
			InstanceId: "vm2",
			Ip:         "10.10.10.10",
			Status:     provision.StatusInstalling,
		},
	}
	for _, u := range expected {
		err := p.collection().Insert(u)
		c.Assert(err, gocheck.IsNil)
	}
	units, err := p.CollectStatus()
	c.Assert(err, gocheck.IsNil)
	c.Assert(units, gocheck.DeepEquals, expected)
}

func (s *S) TestProvisionCollection(c *gocheck.C) {
	var p LXCProvisioner
	collection := p.collection()
	c.Assert(collection.Name, gocheck.Equals, s.collName)
}

func (s *S) TestProvisionInstall(c *gocheck.C) {
	fexec := &etesting.FakeExecutor{}
	execut = fexec
	defer func() {
		execut = nil
	}()
	p := LXCProvisioner{}
	err := p.install("10.10.10.10")
	c.Assert(err, gocheck.IsNil)
	cmd := "ssh"
	args := []string{
		"-q",
		"-o",
		"StrictHostKeyChecking no",
		"-l",
		"ubuntu",
		"10.10.10.10",
		"sudo /var/lib/tsuru/hooks/install",
	}
	c.Assert(fexec.ExecutedCmd(cmd, args), gocheck.Equals, true)
}

func (s *S) TestProvisionStart(c *gocheck.C) {
	fexec := &etesting.FakeExecutor{}
	execut = fexec
	defer func() {
		execut = nil
	}()
	p := LXCProvisioner{}
	err := p.start("10.10.10.10")
	c.Assert(err, gocheck.IsNil)
	cmd := "ssh"
	args := []string{
		"-q",
		"-o",
		"StrictHostKeyChecking no",
		"-l",
		"ubuntu",
		"10.10.10.10",
		"sudo /var/lib/tsuru/hooks/start",
	}
	c.Assert(fexec.ExecutedCmd(cmd, args), gocheck.Equals, true)
}

func (s *S) TestProvisionSetup(c *gocheck.C) {
	fexec := &etesting.FakeExecutor{}
	execut = fexec
	defer func() {
		execut = nil
	}()
	p := LXCProvisioner{}
	formulasPath := "/home/ubuntu/formulas"
	config.Set("lxc:formulas-path", formulasPath)
	err := p.setup("10.10.10.10", "static")
	c.Assert(err, gocheck.IsNil)
	cmd := "scp"
	args := []string{
		"-q",
		"-o",
		"StrictHostKeyChecking no",
		"-r",
		formulasPath + "/static/hooks",
		"ubuntu@10.10.10.10:/var/lib/tsuru",
	}
	c.Assert(fexec.ExecutedCmd(cmd, args), gocheck.Equals, true)
	cmd = "ssh"
	args = []string{
		"-q",
		"-o",
		"StrictHostKeyChecking no",
		"-l",
		"ubuntu",
		"10.10.10.10",
		"sudo mkdir -p /var/lib/tsuru/hooks",
	}
	c.Assert(fexec.ExecutedCmd(cmd, args), gocheck.Equals, true)
	args = []string{
		"-q",
		"-o",
		"StrictHostKeyChecking no",
		"-l",
		"ubuntu",
		"10.10.10.10",
		"sudo chown -R ubuntu /var/lib/tsuru/hooks",
	}
	c.Assert(fexec.ExecutedCmd(cmd, args), gocheck.Equals, true)
}
<|endoftext|>


<commit_before>package rbt

import "fmt"

type color bool

const (
	red   color = true
	black color = false
)

type Ordered interface {
	Less(Ordered) bool
}

type node struct {
	color       color
	value       Ordered
	left, right *node
}

func newNode(c color, o Ordered, l, r *node) *node {
	return &node{
		color: c,
		value: o,
		left:  l,
		right: r,
	}
}

func (n *node) insert(o Ordered) *node {
	m := *n.insertRed(o)
	m.color = black
	return &m
}

func (n *node) insertRed(o Ordered) *node {
	if n == nil {
		return newNode(red, o, nil, nil)
	}

	m := *n

	if n.value.Less(o) {
		m.left = m.left.insertRed(o)
	} else if o.Less(n.value) {
		m.right = m.right.insertRed(o)
	} else {
		return n
	}

	return m.balance()
}

func (n *node) balance() *node {
	if n.color == red {
		return n
	}

	newN := func(
		o Ordered,
		lo Ordered, ll, lr *node,
		ro Ordered, rl, rr *node) *node {
		return newNode(red, o, newNode(black, lo, ll, lr), newNode(black, ro, rl, rr))
	}

	l := n.left
	r := n.right

	if l != nil && l.color == red {
		ll := l.left
		lr := l.right

		newLN := func(o, lo Ordered, ll, lr, rl *node) *node {
			return newN(o, lo, ll, lr, n.value, rl, r)
		}

		if ll != nil && ll.color == red {
			return newLN(l.value, ll.value, ll.left, ll.right, lr)
		} else if lr != nil && lr.color == red {
			return newLN(lr.value, l.value, ll, lr.left, lr.right)
		}
	} else if r != nil && r.color == red {
		rl := r.left
		rr := r.right

		newRN := func(o, ro Ordered, lr, rl, rr *node) *node {
			return newN(o, n.value, l, lr, ro, rl, rr)
		}

		if rl != nil && rl.color == red {
			return newRN(r.value, rr.value, rl, rr.left, rr.right)
		} else if rr != nil && rr.color == red {
			return newRN(rl.value, r.value, rl.left, rl.right, rr)
		}
	}

	return n
}

func (n *node) search(o Ordered) (Ordered, bool) {
	if n == nil {
		return nil, false
	} else if n.value.Less(o) {
		return n.left.search(o)
	} else if o.Less(n.value) {
		return n.right.search(o)
	}

	return n.value, true
}

func (n *node) remove(o Ordered) (*node, bool) {
	_, ok := n.search(o)

	if !ok {
		return n, false
	}

	n, _ = n.removeOne(o)
	m := *n
	m.color = black
	return &m, true
}

func (n *node) removeOne(o Ordered) (*node, bool) {
	if n == nil {
		return nil, true
	} else if n.value.Less(o) {
		l, balanced := n.left.removeOne(o)
		m := *n
		m.left = l

		if balanced {
			return &m, true
		}

		return m.balanceLeft()
	} else if o.Less(n.value) {
		r, balanced := n.right.removeOne(o)
		m := *n
		m.right = r

		if balanced {
			return &m, true
		}

		return m.balanceRight()
	}

	if n.left == nil {
		return n.right, n.color == red
	}

	o, l, balanced := n.takeMax()

	m := newNode(n.color, o, l, n.right)

	if balanced {
		return m, true
	}

	return m.balanceLeft()
}

func (n *node) takeMax() (Ordered, *node, bool) {
	if n.right == nil {
		return n.value, n.left, n.color == red
	}

	o, r, balanced := n.right.takeMax()

	m := *n
	m.right = r

	if balanced {
		return o, &m, true
	}

	n, balanced = m.balanceRight()
	return o, n, balanced
}

func (n *node) balanceLeft() (*node, bool) {
	if n.right.color == red {
		l, _ := newNode(red, n.value, n.left, n.right.left).balanceLeft()
		return newNode(black, n.right.value, l, n.right.right), true
	}

	if n.right.left != nil && n.right.left.color == red {
		return newNode(
			n.color,
			n.right.left.value,
			newNode(black, n.value, n.left, n.right.left.left),
			newNode(black, n.right.value, n.right.left.right, n.right.right)), true
	} else if n.right.right != nil && n.right.right.color == red {
		r := *n.right.right
		r.color = black

		return newNode(
			n.color,
			n.right.value,
			newNode(black, n.value, n.left, n.right.left),
			&r), true
	}

	r := *n.right
	r.color = red

	m := *n
	m.color = black
	m.right = &r

	return &m, n.color == black
}

func (n *node) balanceRight() (*node, bool) {
	if n.left.color == red {
		r, _ := newNode(red, n.value, n.left.right, n.right).balanceRight()
		return newNode(black, n.left.value, n.left.left, r), true
	}

	if n.left.right != nil && n.left.right.color == red {
		return newNode(
			n.color,
			n.left.right.value,
			newNode(black, n.left.value, n.left.left, n.left.right.left),
			newNode(black, n.value, n.left.right.right, n.right)), true
	} else if n.left.left != nil && n.left.left.color == red {
		l := *n.left.left
		l.color = black

		return newNode(
			n.color,
			n.left.value,
			&l,
			newNode(black, n.value, n.left.right, n.right)), true
	}

	l := *n.left
	l.color = red

	m := *n
	m.color = black
	m.left = &l

	return &m, n.color == black
}

func (n *node) dump() {
	n.dumpWithIndent(0)
}

func (n *node) dumpWithIndent(i int) {
	for j := 0; j < i; j++ {
		fmt.Printf(" ")
	}

	if n == nil {
		fmt.Println(nil)
		return
	}

	fmt.Println(n.color, n.value)

	k := i + 2
	n.left.dumpWithIndent(k)
	n.right.dumpWithIndent(k)
}
<commit_msg>Change dump order<commit_after>package rbt

import "fmt"

type color bool

const (
	red   color = true
	black color = false
)

type Ordered interface {
	Less(Ordered) bool
}

type node struct {
	color       color
	value       Ordered
	left, right *node
}

func newNode(c color, o Ordered, l, r *node) *node {
	return &node{
		color: c,
		value: o,
		left:  l,
		right: r,
	}
}

func (n *node) insert(o Ordered) *node {
	m := *n.insertRed(o)
	m.color = black
	return &m
}

func (n *node) insertRed(o Ordered) *node {
	if n == nil {
		return newNode(red, o, nil, nil)
	}

	m := *n

	if n.value.Less(o) {
		m.left = m.left.insertRed(o)
	} else if o.Less(n.value) {
		m.right = m.right.insertRed(o)
	} else {
		return n
	}

	return m.balance()
}

func (n *node) balance() *node {
	if n.color == red {
		return n
	}

	newN := func(
		o Ordered,
		lo Ordered, ll, lr *node,
		ro Ordered, rl, rr *node) *node {
		return newNode(red, o, newNode(black, lo, ll, lr), newNode(black, ro, rl, rr))
	}

	l := n.left
	r := n.right

	if l != nil && l.color == red {
		ll := l.left
		lr := l.right

		newLN := func(o, lo Ordered, ll, lr, rl *node) *node {
			return newN(o, lo, ll, lr, n.value, rl, r)
		}

		if ll != nil && ll.color == red {
			return newLN(l.value, ll.value, ll.left, ll.right, lr)
		} else if lr != nil && lr.color == red {
			return newLN(lr.value, l.value, ll, lr.left, lr.right)
		}
	} else if r != nil && r.color == red {
		rl := r.left
		rr := r.right

		newRN := func(o, ro Ordered, lr, rl, rr *node) *node {
			return newN(o, n.value, l, lr, ro, rl, rr)
		}

		if rl != nil && rl.color == red {
			return newRN(r.value, rr.value, rl, rr.left, rr.right)
		} else if rr != nil && rr.color == red {
			return newRN(rl.value, r.value, rl.left, rl.right, rr)
		}
	}

	return n
}

func (n *node) search(o Ordered) (Ordered, bool) {
	if n == nil {
		return nil, false
	} else if n.value.Less(o) {
		return n.left.search(o)
	} else if o.Less(n.value) {
		return n.right.search(o)
	}

	return n.value, true
}

func (n *node) remove(o Ordered) (*node, bool) {
	_, ok := n.search(o)

	if !ok {
		return n, false
	}

	n, _ = n.removeOne(o)
	m := *n
	m.color = black
	return &m, true
}

func (n *node) removeOne(o Ordered) (*node, bool) {
	if n == nil {
		return nil, true
	} else if n.value.Less(o) {
		l, balanced := n.left.removeOne(o)
		m := *n
		m.left = l

		if balanced {
			return &m, true
		}

		return m.balanceLeft()
	} else if o.Less(n.value) {
		r, balanced := n.right.removeOne(o)
		m := *n
		m.right = r

		if balanced {
			return &m, true
		}

		return m.balanceRight()
	}

	if n.left == nil {
		return n.right, n.color == red
	}

	o, l, balanced := n.takeMax()

	m := newNode(n.color, o, l, n.right)

	if balanced {
		return m, true
	}

	return m.balanceLeft()
}

func (n *node) takeMax() (Ordered, *node, bool) {
	if n.right == nil {
		return n.value, n.left, n.color == red
	}

	o, r, balanced := n.right.takeMax()

	m := *n
	m.right = r

	if balanced {
		return o, &m, true
	}

	n, balanced = m.balanceRight()
	return o, n, balanced
}

func (n *node) balanceLeft() (*node, bool) {
	if n.right.color == red {
		l, _ := newNode(red, n.value, n.left, n.right.left).balanceLeft()
		return newNode(black, n.right.value, l, n.right.right), true
	}

	if n.right.left != nil && n.right.left.color == red {
		return newNode(
			n.color,
			n.right.left.value,
			newNode(black, n.value, n.left, n.right.left.left),
			newNode(black, n.right.value, n.right.left.right, n.right.right)), true
	} else if n.right.right != nil && n.right.right.color == red {
		r := *n.right.right
		r.color = black

		return newNode(
			n.color,
			n.right.value,
			newNode(black, n.value, n.left, n.right.left),
			&r), true
	}

	r := *n.right
	r.color = red

	m := *n
	m.color = black
	m.right = &r

	return &m, n.color == black
}

func (n *node) balanceRight() (*node, bool) {
	if n.left.color == red {
		r, _ := newNode(red, n.value, n.left.right, n.right).balanceRight()
		return newNode(black, n.left.value, n.left.left, r), true
	}

	if n.left.right != nil && n.left.right.color == red {
		return newNode(
			n.color,
			n.left.right.value,
			newNode(black, n.left.value, n.left.left, n.left.right.left),
			newNode(black, n.value, n.left.right.right, n.right)), true
	} else if n.left.left != nil && n.left.left.color == red {
		l := *n.left.left
		l.color = black

		return newNode(
			n.color,
			n.left.value,
			&l,
			newNode(black, n.value, n.left.right, n.right)), true
	}

	l := *n.left
	l.color = red

	m := *n
	m.color = black
	m.left = &l

	return &m, n.color == black
}

func (n *node) dump() {
	n.dumpWithIndent(0)
}

func (n *node) dumpWithIndent(i int) {
	for j := 0; j < i; j++ {
		fmt.Printf(" ")
	}

	if n == nil {
		fmt.Println(nil)
		return
	}

	fmt.Println(n.color, n.value)

	k := i + 2
	n.right.dumpWithIndent(k)
	n.left.dumpWithIndent(k)
}
<|endoftext|>


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

package testing

export type Test struct {
	name string;
	f *() bool;
}

export func Main(tests *[]Test) {
	ok := true;
	for i := 0; i < len(tests); i++ {
		ok1 := tests[i].f();
		status := "FAIL";
		if ok1 {
			status = "PASS"
		}
		ok = ok && ok1;
		println(status, tests[i].name);
	}
	if !ok {
		sys.exit(1);
	}
}
<commit_msg>add -chatty flag to test. was supposed to be in some other cl but got dropped.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package testing

import (
	"flag"
)

var chatty bool;
func init() {
	flag.Bool("chatty", false, &chatty, "chatty");
}

export type Test struct {
	name string;
	f *() bool;
}

export func Main(tests *[]Test) {
	flag.Parse();
	ok := true;
	for i := 0; i < len(tests); i++ {
		if chatty {
			println("=== RUN ", tests[i].name);
		}
		ok1 := tests[i].f();
		if !ok1 {
			ok = false;
			println("--- FAIL", tests[i].name);
		} else if chatty {
			println("--- PASS", tests[i].name);
		}
	}
	if !ok {
		sys.exit(1);
	}
	println("PASS");
}
<|endoftext|>


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

// This file implements the knownFormats map which records the valid
// formats for a given type. The valid formats must correspond to
// supported compiler formats implemented in fmt.go, or whatever
// other format verbs are implemented for the given type. The map may
// also be used to change the use of a format verb across all compiler
// sources automatically (for instance, if the implementation of fmt.go
// changes), by using the -r option together with the new formats in the
// map. To generate this file automatically from the existing source,
// run: go test -run Formats -u.
//
// See the package comment in fmt_test.go for additional information.

package main_test

// knownFormats entries are of the form "typename format" -> "newformat".
// An absent entry means that the format is not recognized as valid.
// An empty new format means that the format should remain unchanged.
var knownFormats = map[string]string{
	"*bytes.Buffer %s":                                "",
	"*cmd/compile/internal/gc.Mpflt %v":               "",
	"*cmd/compile/internal/gc.Mpint %v":               "",
	"*cmd/compile/internal/gc.Node %#v":               "",
	"*cmd/compile/internal/gc.Node %+S":               "",
	"*cmd/compile/internal/gc.Node %+v":               "",
	"*cmd/compile/internal/gc.Node %0j":               "",
	"*cmd/compile/internal/gc.Node %L":                "",
	"*cmd/compile/internal/gc.Node %S":                "",
	"*cmd/compile/internal/gc.Node %j":                "",
	"*cmd/compile/internal/gc.Node %p":                "",
	"*cmd/compile/internal/gc.Node %v":                "",
	"*cmd/compile/internal/ssa.Block %s":              "",
	"*cmd/compile/internal/ssa.Block %v":              "",
	"*cmd/compile/internal/ssa.Func %s":               "",
	"*cmd/compile/internal/ssa.Func %v":               "",
	"*cmd/compile/internal/ssa.Register %s":           "",
	"*cmd/compile/internal/ssa.Register %v":           "",
	"*cmd/compile/internal/ssa.SparseTreeNode %v":     "",
	"*cmd/compile/internal/ssa.Value %s":              "",
	"*cmd/compile/internal/ssa.Value %v":              "",
	"*cmd/compile/internal/ssa.sparseTreeMapEntry %v": "",
	"*cmd/compile/internal/types.Field %p":            "",
	"*cmd/compile/internal/types.Field %v":            "",
	"*cmd/compile/internal/types.Sym %0S":             "",
	"*cmd/compile/internal/types.Sym %S":              "",
	"*cmd/compile/internal/types.Sym %p":              "",
	"*cmd/compile/internal/types.Sym %v":              "",
	"*cmd/compile/internal/types.Type %#L":            "",
	"*cmd/compile/internal/types.Type %#v":            "",
	"*cmd/compile/internal/types.Type %+v":            "",
	"*cmd/compile/internal/types.Type %-S":            "",
	"*cmd/compile/internal/types.Type %0S":            "",
	"*cmd/compile/internal/types.Type %L":             "",
	"*cmd/compile/internal/types.Type %S":             "",
	"*cmd/compile/internal/types.Type %p":             "",
	"*cmd/compile/internal/types.Type %s":             "",
	"*cmd/compile/internal/types.Type %v":             "",
	"*cmd/internal/obj.Addr %v":                       "",
	"*cmd/internal/obj.LSym %v":                       "",
	"*math/big.Float %f":                              "",
	"*math/big.Int %#x":                               "",
	"*math/big.Int %s":                                "",
	"*math/big.Int %v":                                "",
	"[16]byte %x":                                     "",
	"[]*cmd/compile/internal/gc.Node %v":              "",
	"[]*cmd/compile/internal/ssa.Block %v":            "",
	"[]*cmd/compile/internal/ssa.Value %v":            "",
	"[][]string %q":                                   "",
	"[]byte %s":                                       "",
	"[]byte %x":                                       "",
	"[]cmd/compile/internal/ssa.Edge %v":              "",
	"[]cmd/compile/internal/ssa.ID %v":                "",
	"[]cmd/compile/internal/ssa.posetNode %v":         "",
	"[]cmd/compile/internal/ssa.posetUndo %v":         "",
	"[]cmd/compile/internal/syntax.token %s":          "",
	"[]string %v":                                     "",
	"[]uint32 %v":                                     "",
	"bool %v":                                         "",
	"byte %08b":                                       "",
	"byte %c":                                         "",
	"byte %q":                                         "",
	"byte %v":                                         "",
	"cmd/compile/internal/arm.shift %d":               "",
	"cmd/compile/internal/gc.Class %d":                "",
	"cmd/compile/internal/gc.Class %s":                "",
	"cmd/compile/internal/gc.Class %v":                "",
	"cmd/compile/internal/gc.Ctype %d":                "",
	"cmd/compile/internal/gc.Ctype %v":                "",
	"cmd/compile/internal/gc.Level %d":                "",
	"cmd/compile/internal/gc.Level %v":                "",
	"cmd/compile/internal/gc.Nodes %#v":               "",
	"cmd/compile/internal/gc.Nodes %+v":               "",
	"cmd/compile/internal/gc.Nodes %.v":               "",
	"cmd/compile/internal/gc.Nodes %v":                "",
	"cmd/compile/internal/gc.Op %#v":                  "",
	"cmd/compile/internal/gc.Op %v":                   "",
	"cmd/compile/internal/gc.Val %#v":                 "",
	"cmd/compile/internal/gc.Val %T":                  "",
	"cmd/compile/internal/gc.Val %v":                  "",
	"cmd/compile/internal/gc.fmtMode %d":              "",
	"cmd/compile/internal/gc.initKind %d":             "",
	"cmd/compile/internal/gc.itag %v":                 "",
	"cmd/compile/internal/ssa.BranchPrediction %d":    "",
	"cmd/compile/internal/ssa.Edge %v":                "",
	"cmd/compile/internal/ssa.GCNode %v":              "",
	"cmd/compile/internal/ssa.ID %d":                  "",
	"cmd/compile/internal/ssa.ID %v":                  "",
	"cmd/compile/internal/ssa.LocPair %s":             "",
	"cmd/compile/internal/ssa.LocalSlot %s":           "",
	"cmd/compile/internal/ssa.LocalSlot %v":           "",
	"cmd/compile/internal/ssa.Location %T":            "",
	"cmd/compile/internal/ssa.Location %s":            "",
	"cmd/compile/internal/ssa.Op %s":                  "",
	"cmd/compile/internal/ssa.Op %v":                  "",
	"cmd/compile/internal/ssa.ValAndOff %s":           "",
	"cmd/compile/internal/ssa.domain %v":              "",
	"cmd/compile/internal/ssa.posetNode %v":           "",
	"cmd/compile/internal/ssa.posetTestOp %v":         "",
	"cmd/compile/internal/ssa.rbrank %d":              "",
	"cmd/compile/internal/ssa.regMask %d":             "",
	"cmd/compile/internal/ssa.register %d":            "",
	"cmd/compile/internal/ssa.relation %s":            "",
	"cmd/compile/internal/syntax.Error %q":            "",
	"cmd/compile/internal/syntax.Expr %#v":            "",
	"cmd/compile/internal/syntax.LitKind %d":          "",
	"cmd/compile/internal/syntax.Node %T":             "",
	"cmd/compile/internal/syntax.Operator %s":         "",
	"cmd/compile/internal/syntax.Pos %s":              "",
	"cmd/compile/internal/syntax.Pos %v":              "",
	"cmd/compile/internal/syntax.position %s":         "",
	"cmd/compile/internal/syntax.token %q":            "",
	"cmd/compile/internal/syntax.token %s":            "",
	"cmd/compile/internal/types.EType %d":             "",
	"cmd/compile/internal/types.EType %s":             "",
	"cmd/compile/internal/types.EType %v":             "",
	"cmd/internal/obj.ABI %v":                         "",
	"error %v":                                        "",
	"float64 %.2f":                                    "",
	"float64 %.3f":                                    "",
	"float64 %.6g":                                    "",
	"float64 %g":                                      "",
	"int %-12d":                                       "",
	"int %-6d":                                        "",
	"int %-8o":                                        "",
	"int %02d":                                        "",
	"int %6d":                                         "",
	"int %c":                                          "",
	"int %d":                                          "",
	"int %v":                                          "",
	"int %x":                                          "",
	"int16 %d":                                        "",
	"int16 %x":                                        "",
	"int32 %d":                                        "",
	"int32 %v":                                        "",
	"int32 %x":                                        "",
	"int64 %+d":                                       "",
	"int64 %-10d":                                     "",
	"int64 %.5d":                                      "",
	"int64 %X":                                        "",
	"int64 %d":                                        "",
	"int64 %v":                                        "",
	"int64 %x":                                        "",
	"int8 %d":                                         "",
	"int8 %x":                                         "",
	"interface{} %#v":                                 "",
	"interface{} %T":                                  "",
	"interface{} %p":                                  "",
	"interface{} %q":                                  "",
	"interface{} %s":                                  "",
	"interface{} %v":                                  "",
	"map[*cmd/compile/internal/gc.Node]*cmd/compile/internal/ssa.Value %v": "",
	"map[cmd/compile/internal/ssa.ID]uint32 %v":                            "",
	"math/big.Accuracy %s":                                                 "",
	"reflect.Type %s":                                                      "",
	"rune %#U":                                                             "",
	"rune %c":                                                              "",
	"rune %q":                                                              "",
	"string %-*s":                                                          "",
	"string %-16s":                                                         "",
	"string %-6s":                                                          "",
	"string %.*s":                                                          "",
	"string %q":                                                            "",
	"string %s":                                                            "",
	"string %v":                                                            "",
	"time.Duration %d":                                                     "",
	"time.Duration %v":                                                     "",
	"uint %04x":                                                            "",
	"uint %5d":                                                             "",
	"uint %d":                                                              "",
	"uint %x":                                                              "",
	"uint16 %d":                                                            "",
	"uint16 %v":                                                            "",
	"uint16 %x":                                                            "",
	"uint32 %#x":                                                           "",
	"uint32 %d":                                                            "",
	"uint32 %v":                                                            "",
	"uint32 %x":                                                            "",
	"uint64 %08x":                                                          "",
	"uint64 %d":                                                            "",
	"uint64 %x":                                                            "",
	"uint8 %d":                                                             "",
	"uint8 %x":                                                             "",
	"uintptr %d":                                                           "",
}
<commit_msg>cmd/compile: fix fmt_test.go after CL 170062<commit_after>// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file implements the knownFormats map which records the valid
// formats for a given type. The valid formats must correspond to
// supported compiler formats implemented in fmt.go, or whatever
// other format verbs are implemented for the given type. The map may
// also be used to change the use of a format verb across all compiler
// sources automatically (for instance, if the implementation of fmt.go
// changes), by using the -r option together with the new formats in the
// map. To generate this file automatically from the existing source,
// run: go test -run Formats -u.
//
// See the package comment in fmt_test.go for additional information.

package main_test

// knownFormats entries are of the form "typename format" -> "newformat".
// An absent entry means that the format is not recognized as valid.
// An empty new format means that the format should remain unchanged.
var knownFormats = map[string]string{
	"*bytes.Buffer %s":                                "",
	"*cmd/compile/internal/gc.Mpflt %v":               "",
	"*cmd/compile/internal/gc.Mpint %v":               "",
	"*cmd/compile/internal/gc.Node %#v":               "",
	"*cmd/compile/internal/gc.Node %+S":               "",
	"*cmd/compile/internal/gc.Node %+v":               "",
	"*cmd/compile/internal/gc.Node %0j":               "",
	"*cmd/compile/internal/gc.Node %L":                "",
	"*cmd/compile/internal/gc.Node %S":                "",
	"*cmd/compile/internal/gc.Node %j":                "",
	"*cmd/compile/internal/gc.Node %p":                "",
	"*cmd/compile/internal/gc.Node %v":                "",
	"*cmd/compile/internal/ssa.Block %s":              "",
	"*cmd/compile/internal/ssa.Block %v":              "",
	"*cmd/compile/internal/ssa.Func %s":               "",
	"*cmd/compile/internal/ssa.Func %v":               "",
	"*cmd/compile/internal/ssa.Register %s":           "",
	"*cmd/compile/internal/ssa.Register %v":           "",
	"*cmd/compile/internal/ssa.SparseTreeNode %v":     "",
	"*cmd/compile/internal/ssa.Value %s":              "",
	"*cmd/compile/internal/ssa.Value %v":              "",
	"*cmd/compile/internal/ssa.sparseTreeMapEntry %v": "",
	"*cmd/compile/internal/types.Field %p":            "",
	"*cmd/compile/internal/types.Field %v":            "",
	"*cmd/compile/internal/types.Sym %0S":             "",
	"*cmd/compile/internal/types.Sym %S":              "",
	"*cmd/compile/internal/types.Sym %p":              "",
	"*cmd/compile/internal/types.Sym %v":              "",
	"*cmd/compile/internal/types.Type %#L":            "",
	"*cmd/compile/internal/types.Type %#v":            "",
	"*cmd/compile/internal/types.Type %+v":            "",
	"*cmd/compile/internal/types.Type %-S":            "",
	"*cmd/compile/internal/types.Type %0S":            "",
	"*cmd/compile/internal/types.Type %L":             "",
	"*cmd/compile/internal/types.Type %S":             "",
	"*cmd/compile/internal/types.Type %p":             "",
	"*cmd/compile/internal/types.Type %s":             "",
	"*cmd/compile/internal/types.Type %v":             "",
	"*cmd/internal/obj.Addr %v":                       "",
	"*cmd/internal/obj.LSym %v":                       "",
	"*math/big.Float %f":                              "",
	"*math/big.Int %#x":                               "",
	"*math/big.Int %s":                                "",
	"*math/big.Int %v":                                "",
	"[16]byte %x":                                     "",
	"[]*cmd/compile/internal/ssa.Block %v":            "",
	"[]*cmd/compile/internal/ssa.Value %v":            "",
	"[][]string %q":                                   "",
	"[]byte %s":                                       "",
	"[]byte %x":                                       "",
	"[]cmd/compile/internal/ssa.Edge %v":              "",
	"[]cmd/compile/internal/ssa.ID %v":                "",
	"[]cmd/compile/internal/ssa.posetNode %v":         "",
	"[]cmd/compile/internal/ssa.posetUndo %v":         "",
	"[]cmd/compile/internal/syntax.token %s":          "",
	"[]string %v":                                     "",
	"[]uint32 %v":                                     "",
	"bool %v":                                         "",
	"byte %08b":                                       "",
	"byte %c":                                         "",
	"byte %q":                                         "",
	"byte %v":                                         "",
	"cmd/compile/internal/arm.shift %d":               "",
	"cmd/compile/internal/gc.Class %d":                "",
	"cmd/compile/internal/gc.Class %s":                "",
	"cmd/compile/internal/gc.Class %v":                "",
	"cmd/compile/internal/gc.Ctype %d":                "",
	"cmd/compile/internal/gc.Ctype %v":                "",
	"cmd/compile/internal/gc.Level %d":                "",
	"cmd/compile/internal/gc.Level %v":                "",
	"cmd/compile/internal/gc.Nodes %#v":               "",
	"cmd/compile/internal/gc.Nodes %+v":               "",
	"cmd/compile/internal/gc.Nodes %.v":               "",
	"cmd/compile/internal/gc.Nodes %v":                "",
	"cmd/compile/internal/gc.Op %#v":                  "",
	"cmd/compile/internal/gc.Op %v":                   "",
	"cmd/compile/internal/gc.Val %#v":                 "",
	"cmd/compile/internal/gc.Val %T":                  "",
	"cmd/compile/internal/gc.Val %v":                  "",
	"cmd/compile/internal/gc.fmtMode %d":              "",
	"cmd/compile/internal/gc.initKind %d":             "",
	"cmd/compile/internal/gc.itag %v":                 "",
	"cmd/compile/internal/ssa.BranchPrediction %d":    "",
	"cmd/compile/internal/ssa.Edge %v":                "",
	"cmd/compile/internal/ssa.GCNode %v":              "",
	"cmd/compile/internal/ssa.ID %d":                  "",
	"cmd/compile/internal/ssa.ID %v":                  "",
	"cmd/compile/internal/ssa.LocPair %s":             "",
	"cmd/compile/internal/ssa.LocalSlot %s":           "",
	"cmd/compile/internal/ssa.LocalSlot %v":           "",
	"cmd/compile/internal/ssa.Location %T":            "",
	"cmd/compile/internal/ssa.Location %s":            "",
	"cmd/compile/internal/ssa.Op %s":                  "",
	"cmd/compile/internal/ssa.Op %v":                  "",
	"cmd/compile/internal/ssa.ValAndOff %s":           "",
	"cmd/compile/internal/ssa.domain %v":              "",
	"cmd/compile/internal/ssa.posetNode %v":           "",
	"cmd/compile/internal/ssa.posetTestOp %v":         "",
	"cmd/compile/internal/ssa.rbrank %d":              "",
	"cmd/compile/internal/ssa.regMask %d":             "",
	"cmd/compile/internal/ssa.register %d":            "",
	"cmd/compile/internal/ssa.relation %s":            "",
	"cmd/compile/internal/syntax.Error %q":            "",
	"cmd/compile/internal/syntax.Expr %#v":            "",
	"cmd/compile/internal/syntax.LitKind %d":          "",
	"cmd/compile/internal/syntax.Node %T":             "",
	"cmd/compile/internal/syntax.Operator %s":         "",
	"cmd/compile/internal/syntax.Pos %s":              "",
	"cmd/compile/internal/syntax.Pos %v":              "",
	"cmd/compile/internal/syntax.position %s":         "",
	"cmd/compile/internal/syntax.token %q":            "",
	"cmd/compile/internal/syntax.token %s":            "",
	"cmd/compile/internal/types.EType %d":             "",
	"cmd/compile/internal/types.EType %s":             "",
	"cmd/compile/internal/types.EType %v":             "",
	"cmd/internal/obj.ABI %v":                         "",
	"error %v":                                        "",
	"float64 %.2f":                                    "",
	"float64 %.3f":                                    "",
	"float64 %.6g":                                    "",
	"float64 %g":                                      "",
	"int %-12d":                                       "",
	"int %-6d":                                        "",
	"int %-8o":                                        "",
	"int %02d":                                        "",
	"int %6d":                                         "",
	"int %c":                                          "",
	"int %d":                                          "",
	"int %v":                                          "",
	"int %x":                                          "",
	"int16 %d":                                        "",
	"int16 %x":                                        "",
	"int32 %d":                                        "",
	"int32 %v":                                        "",
	"int32 %x":                                        "",
	"int64 %+d":                                       "",
	"int64 %-10d":                                     "",
	"int64 %.5d":                                      "",
	"int64 %X":                                        "",
	"int64 %d":                                        "",
	"int64 %v":                                        "",
	"int64 %x":                                        "",
	"int8 %d":                                         "",
	"int8 %x":                                         "",
	"interface{} %#v":                                 "",
	"interface{} %T":                                  "",
	"interface{} %p":                                  "",
	"interface{} %q":                                  "",
	"interface{} %s":                                  "",
	"interface{} %v":                                  "",
	"map[*cmd/compile/internal/gc.Node]*cmd/compile/internal/ssa.Value %v": "",
	"map[*cmd/compile/internal/gc.Node][]*cmd/compile/internal/gc.Node %v": "",
	"map[cmd/compile/internal/ssa.ID]uint32 %v":                            "",
	"math/big.Accuracy %s": "",
	"reflect.Type %s":      "",
	"rune %#U":             "",
	"rune %c":              "",
	"rune %q":              "",
	"string %-*s":          "",
	"string %-16s":         "",
	"string %-6s":          "",
	"string %.*s":          "",
	"string %q":            "",
	"string %s":            "",
	"string %v":            "",
	"time.Duration %d":     "",
	"time.Duration %v":     "",
	"uint %04x":            "",
	"uint %5d":             "",
	"uint %d":              "",
	"uint %x":              "",
	"uint16 %d":            "",
	"uint16 %v":            "",
	"uint16 %x":            "",
	"uint32 %#x":           "",
	"uint32 %d":            "",
	"uint32 %v":            "",
	"uint32 %x":            "",
	"uint64 %08x":          "",
	"uint64 %d":            "",
	"uint64 %x":            "",
	"uint8 %d":             "",
	"uint8 %v":             "",
	"uint8 %x":             "",
	"uintptr %d":           "",
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"

	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/service/autoscaling"
)

func resourceAwsAutoscalingGroup() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsAutoscalingGroupCreate,
		Read:   resourceAwsAutoscalingGroupRead,
		Update: resourceAwsAutoscalingGroupUpdate,
		Delete: resourceAwsAutoscalingGroupDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"launch_configuration": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"desired_capacity": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Computed: true,
			},

			"min_size": &schema.Schema{
				Type:     schema.TypeInt,
				Required: true,
			},

			"max_size": &schema.Schema{
				Type:     schema.TypeInt,
				Required: true,
			},

			"default_cooldown": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},

			"force_delete": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},

			"health_check_grace_period": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},

			"health_check_type": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},

			"availability_zones": &schema.Schema{
				Type:     schema.TypeSet,
				Required: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set: func(v interface{}) int {
					return hashcode.String(v.(string))
				},
			},

			"load_balancers": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set: func(v interface{}) int {
					return hashcode.String(v.(string))
				},
			},

			"vpc_zone_identifier": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set: func(v interface{}) int {
					return hashcode.String(v.(string))
				},
			},

			"termination_policies": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set: func(v interface{}) int {
					return hashcode.String(v.(string))
				},
			},

			"tag": autoscalingTagsSchema(),
		},
	}
}

func resourceAwsAutoscalingGroupCreate(d *schema.ResourceData, meta interface{}) error {
	autoscalingconn := meta.(*AWSClient).autoscalingconn

	var autoScalingGroupOpts autoscaling.CreateAutoScalingGroupInput
	autoScalingGroupOpts.AutoScalingGroupName = aws.String(d.Get("name").(string))
	autoScalingGroupOpts.LaunchConfigurationName = aws.String(d.Get("launch_configuration").(string))
	autoScalingGroupOpts.MinSize = aws.Long(int64(d.Get("min_size").(int)))
	autoScalingGroupOpts.MaxSize = aws.Long(int64(d.Get("max_size").(int)))
	autoScalingGroupOpts.AvailabilityZones = expandStringList(
		d.Get("availability_zones").(*schema.Set).List())

	if v, ok := d.GetOk("tag"); ok {
		autoScalingGroupOpts.Tags = autoscalingTagsFromMap(
			setToMapByKey(v.(*schema.Set), "key"), d.Get("name").(string))
	}

	if v, ok := d.GetOk("default_cooldown"); ok {
		autoScalingGroupOpts.DefaultCooldown = aws.Long(int64(v.(int)))
	}

	if v, ok := d.GetOk("health_check_type"); ok && v.(string) != "" {
		autoScalingGroupOpts.HealthCheckType = aws.String(v.(string))
	}

	if v, ok := d.GetOk("desired_capacity"); ok {
		autoScalingGroupOpts.DesiredCapacity = aws.Long(int64(v.(int)))
	}

	if v, ok := d.GetOk("health_check_grace_period"); ok {
		autoScalingGroupOpts.HealthCheckGracePeriod = aws.Long(int64(v.(int)))
	}

	if v, ok := d.GetOk("load_balancers"); ok && v.(*schema.Set).Len() > 0 {
		autoScalingGroupOpts.LoadBalancerNames = expandStringList(
			v.(*schema.Set).List())
	}

	if v, ok := d.GetOk("vpc_zone_identifier"); ok && v.(*schema.Set).Len() > 0 {
		exp := expandStringList(v.(*schema.Set).List())
		strs := make([]string, len(exp))
		for _, s := range exp {
			strs = append(strs, *s)
		}
		autoScalingGroupOpts.VPCZoneIdentifier = aws.String(strings.Join(strs, ","))
	}

	if v, ok := d.GetOk("termination_policies"); ok && v.(*schema.Set).Len() > 0 {
		autoScalingGroupOpts.TerminationPolicies = expandStringList(
			v.(*schema.Set).List())
	}

	log.Printf("[DEBUG] AutoScaling Group create configuration: %#v", autoScalingGroupOpts)
	_, err := autoscalingconn.CreateAutoScalingGroup(&autoScalingGroupOpts)
	if err != nil {
		return fmt.Errorf("Error creating Autoscaling Group: %s", err)
	}

	d.SetId(d.Get("name").(string))
	log.Printf("[INFO] AutoScaling Group ID: %s", d.Id())

	return resourceAwsAutoscalingGroupRead(d, meta)
}

func resourceAwsAutoscalingGroupRead(d *schema.ResourceData, meta interface{}) error {
	g, err := getAwsAutoscalingGroup(d, meta)
	if err != nil {
		return err
	}
	if g == nil {
		return nil
	}

	d.Set("availability_zones", g.AvailabilityZones)
	d.Set("default_cooldown", g.DefaultCooldown)
	d.Set("desired_capacity", g.DesiredCapacity)
	d.Set("health_check_grace_period", g.HealthCheckGracePeriod)
	d.Set("health_check_type", g.HealthCheckType)
	d.Set("launch_configuration", g.LaunchConfigurationName)
	d.Set("load_balancers", g.LoadBalancerNames)
	d.Set("min_size", g.MinSize)
	d.Set("max_size", g.MaxSize)
	d.Set("name", g.AutoScalingGroupName)
	d.Set("tag", g.Tags)
	d.Set("vpc_zone_identifier", strings.Split(*g.VPCZoneIdentifier, ","))
	d.Set("termination_policies", g.TerminationPolicies)

	return nil
}

func resourceAwsAutoscalingGroupUpdate(d *schema.ResourceData, meta interface{}) error {
	autoscalingconn := meta.(*AWSClient).autoscalingconn

	opts := autoscaling.UpdateAutoScalingGroupInput{
		AutoScalingGroupName: aws.String(d.Id()),
	}

	if d.HasChange("desired_capacity") {
		opts.DesiredCapacity = aws.Long(int64(d.Get("desired_capacity").(int)))
	}

	if d.HasChange("launch_configuration") {
		opts.LaunchConfigurationName = aws.String(d.Get("launch_configuration").(string))
	}

	if d.HasChange("min_size") {
		opts.MinSize = aws.Long(int64(d.Get("min_size").(int)))
	}

	if d.HasChange("max_size") {
		opts.MaxSize = aws.Long(int64(d.Get("max_size").(int)))
	}

	if err := setAutoscalingTags(autoscalingconn, d); err != nil {
		return err
	} else {
		d.SetPartial("tag")
	}

	log.Printf("[DEBUG] AutoScaling Group update configuration: %#v", opts)
	_, err := autoscalingconn.UpdateAutoScalingGroup(&opts)
	if err != nil {
		d.Partial(true)
		return fmt.Errorf("Error updating Autoscaling group: %s", err)
	}

	return resourceAwsAutoscalingGroupRead(d, meta)
}

func resourceAwsAutoscalingGroupDelete(d *schema.ResourceData, meta interface{}) error {
	autoscalingconn := meta.(*AWSClient).autoscalingconn

	// Read the autoscaling group first. If it doesn't exist, we're done.
	// We need the group in order to check if there are instances attached.
	// If so, we need to remove those first.
	g, err := getAwsAutoscalingGroup(d, meta)
	if err != nil {
		return err
	}
	if g == nil {
		return nil
	}
	if len(g.Instances) > 0 || *g.DesiredCapacity > 0 {
		if err := resourceAwsAutoscalingGroupDrain(d, meta); err != nil {
			return err
		}
	}

	log.Printf("[DEBUG] AutoScaling Group destroy: %v", d.Id())
	deleteopts := autoscaling.DeleteAutoScalingGroupInput{AutoScalingGroupName: aws.String(d.Id())}

	// You can force an autoscaling group to delete
	// even if it's in the process of scaling a resource.
	// Normally, you would set the min-size and max-size to 0,0
	// and then delete the group. This bypasses that and leaves
	// resources potentially dangling.
	if d.Get("force_delete").(bool) {
		deleteopts.ForceDelete = aws.Boolean(true)
	}

	if _, err := autoscalingconn.DeleteAutoScalingGroup(&deleteopts); err != nil {
		autoscalingerr, ok := err.(aws.APIError)
		if ok && autoscalingerr.Code == "InvalidGroup.NotFound" {
			return nil
		}
		return err
	}

	return resource.Retry(5*time.Minute, func() error {
		if g, _ = getAwsAutoscalingGroup(d, meta); g != nil {
			return fmt.Errorf("Auto Scaling Group still exists")
		}
		return nil
	})
}

func getAwsAutoscalingGroup(
	d *schema.ResourceData,
	meta interface{}) (*autoscaling.AutoScalingGroup, error) {
	autoscalingconn := meta.(*AWSClient).autoscalingconn

	describeOpts := autoscaling.DescribeAutoScalingGroupsInput{
		AutoScalingGroupNames: []*string{aws.String(d.Id())},
	}

	log.Printf("[DEBUG] AutoScaling Group describe configuration: %#v", describeOpts)
	describeGroups, err := autoscalingconn.DescribeAutoScalingGroups(&describeOpts)
	if err != nil {
		autoscalingerr, ok := err.(aws.APIError)
		if ok && autoscalingerr.Code == "InvalidGroup.NotFound" {
			d.SetId("")
			return nil, nil
		}

		return nil, fmt.Errorf("Error retrieving AutoScaling groups: %s", err)
	}

	// Search for the autoscaling group
	for idx, asc := range describeGroups.AutoScalingGroups {
		if *asc.AutoScalingGroupName == d.Id() {
			return describeGroups.AutoScalingGroups[idx], nil
		}
	}

	// ASG not found
	d.SetId("")
	return nil, nil
}

func resourceAwsAutoscalingGroupDrain(d *schema.ResourceData, meta interface{}) error {
	autoscalingconn := meta.(*AWSClient).autoscalingconn

	// First, set the capacity to zero so the group will drain
	log.Printf("[DEBUG] Reducing autoscaling group capacity to zero")
	opts := autoscaling.UpdateAutoScalingGroupInput{
		AutoScalingGroupName: aws.String(d.Id()),
		DesiredCapacity:      aws.Long(0),
		MinSize:              aws.Long(0),
		MaxSize:              aws.Long(0),
	}
	if _, err := autoscalingconn.UpdateAutoScalingGroup(&opts); err != nil {
		return fmt.Errorf("Error setting capacity to zero to drain: %s", err)
	}

	// Next, wait for the autoscale group to drain
	log.Printf("[DEBUG] Waiting for group to have zero instances")
	return resource.Retry(10*time.Minute, func() error {
		g, err := getAwsAutoscalingGroup(d, meta)
		if err != nil {
			return resource.RetryError{Err: err}
		}
		if g == nil {
			return nil
		}

		if len(g.Instances) == 0 {
			return nil
		}

		return fmt.Errorf("group still has %d instances", len(g.Instances))
	})
}
<commit_msg>don't need to create a new ASG for this change<commit_after>package aws

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"

	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/service/autoscaling"
)

func resourceAwsAutoscalingGroup() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsAutoscalingGroupCreate,
		Read:   resourceAwsAutoscalingGroupRead,
		Update: resourceAwsAutoscalingGroupUpdate,
		Delete: resourceAwsAutoscalingGroupDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"launch_configuration": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"desired_capacity": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Computed: true,
			},

			"min_size": &schema.Schema{
				Type:     schema.TypeInt,
				Required: true,
			},

			"max_size": &schema.Schema{
				Type:     schema.TypeInt,
				Required: true,
			},

			"default_cooldown": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},

			"force_delete": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},

			"health_check_grace_period": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
				Computed: true,
			},

			"health_check_type": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},

			"availability_zones": &schema.Schema{
				Type:     schema.TypeSet,
				Required: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set: func(v interface{}) int {
					return hashcode.String(v.(string))
				},
			},

			"load_balancers": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set: func(v interface{}) int {
					return hashcode.String(v.(string))
				},
			},

			"vpc_zone_identifier": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set: func(v interface{}) int {
					return hashcode.String(v.(string))
				},
			},

			"termination_policies": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set: func(v interface{}) int {
					return hashcode.String(v.(string))
				},
			},

			"tag": autoscalingTagsSchema(),
		},
	}
}

func resourceAwsAutoscalingGroupCreate(d *schema.ResourceData, meta interface{}) error {
	autoscalingconn := meta.(*AWSClient).autoscalingconn

	var autoScalingGroupOpts autoscaling.CreateAutoScalingGroupInput
	autoScalingGroupOpts.AutoScalingGroupName = aws.String(d.Get("name").(string))
	autoScalingGroupOpts.LaunchConfigurationName = aws.String(d.Get("launch_configuration").(string))
	autoScalingGroupOpts.MinSize = aws.Long(int64(d.Get("min_size").(int)))
	autoScalingGroupOpts.MaxSize = aws.Long(int64(d.Get("max_size").(int)))
	autoScalingGroupOpts.AvailabilityZones = expandStringList(
		d.Get("availability_zones").(*schema.Set).List())

	if v, ok := d.GetOk("tag"); ok {
		autoScalingGroupOpts.Tags = autoscalingTagsFromMap(
			setToMapByKey(v.(*schema.Set), "key"), d.Get("name").(string))
	}

	if v, ok := d.GetOk("default_cooldown"); ok {
		autoScalingGroupOpts.DefaultCooldown = aws.Long(int64(v.(int)))
	}

	if v, ok := d.GetOk("health_check_type"); ok && v.(string) != "" {
		autoScalingGroupOpts.HealthCheckType = aws.String(v.(string))
	}

	if v, ok := d.GetOk("desired_capacity"); ok {
		autoScalingGroupOpts.DesiredCapacity = aws.Long(int64(v.(int)))
	}

	if v, ok := d.GetOk("health_check_grace_period"); ok {
		autoScalingGroupOpts.HealthCheckGracePeriod = aws.Long(int64(v.(int)))
	}

	if v, ok := d.GetOk("load_balancers"); ok && v.(*schema.Set).Len() > 0 {
		autoScalingGroupOpts.LoadBalancerNames = expandStringList(
			v.(*schema.Set).List())
	}

	if v, ok := d.GetOk("vpc_zone_identifier"); ok && v.(*schema.Set).Len() > 0 {
		exp := expandStringList(v.(*schema.Set).List())
		strs := make([]string, len(exp))
		for _, s := range exp {
			strs = append(strs, *s)
		}
		autoScalingGroupOpts.VPCZoneIdentifier = aws.String(strings.Join(strs, ","))
	}

	if v, ok := d.GetOk("termination_policies"); ok && v.(*schema.Set).Len() > 0 {
		autoScalingGroupOpts.TerminationPolicies = expandStringList(
			v.(*schema.Set).List())
	}

	log.Printf("[DEBUG] AutoScaling Group create configuration: %#v", autoScalingGroupOpts)
	_, err := autoscalingconn.CreateAutoScalingGroup(&autoScalingGroupOpts)
	if err != nil {
		return fmt.Errorf("Error creating Autoscaling Group: %s", err)
	}

	d.SetId(d.Get("name").(string))
	log.Printf("[INFO] AutoScaling Group ID: %s", d.Id())

	return resourceAwsAutoscalingGroupRead(d, meta)
}

func resourceAwsAutoscalingGroupRead(d *schema.ResourceData, meta interface{}) error {
	g, err := getAwsAutoscalingGroup(d, meta)
	if err != nil {
		return err
	}
	if g == nil {
		return nil
	}

	d.Set("availability_zones", g.AvailabilityZones)
	d.Set("default_cooldown", g.DefaultCooldown)
	d.Set("desired_capacity", g.DesiredCapacity)
	d.Set("health_check_grace_period", g.HealthCheckGracePeriod)
	d.Set("health_check_type", g.HealthCheckType)
	d.Set("launch_configuration", g.LaunchConfigurationName)
	d.Set("load_balancers", g.LoadBalancerNames)
	d.Set("min_size", g.MinSize)
	d.Set("max_size", g.MaxSize)
	d.Set("name", g.AutoScalingGroupName)
	d.Set("tag", g.Tags)
	d.Set("vpc_zone_identifier", strings.Split(*g.VPCZoneIdentifier, ","))
	d.Set("termination_policies", g.TerminationPolicies)

	return nil
}

func resourceAwsAutoscalingGroupUpdate(d *schema.ResourceData, meta interface{}) error {
	autoscalingconn := meta.(*AWSClient).autoscalingconn

	opts := autoscaling.UpdateAutoScalingGroupInput{
		AutoScalingGroupName: aws.String(d.Id()),
	}

	if d.HasChange("desired_capacity") {
		opts.DesiredCapacity = aws.Long(int64(d.Get("desired_capacity").(int)))
	}

	if d.HasChange("launch_configuration") {
		opts.LaunchConfigurationName = aws.String(d.Get("launch_configuration").(string))
	}

	if d.HasChange("min_size") {
		opts.MinSize = aws.Long(int64(d.Get("min_size").(int)))
	}

	if d.HasChange("max_size") {
		opts.MaxSize = aws.Long(int64(d.Get("max_size").(int)))
	}

	if err := setAutoscalingTags(autoscalingconn, d); err != nil {
		return err
	} else {
		d.SetPartial("tag")
	}

	log.Printf("[DEBUG] AutoScaling Group update configuration: %#v", opts)
	_, err := autoscalingconn.UpdateAutoScalingGroup(&opts)
	if err != nil {
		d.Partial(true)
		return fmt.Errorf("Error updating Autoscaling group: %s", err)
	}

	return resourceAwsAutoscalingGroupRead(d, meta)
}

func resourceAwsAutoscalingGroupDelete(d *schema.ResourceData, meta interface{}) error {
	autoscalingconn := meta.(*AWSClient).autoscalingconn

	// Read the autoscaling group first. If it doesn't exist, we're done.
	// We need the group in order to check if there are instances attached.
	// If so, we need to remove those first.
	g, err := getAwsAutoscalingGroup(d, meta)
	if err != nil {
		return err
	}
	if g == nil {
		return nil
	}
	if len(g.Instances) > 0 || *g.DesiredCapacity > 0 {
		if err := resourceAwsAutoscalingGroupDrain(d, meta); err != nil {
			return err
		}
	}

	log.Printf("[DEBUG] AutoScaling Group destroy: %v", d.Id())
	deleteopts := autoscaling.DeleteAutoScalingGroupInput{AutoScalingGroupName: aws.String(d.Id())}

	// You can force an autoscaling group to delete
	// even if it's in the process of scaling a resource.
	// Normally, you would set the min-size and max-size to 0,0
	// and then delete the group. This bypasses that and leaves
	// resources potentially dangling.
	if d.Get("force_delete").(bool) {
		deleteopts.ForceDelete = aws.Boolean(true)
	}

	if _, err := autoscalingconn.DeleteAutoScalingGroup(&deleteopts); err != nil {
		autoscalingerr, ok := err.(aws.APIError)
		if ok && autoscalingerr.Code == "InvalidGroup.NotFound" {
			return nil
		}
		return err
	}

	return resource.Retry(5*time.Minute, func() error {
		if g, _ = getAwsAutoscalingGroup(d, meta); g != nil {
			return fmt.Errorf("Auto Scaling Group still exists")
		}
		return nil
	})
}

func getAwsAutoscalingGroup(
	d *schema.ResourceData,
	meta interface{}) (*autoscaling.AutoScalingGroup, error) {
	autoscalingconn := meta.(*AWSClient).autoscalingconn

	describeOpts := autoscaling.DescribeAutoScalingGroupsInput{
		AutoScalingGroupNames: []*string{aws.String(d.Id())},
	}

	log.Printf("[DEBUG] AutoScaling Group describe configuration: %#v", describeOpts)
	describeGroups, err := autoscalingconn.DescribeAutoScalingGroups(&describeOpts)
	if err != nil {
		autoscalingerr, ok := err.(aws.APIError)
		if ok && autoscalingerr.Code == "InvalidGroup.NotFound" {
			d.SetId("")
			return nil, nil
		}

		return nil, fmt.Errorf("Error retrieving AutoScaling groups: %s", err)
	}

	// Search for the autoscaling group
	for idx, asc := range describeGroups.AutoScalingGroups {
		if *asc.AutoScalingGroupName == d.Id() {
			return describeGroups.AutoScalingGroups[idx], nil
		}
	}

	// ASG not found
	d.SetId("")
	return nil, nil
}

func resourceAwsAutoscalingGroupDrain(d *schema.ResourceData, meta interface{}) error {
	autoscalingconn := meta.(*AWSClient).autoscalingconn

	// First, set the capacity to zero so the group will drain
	log.Printf("[DEBUG] Reducing autoscaling group capacity to zero")
	opts := autoscaling.UpdateAutoScalingGroupInput{
		AutoScalingGroupName: aws.String(d.Id()),
		DesiredCapacity:      aws.Long(0),
		MinSize:              aws.Long(0),
		MaxSize:              aws.Long(0),
	}
	if _, err := autoscalingconn.UpdateAutoScalingGroup(&opts); err != nil {
		return fmt.Errorf("Error setting capacity to zero to drain: %s", err)
	}

	// Next, wait for the autoscale group to drain
	log.Printf("[DEBUG] Waiting for group to have zero instances")
	return resource.Retry(10*time.Minute, func() error {
		g, err := getAwsAutoscalingGroup(d, meta)
		if err != nil {
			return resource.RetryError{Err: err}
		}
		if g == nil {
			return nil
		}

		if len(g.Instances) == 0 {
			return nil
		}

		return fmt.Errorf("group still has %d instances", len(g.Instances))
	})
}
<|endoftext|>


<commit_before>// Copyright 2013 The StudyGolang Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// http://studygolang.com
// Author: polaris	polaris@studygolang.com

package controller

import (
	"fmt"
	"html/template"
	"net/http"

	"http/middleware"
	"logic"
	"model"

	"github.com/labstack/echo"
	"github.com/polaris1119/goutils"
)

type MessageController struct{}

// 注册路由
func (self MessageController) RegisterRoute(g *echo.Group) {
	messageG := g.Group("/message/", middleware.NeedLogin())

	messageG.GET(":msgtype", self.ReadList)
	messageG.GET("system", self.ReadList)
	messageG.Match([]string{"GET", "POST"}, "/send", self.Send)
	messageG.POST("delete", self.Delete)

	// g.GET("/message/:msgtype", self.ReadList, middleware.NeedLogin())
	// g.GET("/message/system", self.ReadList, middleware.NeedLogin())
	// g.Match([]string{"GET", "POST"}, "/message/send", self.Send, middleware.NeedLogin())
	// g.POST("/message/delete", self.Delete, middleware.NeedLogin())
}

// Send 发短消息
func (MessageController) Send(ctx echo.Context) error {
	content := ctx.FormValue("content")
	// 请求发送消息页面
	if content == "" || ctx.Request().Method() != "POST" {
		username := ctx.FormValue("username")
		if username == "" {
			return ctx.Redirect(http.StatusSeeOther, "/")
		}
		user := logic.DefaultUser.FindOne(ctx, "username", username)
		return render(ctx, "messages/send.html", map[string]interface{}{"user": user})
	}

	user := ctx.Get("user").(*model.Me)
	to := goutils.MustInt(ctx.FormValue("to"))
	ok := logic.DefaultMessage.SendMessageTo(ctx, user.Uid, to, content)
	if !ok {
		return fail(ctx, 1, "对不起，发送失败，请稍候再试！")
	}

	return success(ctx, nil)
}

// 消息列表
func (MessageController) ReadList(ctx echo.Context) error {
	user := ctx.Get("user").(*model.Me)
	msgtype := ctx.Param("msgtype")
	if msgtype == "" {
		msgtype = "system"
	}

	curPage := goutils.MustInt(ctx.QueryParam("p"), 1)
	paginator := logic.NewPaginator(curPage)

	var (
		messages []map[string]interface{}
		total    int64
	)
	switch msgtype {
	case "system":
		messages = logic.DefaultMessage.FindSysMsgsByUid(ctx, user.Uid, paginator)
		total = logic.DefaultMessage.SysMsgCount(ctx, user.Uid)
	case "inbox":
		messages = logic.DefaultMessage.FindToMsgsByUid(ctx, user.Uid, paginator)
		total = logic.DefaultMessage.ToMsgCount(ctx, user.Uid)
	case "outbox":
		messages = logic.DefaultMessage.FindFromMsgsByUid(ctx, user.Uid, paginator)
		total = logic.DefaultMessage.FromMsgCount(ctx, user.Uid)
	default:
		return ctx.Redirect(http.StatusSeeOther, "/")
	}

	pageHtml := paginator.SetTotal(total).GetPageHtml(fmt.Sprintf("/system/%s", msgtype))

	return render(ctx, "messages/list.html", map[string]interface{}{"messages": messages, "msgtype": msgtype, "page": template.HTML(pageHtml)})
}

// 删除消息
func (MessageController) Delete(ctx echo.Context) error {
	id := ctx.FormValue("id")
	msgtype := ctx.FormValue("msgtype")
	if !logic.DefaultMessage.DeleteMessage(ctx, id, msgtype) {
		return fail(ctx, 1, "对不起，删除失败，请稍候再试！")
	}

	return success(ctx, nil)
}
<commit_msg>send msessage bugfix<commit_after>// Copyright 2013 The StudyGolang Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// http://studygolang.com
// Author: polaris	polaris@studygolang.com

package controller

import (
	"fmt"
	"html/template"
	"net/http"

	"http/middleware"
	"logic"
	"model"

	"github.com/labstack/echo"
	"github.com/polaris1119/goutils"
)

type MessageController struct{}

// 注册路由
func (self MessageController) RegisterRoute(g *echo.Group) {
	messageG := g.Group("/message/", middleware.NeedLogin())

	messageG.GET(":msgtype", self.ReadList)
	messageG.GET("system", self.ReadList)
	messageG.Match([]string{"GET", "POST"}, "send", self.Send)
	messageG.POST("delete", self.Delete)

	// g.GET("/message/:msgtype", self.ReadList, middleware.NeedLogin())
	// g.GET("/message/system", self.ReadList, middleware.NeedLogin())
	// g.Match([]string{"GET", "POST"}, "/message/send", self.Send, middleware.NeedLogin())
	// g.POST("/message/delete", self.Delete, middleware.NeedLogin())
}

// Send 发短消息
func (MessageController) Send(ctx echo.Context) error {
	content := ctx.FormValue("content")
	// 请求发送消息页面
	if content == "" || ctx.Request().Method() != "POST" {
		username := ctx.FormValue("username")
		if username == "" {
			return ctx.Redirect(http.StatusSeeOther, "/")
		}
		user := logic.DefaultUser.FindOne(ctx, "username", username)
		return render(ctx, "messages/send.html", map[string]interface{}{"user": user})
	}

	user := ctx.Get("user").(*model.Me)
	to := goutils.MustInt(ctx.FormValue("to"))
	ok := logic.DefaultMessage.SendMessageTo(ctx, user.Uid, to, content)
	if !ok {
		return fail(ctx, 1, "对不起，发送失败，请稍候再试！")
	}

	return success(ctx, nil)
}

// 消息列表
func (MessageController) ReadList(ctx echo.Context) error {
	user := ctx.Get("user").(*model.Me)
	msgtype := ctx.Param("msgtype")
	if msgtype == "" {
		msgtype = "system"
	}

	curPage := goutils.MustInt(ctx.QueryParam("p"), 1)
	paginator := logic.NewPaginator(curPage)

	var (
		messages []map[string]interface{}
		total    int64
	)
	switch msgtype {
	case "system":
		messages = logic.DefaultMessage.FindSysMsgsByUid(ctx, user.Uid, paginator)
		total = logic.DefaultMessage.SysMsgCount(ctx, user.Uid)
	case "inbox":
		messages = logic.DefaultMessage.FindToMsgsByUid(ctx, user.Uid, paginator)
		total = logic.DefaultMessage.ToMsgCount(ctx, user.Uid)
	case "outbox":
		messages = logic.DefaultMessage.FindFromMsgsByUid(ctx, user.Uid, paginator)
		total = logic.DefaultMessage.FromMsgCount(ctx, user.Uid)
	default:
		return ctx.Redirect(http.StatusSeeOther, "/")
	}

	pageHtml := paginator.SetTotal(total).GetPageHtml(fmt.Sprintf("/system/%s", msgtype))

	return render(ctx, "messages/list.html", map[string]interface{}{"messages": messages, "msgtype": msgtype, "page": template.HTML(pageHtml)})
}

// 删除消息
func (MessageController) Delete(ctx echo.Context) error {
	id := ctx.FormValue("id")
	msgtype := ctx.FormValue("msgtype")
	if !logic.DefaultMessage.DeleteMessage(ctx, id, msgtype) {
		return fail(ctx, 1, "对不起，删除失败，请稍候再试！")
	}

	return success(ctx, nil)
}
<|endoftext|>