<commit_before>// Copyright 2013 gandalf 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 main

import (
	"bytes"
	"github.com/globocom/commandmocker"
	"github.com/globocom/config"
	"github.com/globocom/gandalf/db"
	"github.com/globocom/gandalf/repository"
	"github.com/globocom/gandalf/user"
	"labix.org/v2/mgo/bson"
	. "launchpad.net/gocheck"
	"log/syslog"
	"os"
	"path"
	"testing"
)

func Test(t *testing.T) { TestingT(t) }

type S struct {
	user *user.User
	repo *repository.Repository
}

var _ = Suite(&S{})

func (s *S) SetUpSuite(c *C) {
	var err error
	log, err = syslog.New(syslog.LOG_INFO, "gandalf-listener")
	c.Check(err, IsNil)
	err = config.ReadConfigFile("../etc/gandalf.conf")
	c.Check(err, IsNil)
	config.Set("database:name", "gandalf_bin_tests")
	db.Connect()
	s.user, err = user.New("testuser", map[string]string{})
	c.Check(err, IsNil)
	// does not uses repository.New to avoid creation of bare git repo
	s.repo = &repository.Repository{Name: "myapp", Users: []string{s.user.Name}}
	err = db.Session.Repository().Insert(s.repo)
	c.Check(err, IsNil)
}

func (s *S) TearDownSuite(c *C) {
	db.Session.DB.DropDatabase()
}

func (s *S) TestHasWritePermissionSholdReturnTrueWhenUserCanWriteInRepo(c *C) {
	allowed := hasWritePermission(s.user, s.repo)
	c.Assert(allowed, Equals, true)
}

func (s *S) TestHasWritePermissionShouldReturnFalseWhenUserCannotWriteinRepo(c *C) {
	r := &repository.Repository{Name: "myotherapp"}
	db.Session.Repository().Insert(&r)
	defer db.Session.Repository().Remove(bson.M{"_id": r.Name})
	allowed := hasWritePermission(s.user, r)
	c.Assert(allowed, Equals, false)
}

func (s *S) TestHasReadPermissionShouldReturnTrueWhenRepositoryIsPublic(c *C) {
	r := &repository.Repository{Name: "myotherapp", IsPublic: true}
	db.Session.Repository().Insert(&r)
	defer db.Session.Repository().Remove(bson.M{"_id": r.Name})
	allowed := hasReadPermission(s.user, r)
	c.Assert(allowed, Equals, true)
}

func (s *S) TestHasReadPermissionShouldReturnTrueWhenRepositoryIsNotPublicAndUserHasPermissionToReadAndWrite(c *C) {
	allowed := hasReadPermission(s.user, s.repo)
	c.Assert(allowed, Equals, true)
}

func (s *S) TestHasReadPermissionShouldReturnFalseWhenUserDoesNotHavePermissionToReadWriteAndRepoIsNotPublic(c *C) {
	r := &repository.Repository{Name: "myotherapp", IsPublic: false}
	db.Session.Repository().Insert(&r)
	defer db.Session.Repository().Remove(bson.M{"_id": r.Name})
	allowed := hasReadPermission(s.user, r)
	c.Assert(allowed, Equals, false)
}

func (s *S) TestActionShouldReturnTheCommandBeingExecutedBySSH_ORIGINAL_COMMANDEnvVar(c *C) {
	os.Setenv("SSH_ORIGINAL_COMMAND", "test-cmd")
	defer os.Setenv("SSH_ORIGINAL_COMMAND", "")
	cmd := action()
	c.Assert(cmd, Equals, "test-cmd")
}

func (s *S) TestActionShouldReturnEmptyWhenEnvVarIsNotSet(c *C) {
	cmd := action()
	c.Assert(cmd, Equals, "")
}

func (s *S) TestRequestedRepositoryShouldGetArgumentInSSH_ORIGINAL_COMMANDAndRetrieveTheEquivalentDatabaseRepository(c *C) {
	r := repository.Repository{Name: "foo"}
	err := db.Session.Repository().Insert(&r)
	c.Assert(err, IsNil)
	defer db.Session.Repository().Remove(bson.M{"_id": r.Name})
	os.Setenv("SSH_ORIGINAL_COMMAND", "git-receive-pack 'foo.git'")
	defer os.Setenv("SSH_ORIGINAL_COMMAND", "")
	repo, err := requestedRepository()
	c.Assert(err, IsNil)
	c.Assert(repo.Name, Equals, r.Name)
}

func (s *S) TestRequestedRepositoryShouldDeduceCorrectlyRepositoryNameWithDash(c *C) {
	r := repository.Repository{Name: "foo-bar"}
	err := db.Session.Repository().Insert(&r)
	c.Assert(err, IsNil)
	defer db.Session.Repository().Remove(bson.M{"_id": r.Name})
	os.Setenv("SSH_ORIGINAL_COMMAND", "git-receive-pack 'foo-bar.git'")
	defer os.Setenv("SSH_ORIGINAL_COMMAND", "")
	repo, err := requestedRepository()
	c.Assert(err, IsNil)
	c.Assert(repo.Name, Equals, r.Name)
}

func (s *S) TestRequestedRepositoryShouldReturnErrorWhenCommandDoesNotPassesWhatIsExpected(c *C) {
	os.Setenv("SSH_ORIGINAL_COMMAND", "rm -rf /")
	defer os.Setenv("SSH_ORIGINAL_COMMAND", "")
	_, err := requestedRepository()
	c.Assert(err, ErrorMatches, "^Cannot deduce repository name from command. You are probably trying to do something nasty$")
}

func (s *S) TestRequestedRepositoryShouldReturnErrorWhenThereIsNoCommandPassedToSSH_ORIGINAL_COMMAND(c *C) {
	_, err := requestedRepository()
	c.Assert(err, ErrorMatches, "^Cannot deduce repository name from command. You are probably trying to do something nasty$")
}

func (s *S) TestRequestedRepositoryShouldReturnFormatedErrorWhenRepositoryDoesNotExists(c *C) {
	os.Setenv("SSH_ORIGINAL_COMMAND", "git-receive-pack 'inexistent-repo.git'")
	defer os.Setenv("SSH_ORIGINAL_COMMAND", "")
	_, err := requestedRepository()
	c.Assert(err, ErrorMatches, "^Repository not found$")
}

func (s *S) TestRequestedRepositoryShouldReturnEmptyRepositoryStructOnError(c *C) {
	repo, err := requestedRepository()
	c.Assert(err, NotNil)
	c.Assert(repo.Name, Equals, "")
}

func (s *S) TestRequestedRepositoryName(c *C) {
	os.Setenv("SSH_ORIGINAL_COMMAND", "git-receive-pack 'foobar.git'")
	defer os.Setenv("SSH_ORIGINAL_COMMAND", "")
	name, err := requestedRepositoryName()
	c.Assert(err, IsNil)
	c.Assert(name, Equals, "foobar")
}

func (s *S) TestrequestedRepositoryNameShouldReturnErrorWhenTheresNoMatch(c *C) {
	os.Setenv("SSH_ORIGINAL_COMMAND", "git-receive-pack foobar")
	defer os.Setenv("SSH_ORIGINAL_COMMAND", "")
	name, err := requestedRepositoryName()
	c.Assert(err, ErrorMatches, "Cannot deduce repository name from command. You are probably trying to do something nasty")
	c.Assert(name, Equals, "")
}

func (s *S) TestValidateCmdReturnsErrorWhenSSH_ORIGINAL_COMMANDIsNotAGitCommand(c *C) {
	os.Setenv("SSH_ORIGINAL_COMMAND", "rm -rf /")
	defer os.Setenv("SSH_ORIGINAL_COMMAND", "")
	err := validateCmd()
	c.Assert(err, ErrorMatches, "^You've tried to execute some weird command, I'm deliberately denying you to do that, get over it.$")
}

func (s *S) TestValidateCmdDoNotReturnsErrorWhenSSH_ORIGINAL_COMMANDIsAValidGitCommand(c *C) {
	os.Setenv("SSH_ORIGINAL_COMMAND", "git-receive-pack 'my-repo.git'")
	defer os.Setenv("SSH_ORIGINAL_COMMAND", "")
	err := validateCmd()
	c.Assert(err, IsNil)
}

func (s *S) TestExecuteActionShouldExecuteGitReceivePackWhenUserHasWritePermission(c *C) {
	dir, err := commandmocker.Add("git-receive-pack", "$*")
	c.Check(err, IsNil)
	defer commandmocker.Remove(dir)
	os.Args = []string{"gandalf", s.user.Name}
	os.Setenv("SSH_ORIGINAL_COMMAND", "git-receive-pack 'myapp.git'")
	defer func() {
		os.Args = []string{}
		os.Setenv("SSH_ORIGINAL_COMMAND", "")
	}()
	stdout := &bytes.Buffer{}
	executeAction(hasWritePermission, "You don't have access to write in this repository.", stdout)
	c.Assert(commandmocker.Ran(dir), Equals, true)
	p, err := config.GetString("git:bare:location")
	c.Assert(err, IsNil)
	expected := path.Join(p, "myapp.git")
	c.Assert(stdout.String(), Equals, expected)
}

func (s *S) TestExecuteActionShouldNotCallSSH_ORIGINAL_COMMANDWhenUserDoesNotExists(c *C) {
	dir, err := commandmocker.Add("git-receive-pack", "$*")
	c.Check(err, IsNil)
	defer commandmocker.Remove(dir)
	os.Args = []string{"gandalf", "god"}
	os.Setenv("SSH_ORIGINAL_COMMAND", "git-receive-pack 'myapp.git'")
	defer func() {
		os.Args = []string{}
		os.Setenv("SSH_ORIGINAL_COMMAND", "")
	}()
	stdout := new(bytes.Buffer)
	errorMsg := "You don't have access to write in this repository."
	executeAction(hasWritePermission, errorMsg, stdout)
	c.Assert(commandmocker.Ran(dir), Equals, false)
}

func (s *S) TestExecuteActionShouldNotCallSSH_ORIGINAL_COMMANDWhenRepositoryDoesNotExists(c *C) {
	dir, err := commandmocker.Add("git-receive-pack", "$*")
	c.Check(err, IsNil)
	defer commandmocker.Remove(dir)
	os.Args = []string{"gandalf", s.user.Name}
	os.Setenv("SSH_ORIGINAL_COMMAND", "git-receive-pack 'ghostapp.git'")
	defer func() {
		os.Args = []string{}
		os.Setenv("SSH_ORIGINAL_COMMAND", "")
	}()
	stdout := &bytes.Buffer{}
	errorMsg := "You don't have access to write in this repository."
	executeAction(hasWritePermission, errorMsg, stdout)
	c.Assert(commandmocker.Ran(dir), Equals, false)
}

func (s *S) TestFormatCommandShouldReceiveAGitCommandAndCanonizalizeTheRepositoryPath(c *C) {
	os.Setenv("SSH_ORIGINAL_COMMAND", "git-receive-pack 'myproject.git'")
	defer os.Setenv("SSH_ORIGINAL_COMMAND", "")
	cmd, err := formatCommand()
	c.Assert(err, IsNil)
	p, err := config.GetString("git:bare:location")
	c.Assert(err, IsNil)
	expected := path.Join(p, "myproject.git")
	c.Assert(cmd, DeepEquals, []string{"git-receive-pack", expected})
}
<commit_msg>bin: don't use unqualified imports for gocheck<commit_after>// Copyright 2013 gandalf 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 main

import (
	"bytes"
	"github.com/globocom/commandmocker"
	"github.com/globocom/config"
	"github.com/globocom/gandalf/db"
	"github.com/globocom/gandalf/repository"
	"github.com/globocom/gandalf/user"
	"labix.org/v2/mgo/bson"
	"launchpad.net/gocheck"
	"log/syslog"
	"os"
	"path"
	"testing"
)

func Test(t *testing.T) { gocheck.TestingT(t) }

type S struct {
	user *user.User
	repo *repository.Repository
}

var _ = gocheck.Suite(&S{})

func (s *S) SetUpSuite(c *gocheck.C) {
	var err error
	log, err = syslog.New(syslog.LOG_INFO, "gandalf-listener")
	c.Check(err, gocheck.IsNil)
	err = config.ReadConfigFile("../etc/gandalf.conf")
	c.Check(err, gocheck.IsNil)
	config.Set("database:name", "gandalf_bin_tests")
	db.Connect()
	s.user, err = user.New("testuser", map[string]string{})
	c.Check(err, gocheck.IsNil)
	// does not uses repository.New to avoid creation of bare git repo
	s.repo = &repository.Repository{Name: "myapp", Users: []string{s.user.Name}}
	err = db.Session.Repository().Insert(s.repo)
	c.Check(err, gocheck.IsNil)
}

func (s *S) TearDownSuite(c *gocheck.C) {
	db.Session.DB.DropDatabase()
}

func (s *S) TestHasWritePermissionSholdReturnTrueWhenUserCanWriteInRepo(c *gocheck.C) {
	allowed := hasWritePermission(s.user, s.repo)
	c.Assert(allowed, gocheck.Equals, true)
}

func (s *S) TestHasWritePermissionShouldReturnFalseWhenUserCannotWriteinRepo(c *gocheck.C) {
	r := &repository.Repository{Name: "myotherapp"}
	db.Session.Repository().Insert(&r)
	defer db.Session.Repository().Remove(bson.M{"_id": r.Name})
	allowed := hasWritePermission(s.user, r)
	c.Assert(allowed, gocheck.Equals, false)
}

func (s *S) TestHasReadPermissionShouldReturnTrueWhenRepositoryIsPublic(c *gocheck.C) {
	r := &repository.Repository{Name: "myotherapp", IsPublic: true}
	db.Session.Repository().Insert(&r)
	defer db.Session.Repository().Remove(bson.M{"_id": r.Name})
	allowed := hasReadPermission(s.user, r)
	c.Assert(allowed, gocheck.Equals, true)
}

func (s *S) TestHasReadPermissionShouldReturnTrueWhenRepositoryIsNotPublicAndUserHasPermissionToReadAndWrite(c *gocheck.C) {
	allowed := hasReadPermission(s.user, s.repo)
	c.Assert(allowed, gocheck.Equals, true)
}

func (s *S) TestHasReadPermissionShouldReturnFalseWhenUserDoesNotHavePermissionToReadWriteAndRepoIsNotPublic(c *gocheck.C) {
	r := &repository.Repository{Name: "myotherapp", IsPublic: false}
	db.Session.Repository().Insert(&r)
	defer db.Session.Repository().Remove(bson.M{"_id": r.Name})
	allowed := hasReadPermission(s.user, r)
	c.Assert(allowed, gocheck.Equals, false)
}

func (s *S) TestActionShouldReturnTheCommandBeingExecutedBySSH_ORIGINAL_COMMANDEnvVar(c *gocheck.C) {
	os.Setenv("SSH_ORIGINAL_COMMAND", "test-cmd")
	defer os.Setenv("SSH_ORIGINAL_COMMAND", "")
	cmd := action()
	c.Assert(cmd, gocheck.Equals, "test-cmd")
}

func (s *S) TestActionShouldReturnEmptyWhenEnvVarIsNotSet(c *gocheck.C) {
	cmd := action()
	c.Assert(cmd, gocheck.Equals, "")
}

func (s *S) TestRequestedRepositoryShouldGetArgumentInSSH_ORIGINAL_COMMANDAndRetrieveTheEquivalentDatabaseRepository(c *gocheck.C) {
	r := repository.Repository{Name: "foo"}
	err := db.Session.Repository().Insert(&r)
	c.Assert(err, gocheck.IsNil)
	defer db.Session.Repository().Remove(bson.M{"_id": r.Name})
	os.Setenv("SSH_ORIGINAL_COMMAND", "git-receive-pack 'foo.git'")
	defer os.Setenv("SSH_ORIGINAL_COMMAND", "")
	repo, err := requestedRepository()
	c.Assert(err, gocheck.IsNil)
	c.Assert(repo.Name, gocheck.Equals, r.Name)
}

func (s *S) TestRequestedRepositoryShouldDeduceCorrectlyRepositoryNameWithDash(c *gocheck.C) {
	r := repository.Repository{Name: "foo-bar"}
	err := db.Session.Repository().Insert(&r)
	c.Assert(err, gocheck.IsNil)
	defer db.Session.Repository().Remove(bson.M{"_id": r.Name})
	os.Setenv("SSH_ORIGINAL_COMMAND", "git-receive-pack 'foo-bar.git'")
	defer os.Setenv("SSH_ORIGINAL_COMMAND", "")
	repo, err := requestedRepository()
	c.Assert(err, gocheck.IsNil)
	c.Assert(repo.Name, gocheck.Equals, r.Name)
}

func (s *S) TestRequestedRepositoryShouldReturnErrorWhenCommandDoesNotPassesWhatIsExpected(c *gocheck.C) {
	os.Setenv("SSH_ORIGINAL_COMMAND", "rm -rf /")
	defer os.Setenv("SSH_ORIGINAL_COMMAND", "")
	_, err := requestedRepository()
	c.Assert(err, gocheck.ErrorMatches, "^Cannot deduce repository name from command. You are probably trying to do something nasty$")
}

func (s *S) TestRequestedRepositoryShouldReturnErrorWhenThereIsNoCommandPassedToSSH_ORIGINAL_COMMAND(c *gocheck.C) {
	_, err := requestedRepository()
	c.Assert(err, gocheck.ErrorMatches, "^Cannot deduce repository name from command. You are probably trying to do something nasty$")
}

func (s *S) TestRequestedRepositoryShouldReturnFormatedErrorWhenRepositoryDoesNotExists(c *gocheck.C) {
	os.Setenv("SSH_ORIGINAL_COMMAND", "git-receive-pack 'inexistent-repo.git'")
	defer os.Setenv("SSH_ORIGINAL_COMMAND", "")
	_, err := requestedRepository()
	c.Assert(err, gocheck.ErrorMatches, "^Repository not found$")
}

func (s *S) TestRequestedRepositoryShouldReturnEmptyRepositoryStructOnError(c *gocheck.C) {
	repo, err := requestedRepository()
	c.Assert(err, gocheck.NotNil)
	c.Assert(repo.Name, gocheck.Equals, "")
}

func (s *S) TestRequestedRepositoryName(c *gocheck.C) {
	os.Setenv("SSH_ORIGINAL_COMMAND", "git-receive-pack 'foobar.git'")
	defer os.Setenv("SSH_ORIGINAL_COMMAND", "")
	name, err := requestedRepositoryName()
	c.Assert(err, gocheck.IsNil)
	c.Assert(name, gocheck.Equals, "foobar")
}

func (s *S) TestrequestedRepositoryNameShouldReturnErrorWhenTheresNoMatch(c *gocheck.C) {
	os.Setenv("SSH_ORIGINAL_COMMAND", "git-receive-pack foobar")
	defer os.Setenv("SSH_ORIGINAL_COMMAND", "")
	name, err := requestedRepositoryName()
	c.Assert(err, gocheck.ErrorMatches, "Cannot deduce repository name from command. You are probably trying to do something nasty")
	c.Assert(name, gocheck.Equals, "")
}

func (s *S) TestValidateCmdReturnsErrorWhenSSH_ORIGINAL_COMMANDIsNotAGitCommand(c *gocheck.C) {
	os.Setenv("SSH_ORIGINAL_COMMAND", "rm -rf /")
	defer os.Setenv("SSH_ORIGINAL_COMMAND", "")
	err := validateCmd()
	c.Assert(err, gocheck.ErrorMatches, "^You've tried to execute some weird command, I'm deliberately denying you to do that, get over it.$")
}

func (s *S) TestValidateCmdDoNotReturnsErrorWhenSSH_ORIGINAL_COMMANDIsAValidGitCommand(c *gocheck.C) {
	os.Setenv("SSH_ORIGINAL_COMMAND", "git-receive-pack 'my-repo.git'")
	defer os.Setenv("SSH_ORIGINAL_COMMAND", "")
	err := validateCmd()
	c.Assert(err, gocheck.IsNil)
}

func (s *S) TestExecuteActionShouldExecuteGitReceivePackWhenUserHasWritePermission(c *gocheck.C) {
	dir, err := commandmocker.Add("git-receive-pack", "$*")
	c.Check(err, gocheck.IsNil)
	defer commandmocker.Remove(dir)
	os.Args = []string{"gandalf", s.user.Name}
	os.Setenv("SSH_ORIGINAL_COMMAND", "git-receive-pack 'myapp.git'")
	defer func() {
		os.Args = []string{}
		os.Setenv("SSH_ORIGINAL_COMMAND", "")
	}()
	stdout := &bytes.Buffer{}
	executeAction(hasWritePermission, "You don't have access to write in this repository.", stdout)
	c.Assert(commandmocker.Ran(dir), gocheck.Equals, true)
	p, err := config.GetString("git:bare:location")
	c.Assert(err, gocheck.IsNil)
	expected := path.Join(p, "myapp.git")
	c.Assert(stdout.String(), gocheck.Equals, expected)
}

func (s *S) TestExecuteActionShouldNotCallSSH_ORIGINAL_COMMANDWhenUserDoesNotExists(c *gocheck.C) {
	dir, err := commandmocker.Add("git-receive-pack", "$*")
	c.Check(err, gocheck.IsNil)
	defer commandmocker.Remove(dir)
	os.Args = []string{"gandalf", "god"}
	os.Setenv("SSH_ORIGINAL_COMMAND", "git-receive-pack 'myapp.git'")
	defer func() {
		os.Args = []string{}
		os.Setenv("SSH_ORIGINAL_COMMAND", "")
	}()
	stdout := new(bytes.Buffer)
	errorMsg := "You don't have access to write in this repository."
	executeAction(hasWritePermission, errorMsg, stdout)
	c.Assert(commandmocker.Ran(dir), gocheck.Equals, false)
}

func (s *S) TestExecuteActionShouldNotCallSSH_ORIGINAL_COMMANDWhenRepositoryDoesNotExists(c *gocheck.C) {
	dir, err := commandmocker.Add("git-receive-pack", "$*")
	c.Check(err, gocheck.IsNil)
	defer commandmocker.Remove(dir)
	os.Args = []string{"gandalf", s.user.Name}
	os.Setenv("SSH_ORIGINAL_COMMAND", "git-receive-pack 'ghostapp.git'")
	defer func() {
		os.Args = []string{}
		os.Setenv("SSH_ORIGINAL_COMMAND", "")
	}()
	stdout := &bytes.Buffer{}
	errorMsg := "You don't have access to write in this repository."
	executeAction(hasWritePermission, errorMsg, stdout)
	c.Assert(commandmocker.Ran(dir), gocheck.Equals, false)
}

func (s *S) TestFormatCommandShouldReceiveAGitCommandAndCanonizalizeTheRepositoryPath(c *gocheck.C) {
	os.Setenv("SSH_ORIGINAL_COMMAND", "git-receive-pack 'myproject.git'")
	defer os.Setenv("SSH_ORIGINAL_COMMAND", "")
	cmd, err := formatCommand()
	c.Assert(err, gocheck.IsNil)
	p, err := config.GetString("git:bare:location")
	c.Assert(err, gocheck.IsNil)
	expected := path.Join(p, "myproject.git")
	c.Assert(cmd, gocheck.DeepEquals, []string{"git-receive-pack", expected})
}
<|endoftext|>


<commit_before>package openstack

import (
	"fmt"
	"log"
	"time"

	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/rackspace/gophercloud"
	"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs"
	"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups"
	"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
	"github.com/rackspace/gophercloud/pagination"
)

func resourceComputeInstance() *schema.Resource {
	return &schema.Resource{
		Create: resourceComputeInstanceCreate,
		Read:   resourceComputeInstanceRead,
		Update: resourceComputeInstanceUpdate,
		Delete: resourceComputeInstanceDelete,

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

			"image_ref": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: false,
			},

			"flavor_ref": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: false,
			},

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

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

			"networks": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				ForceNew: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"uuid": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
						},

						"port": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
						},

						"fixed_ip": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
						},
					},
				},
			},

			"metadata": &schema.Schema{
				Type:     schema.TypeMap,
				Optional: true,
				ForceNew: false,
			},

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

			"admin_pass": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: false,
			},

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

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

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

func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	osClient := config.computeV2Client

	var createOpts servers.CreateOptsBuilder

	serverCreateOpts := &servers.CreateOpts{
		Name:             d.Get("name").(string),
		ImageRef:         d.Get("image_ref").(string),
		FlavorRef:        d.Get("flavor_ref").(string),
		SecurityGroups:   resourceInstanceSecGroups(d),
		AvailabilityZone: d.Get("availability_zone").(string),
		Networks:         resourceInstanceNetworks(d),
		Metadata:         resourceInstanceMetadata(d),
		ConfigDrive:      d.Get("config_drive").(bool),
		AdminPass:        d.Get("admin_pass").(string),
	}

	if keyName, ok := d.Get("key_pair").(string); ok && keyName != "" {
		createOpts = &keypairs.CreateOptsExt{
			serverCreateOpts,
			keyName,
		}
	}

	log.Printf("[INFO] Requesting instance creation")
	server, err := servers.Create(osClient, createOpts).Extract()
	if err != nil {
		return fmt.Errorf("Error creating OpenStack server: %s", err)
	}
	log.Printf("[INFO] Instance ID: %s", server.ID)

	// Store the ID now
	d.SetId(server.ID)

	// Wait for the instance to become running so we can get some attributes
	// that aren't available until later.
	log.Printf(
		"[DEBUG] Waiting for instance (%s) to become running",
		server.ID)

	stateConf := &resource.StateChangeConf{
		Pending:    []string{"BUILD"},
		Target:     "ACTIVE",
		Refresh:    ServerStateRefreshFunc(osClient, server.ID),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	serverRaw, err := stateConf.WaitForState()
	if err != nil {
		return fmt.Errorf(
			"Error waiting for instance (%s) to become ready: %s",
			server.ID, err)
	}

	server = serverRaw.(*servers.Server)

	return resourceComputeInstanceRead(d, meta)
}

func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	osClient := config.computeV2Client

	server, err := servers.Get(osClient, d.Id()).Extract()
	if err != nil {
		return fmt.Errorf("Error retrieving OpenStack server: %s", err)
	}

	log.Printf("[DEBUG] Retreived Server %s: %+v", d.Id(), server)

	d.Set("name", server.Name)
	d.Set("access_ip_v4", server.AccessIPv4)
	d.Set("access_ip_v6", server.AccessIPv6)

	host := server.AccessIPv4
	if host == "" {
		if publicAddressesRaw, ok := server.Addresses["public"]; ok {
			publicAddresses := publicAddressesRaw.([]interface{})
			for _, paRaw := range publicAddresses {
				pa := paRaw.(map[string]interface{})
				if pa["version"].(float64) == 4 {
					host = pa["addr"].(string)
				}
			}
		}
	}

	log.Printf("host: %s", host)

	// Initialize the connection info
	d.SetConnInfo(map[string]string{
		"type": "ssh",
		"host": host,
	})

	d.Set("metadata", server.Metadata)

	var currentSG []string
	err = secgroups.ListByServer(osClient, d.Id()).EachPage(func(page pagination.Page) (bool, error) {
		secGrpList, err := secgroups.ExtractSecurityGroups(page)
		if err != nil {
			return false, fmt.Errorf("Error setting security groups for OpenStack server: %s", err)
		}

		for _, sg := range secGrpList {
			currentSG = append(currentSG, sg.Name)
		}

		return true, nil
	})
	d.Set("security_groups", currentSG)

	newFlavor, ok := server.Flavor["id"].(string)
	if !ok {
		return fmt.Errorf("Error setting OpenStack server's flavor: %v", newFlavor)
	}
	d.Set("flavor_ref", newFlavor)

	return nil
}

func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	osClient := config.computeV2Client

	var updateOpts servers.UpdateOpts
	// If the Metadata has changed, then update that.
	if d.HasChange("name") {
		updateOpts.Name = d.Get("name").(string)
	}
	if d.HasChange("access_ip_v4") {
		updateOpts.AccessIPv4 = d.Get("access_ip_v4").(string)
	}
	if d.HasChange("access_ip_v6") {
		updateOpts.AccessIPv4 = d.Get("access_ip_v6").(string)
	}

	// If there's nothing to update, don't waste an HTTP call.
	if updateOpts != (servers.UpdateOpts{}) {
		log.Printf("[DEBUG] Updating Server %s with options: %+v", d.Id(), updateOpts)

		_, err := servers.Update(osClient, d.Id(), updateOpts).Extract()
		if err != nil {
			return fmt.Errorf("Error updating OpenStack server: %s", err)
		}
	}

	if d.HasChange("metadata") {
		var metadataOpts servers.MetadataOpts
		metadataOpts = make(servers.MetadataOpts)
		newMetadata := d.Get("metadata").(map[string]interface{})
		for k, v := range newMetadata {
			metadataOpts[k] = v.(string)
		}

		_, err := servers.UpdateMetadata(osClient, d.Id(), metadataOpts).Extract()
		if err != nil {
			return fmt.Errorf("Error updating OpenStack server (%s) metadata: %s", d.Id(), err)
		}
	}

	if d.HasChange("security_groups") {
		oldSGRaw, newSGRaw := d.GetChange("security_groups")
		oldSGSet, newSGSet := oldSGRaw.(*schema.Set), newSGRaw.(*schema.Set)
		secgroupsToAdd := newSGSet.Difference(oldSGSet)
		secgroupsToRemove := oldSGSet.Difference(newSGSet)

		log.Printf("[DEBUG] Security groups to add: %v", secgroupsToAdd)

		log.Printf("[DEBUG] Security groups to remove: %v", secgroupsToRemove)

		for _, g := range secgroupsToAdd.List() {
			err := secgroups.AddServerToGroup(osClient, d.Id(), g.(string)).ExtractErr()
			if err != nil {
				return fmt.Errorf("Error adding security group to OpenStack server (%s): %s", d.Id(), err)
			}
			log.Printf("[DEBUG] Added security group (%s) to instance (%s)", g.(string), d.Id())
		}

		for _, g := range secgroupsToRemove.List() {
			err := secgroups.RemoveServerFromGroup(osClient, d.Id(), g.(string)).ExtractErr()
			if err != nil {
				return fmt.Errorf("Error removing security group from OpenStack server (%s): %s", d.Id(), err)
			}
			log.Printf("[DEBUG] Removed security group (%s) from instance (%s)", g.(string), d.Id())
		}
	}

	if d.HasChange("admin_pass") {
		if newPwd, ok := d.Get("admin_pass").(string); ok {
			err := servers.ChangeAdminPassword(osClient, d.Id(), newPwd).ExtractErr()
			if err != nil {
				return fmt.Errorf("Error changing admin password of OpenStack server (%s): %s", d.Id(), err)
			}
		}
	}

	if d.HasChange("flavor_ref") {
		resizeOpts := &servers.ResizeOpts{
			FlavorRef: d.Get("flavor_ref").(string),
		}
		err := servers.Resize(osClient, d.Id(), resizeOpts).ExtractErr()
		if err != nil {
			return fmt.Errorf("Error resizing OpenStack server: %s", err)
		}

		// Wait for the instance to finish resizing.
		log.Printf("[DEBUG] Waiting for instance (%s) to finish resizing", d.Id())

		stateConf := &resource.StateChangeConf{
			Pending:    []string{"RESIZE"},
			Target:     "VERIFY_RESIZE",
			Refresh:    ServerStateRefreshFunc(osClient, d.Id()),
			Timeout:    3 * time.Minute,
			Delay:      10 * time.Second,
			MinTimeout: 3 * time.Second,
		}

		_, err = stateConf.WaitForState()
		if err != nil {
			return fmt.Errorf("Error waiting for instance (%s) to resize: %s", d.Id(), err)
		}

		// Confirm resize.
		log.Printf("[DEBUG] Confirming resize")
		err = servers.ConfirmResize(osClient, d.Id()).ExtractErr()
		if err != nil {
			return fmt.Errorf("Error confirming resize of OpenStack server: %s", err)
		}

		stateConf = &resource.StateChangeConf{
			Pending:    []string{"VERIFY_RESIZE"},
			Target:     "ACTIVE",
			Refresh:    ServerStateRefreshFunc(osClient, d.Id()),
			Timeout:    3 * time.Minute,
			Delay:      10 * time.Second,
			MinTimeout: 3 * time.Second,
		}

		_, err = stateConf.WaitForState()
		if err != nil {
			return fmt.Errorf("Error waiting for instance (%s) to confirm resize: %s", d.Id(), err)
		}
	}

	return resourceComputeInstanceRead(d, meta)
}

func resourceComputeInstanceDelete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	osClient := config.computeV2Client

	err := servers.Delete(osClient, d.Id()).ExtractErr()
	if err != nil {
		return fmt.Errorf("Error deleting OpenStack server: %s", err)
	}

	// Wait for the instance to delete before moving on.
	log.Printf("[DEBUG] Waiting for instance (%s) to delete", d.Id())

	stateConf := &resource.StateChangeConf{
		Target:     "",
		Refresh:    ServerStateRefreshFunc(osClient, d.Id()),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, err = stateConf.WaitForState()
	if err != nil {
		return fmt.Errorf(
			"Error waiting for instance (%s) to delete: %s",
			d.Id(), err)
	}

	d.SetId("")
	return nil
}

// ServerStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// an OpenStack instance.
func ServerStateRefreshFunc(client *gophercloud.ServiceClient, instanceID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		s, err := servers.Get(client, instanceID).Extract()
		if err != nil {
			return nil, "", err
		}

		return s, s.Status, nil
	}
}

func resourceInstanceSecGroups(d *schema.ResourceData) []string {
	rawSecGroups := d.Get("security_groups").(*schema.Set)
	secgroups := make([]string, rawSecGroups.Len())
	for i, raw := range rawSecGroups.List() {
		secgroups[i] = raw.(string)
	}
	return secgroups
}

func resourceInstanceNetworks(d *schema.ResourceData) []servers.Network {
	rawNetworks := d.Get("networks").([]interface{})
	networks := make([]servers.Network, len(rawNetworks))
	for i, raw := range rawNetworks {
		rawMap := raw.(map[string]interface{})
		networks[i] = servers.Network{
			UUID:    rawMap["uuid"].(string),
			Port:    rawMap["port"].(string),
			FixedIP: rawMap["fixed_ip"].(string),
		}
	}
	return networks
}

func resourceInstanceMetadata(d *schema.ResourceData) map[string]string {
	m := make(map[string]string)
	for key, val := range d.Get("metadata").(map[string]interface{}) {
		m[key] = val.(string)
	}
	return m
}
<commit_msg>remove unneeded variables during server creation<commit_after>package openstack

import (
	"fmt"
	"log"
	"time"

	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/rackspace/gophercloud"
	"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs"
	"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups"
	"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
	"github.com/rackspace/gophercloud/pagination"
)

func resourceComputeInstance() *schema.Resource {
	return &schema.Resource{
		Create: resourceComputeInstanceCreate,
		Read:   resourceComputeInstanceRead,
		Update: resourceComputeInstanceUpdate,
		Delete: resourceComputeInstanceDelete,

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

			"image_ref": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: false,
			},

			"flavor_ref": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: false,
			},

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

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

			"networks": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				ForceNew: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"uuid": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
						},

						"port": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
						},

						"fixed_ip": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
						},
					},
				},
			},

			"metadata": &schema.Schema{
				Type:     schema.TypeMap,
				Optional: true,
				ForceNew: false,
			},

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

			"admin_pass": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: false,
			},

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

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

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

func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	osClient := config.computeV2Client

	var createOpts servers.CreateOptsBuilder

	serverCreateOpts := &servers.CreateOpts{
		Name:             d.Get("name").(string),
		ImageRef:         d.Get("image_ref").(string),
		FlavorRef:        d.Get("flavor_ref").(string),
		SecurityGroups:   resourceInstanceSecGroups(d),
		AvailabilityZone: d.Get("availability_zone").(string),
		Networks:         resourceInstanceNetworks(d),
		Metadata:         resourceInstanceMetadata(d),
		ConfigDrive:      d.Get("config_drive").(bool),
		AdminPass:        d.Get("admin_pass").(string),
	}

	if keyName, ok := d.Get("key_pair").(string); ok && keyName != "" {
		createOpts = &keypairs.CreateOptsExt{
			serverCreateOpts,
			keyName,
		}
	}

	log.Printf("[INFO] Requesting instance creation")
	server, err := servers.Create(osClient, createOpts).Extract()
	if err != nil {
		return fmt.Errorf("Error creating OpenStack server: %s", err)
	}
	log.Printf("[INFO] Instance ID: %s", server.ID)

	// Store the ID now
	d.SetId(server.ID)

	// Wait for the instance to become running so we can get some attributes
	// that aren't available until later.
	log.Printf(
		"[DEBUG] Waiting for instance (%s) to become running",
		server.ID)

	stateConf := &resource.StateChangeConf{
		Pending:    []string{"BUILD"},
		Target:     "ACTIVE",
		Refresh:    ServerStateRefreshFunc(osClient, server.ID),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, err = stateConf.WaitForState()
	if err != nil {
		return fmt.Errorf(
			"Error waiting for instance (%s) to become ready: %s",
			server.ID, err)
	}

	return resourceComputeInstanceRead(d, meta)
}

func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	osClient := config.computeV2Client

	server, err := servers.Get(osClient, d.Id()).Extract()
	if err != nil {
		return fmt.Errorf("Error retrieving OpenStack server: %s", err)
	}

	log.Printf("[DEBUG] Retreived Server %s: %+v", d.Id(), server)

	d.Set("name", server.Name)
	d.Set("access_ip_v4", server.AccessIPv4)
	d.Set("access_ip_v6", server.AccessIPv6)

	host := server.AccessIPv4
	if host == "" {
		if publicAddressesRaw, ok := server.Addresses["public"]; ok {
			publicAddresses := publicAddressesRaw.([]interface{})
			for _, paRaw := range publicAddresses {
				pa := paRaw.(map[string]interface{})
				if pa["version"].(float64) == 4 {
					host = pa["addr"].(string)
				}
			}
		}
	}

	log.Printf("host: %s", host)

	// Initialize the connection info
	d.SetConnInfo(map[string]string{
		"type": "ssh",
		"host": host,
	})

	d.Set("metadata", server.Metadata)

	var currentSG []string
	err = secgroups.ListByServer(osClient, d.Id()).EachPage(func(page pagination.Page) (bool, error) {
		secGrpList, err := secgroups.ExtractSecurityGroups(page)
		if err != nil {
			return false, fmt.Errorf("Error setting security groups for OpenStack server: %s", err)
		}

		for _, sg := range secGrpList {
			currentSG = append(currentSG, sg.Name)
		}

		return true, nil
	})
	d.Set("security_groups", currentSG)

	newFlavor, ok := server.Flavor["id"].(string)
	if !ok {
		return fmt.Errorf("Error setting OpenStack server's flavor: %v", newFlavor)
	}
	d.Set("flavor_ref", newFlavor)

	return nil
}

func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	osClient := config.computeV2Client

	var updateOpts servers.UpdateOpts
	// If the Metadata has changed, then update that.
	if d.HasChange("name") {
		updateOpts.Name = d.Get("name").(string)
	}
	if d.HasChange("access_ip_v4") {
		updateOpts.AccessIPv4 = d.Get("access_ip_v4").(string)
	}
	if d.HasChange("access_ip_v6") {
		updateOpts.AccessIPv4 = d.Get("access_ip_v6").(string)
	}

	// If there's nothing to update, don't waste an HTTP call.
	if updateOpts != (servers.UpdateOpts{}) {
		log.Printf("[DEBUG] Updating Server %s with options: %+v", d.Id(), updateOpts)

		_, err := servers.Update(osClient, d.Id(), updateOpts).Extract()
		if err != nil {
			return fmt.Errorf("Error updating OpenStack server: %s", err)
		}
	}

	if d.HasChange("metadata") {
		var metadataOpts servers.MetadataOpts
		metadataOpts = make(servers.MetadataOpts)
		newMetadata := d.Get("metadata").(map[string]interface{})
		for k, v := range newMetadata {
			metadataOpts[k] = v.(string)
		}

		_, err := servers.UpdateMetadata(osClient, d.Id(), metadataOpts).Extract()
		if err != nil {
			return fmt.Errorf("Error updating OpenStack server (%s) metadata: %s", d.Id(), err)
		}
	}

	if d.HasChange("security_groups") {
		oldSGRaw, newSGRaw := d.GetChange("security_groups")
		oldSGSet, newSGSet := oldSGRaw.(*schema.Set), newSGRaw.(*schema.Set)
		secgroupsToAdd := newSGSet.Difference(oldSGSet)
		secgroupsToRemove := oldSGSet.Difference(newSGSet)

		log.Printf("[DEBUG] Security groups to add: %v", secgroupsToAdd)

		log.Printf("[DEBUG] Security groups to remove: %v", secgroupsToRemove)

		for _, g := range secgroupsToAdd.List() {
			err := secgroups.AddServerToGroup(osClient, d.Id(), g.(string)).ExtractErr()
			if err != nil {
				return fmt.Errorf("Error adding security group to OpenStack server (%s): %s", d.Id(), err)
			}
			log.Printf("[DEBUG] Added security group (%s) to instance (%s)", g.(string), d.Id())
		}

		for _, g := range secgroupsToRemove.List() {
			err := secgroups.RemoveServerFromGroup(osClient, d.Id(), g.(string)).ExtractErr()
			if err != nil {
				return fmt.Errorf("Error removing security group from OpenStack server (%s): %s", d.Id(), err)
			}
			log.Printf("[DEBUG] Removed security group (%s) from instance (%s)", g.(string), d.Id())
		}
	}

	if d.HasChange("admin_pass") {
		if newPwd, ok := d.Get("admin_pass").(string); ok {
			err := servers.ChangeAdminPassword(osClient, d.Id(), newPwd).ExtractErr()
			if err != nil {
				return fmt.Errorf("Error changing admin password of OpenStack server (%s): %s", d.Id(), err)
			}
		}
	}

	if d.HasChange("flavor_ref") {
		resizeOpts := &servers.ResizeOpts{
			FlavorRef: d.Get("flavor_ref").(string),
		}
		err := servers.Resize(osClient, d.Id(), resizeOpts).ExtractErr()
		if err != nil {
			return fmt.Errorf("Error resizing OpenStack server: %s", err)
		}

		// Wait for the instance to finish resizing.
		log.Printf("[DEBUG] Waiting for instance (%s) to finish resizing", d.Id())

		stateConf := &resource.StateChangeConf{
			Pending:    []string{"RESIZE"},
			Target:     "VERIFY_RESIZE",
			Refresh:    ServerStateRefreshFunc(osClient, d.Id()),
			Timeout:    3 * time.Minute,
			Delay:      10 * time.Second,
			MinTimeout: 3 * time.Second,
		}

		_, err = stateConf.WaitForState()
		if err != nil {
			return fmt.Errorf("Error waiting for instance (%s) to resize: %s", d.Id(), err)
		}

		// Confirm resize.
		log.Printf("[DEBUG] Confirming resize")
		err = servers.ConfirmResize(osClient, d.Id()).ExtractErr()
		if err != nil {
			return fmt.Errorf("Error confirming resize of OpenStack server: %s", err)
		}

		stateConf = &resource.StateChangeConf{
			Pending:    []string{"VERIFY_RESIZE"},
			Target:     "ACTIVE",
			Refresh:    ServerStateRefreshFunc(osClient, d.Id()),
			Timeout:    3 * time.Minute,
			Delay:      10 * time.Second,
			MinTimeout: 3 * time.Second,
		}

		_, err = stateConf.WaitForState()
		if err != nil {
			return fmt.Errorf("Error waiting for instance (%s) to confirm resize: %s", d.Id(), err)
		}
	}

	return resourceComputeInstanceRead(d, meta)
}

func resourceComputeInstanceDelete(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	osClient := config.computeV2Client

	err := servers.Delete(osClient, d.Id()).ExtractErr()
	if err != nil {
		return fmt.Errorf("Error deleting OpenStack server: %s", err)
	}

	// Wait for the instance to delete before moving on.
	log.Printf("[DEBUG] Waiting for instance (%s) to delete", d.Id())

	stateConf := &resource.StateChangeConf{
		Target:     "",
		Refresh:    ServerStateRefreshFunc(osClient, d.Id()),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, err = stateConf.WaitForState()
	if err != nil {
		return fmt.Errorf(
			"Error waiting for instance (%s) to delete: %s",
			d.Id(), err)
	}

	d.SetId("")
	return nil
}

// ServerStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// an OpenStack instance.
func ServerStateRefreshFunc(client *gophercloud.ServiceClient, instanceID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		s, err := servers.Get(client, instanceID).Extract()
		if err != nil {
			return nil, "", err
		}

		return s, s.Status, nil
	}
}

func resourceInstanceSecGroups(d *schema.ResourceData) []string {
	rawSecGroups := d.Get("security_groups").(*schema.Set)
	secgroups := make([]string, rawSecGroups.Len())
	for i, raw := range rawSecGroups.List() {
		secgroups[i] = raw.(string)
	}
	return secgroups
}

func resourceInstanceNetworks(d *schema.ResourceData) []servers.Network {
	rawNetworks := d.Get("networks").([]interface{})
	networks := make([]servers.Network, len(rawNetworks))
	for i, raw := range rawNetworks {
		rawMap := raw.(map[string]interface{})
		networks[i] = servers.Network{
			UUID:    rawMap["uuid"].(string),
			Port:    rawMap["port"].(string),
			FixedIP: rawMap["fixed_ip"].(string),
		}
	}
	return networks
}

func resourceInstanceMetadata(d *schema.ResourceData) map[string]string {
	m := make(map[string]string)
	for key, val := range d.Get("metadata").(map[string]interface{}) {
		m[key] = val.(string)
	}
	return m
}
<|endoftext|>


<commit_before>package boltdb

import (
	"encoding/json"
	"fmt"
	"io"
	"os"
	"sync"
	"time"

	"github.com/asdine/storm"
	"github.com/asdine/storm/index"
	"github.com/boltdb/bolt"
	"github.com/hashicorp/raft"

	"github.com/gansoi/gansoi/database"
	"github.com/gansoi/gansoi/stats"
)

type (
	// BoltStore is the lowest level of the gansoi database, it represent the
	// on-disk database. BoltStore implements raft.FSM and database.LocalDatabase.
	BoltStore struct {
		dbMutex       sync.RWMutex
		db            *storm.DB
		listenersLock sync.RWMutex
		listeners     []database.LocalListener
	}
)

func init() {
	stats.CounterInit("database_saves")
	stats.CounterInit("database_deletes")
	stats.CounterInit("database_applied")
	stats.CounterInit("database_snapshot")
}

// NewBoltStore will instantiate a new BoltStore. path will be created if it
// doesn't exist.
func NewBoltStore(path string) (*BoltStore, error) {
	d := &BoltStore{}

	err := d.open(path)
	if err != nil {
		return nil, err
	}

	return d, nil
}

// Close will close the database. Accessing the database after this will
// result in a deadlock.
func (d *BoltStore) Close() error {
	d.dbMutex.RLock()
	return d.db.Close()
}

// open will open the underlying file storage.
func (d *BoltStore) open(filepath string) error {
	db, err := storm.Open(
		filepath,
		storm.BoltOptions(0600, &bolt.Options{Timeout: 1 * time.Second}),
		storm.AutoIncrement(),
	)
	if err != nil {
		return err
	}

	d.db = db

	return nil
}

// Storm will return the underlying Storm database.
func (d *BoltStore) Storm() *storm.DB {
	d.dbMutex.RLock()
	defer d.dbMutex.RUnlock()

	return d.db
}

// ProcessLogEntry will process the log entry and apply whatever needs doing.
func (d *BoltStore) ProcessLogEntry(entry *database.LogEntry) error {
	var err error

	var v interface{}

	switch entry.Command {
	case database.CommandSave:
		v, _ = entry.Payload()
		stats.CounterInc("database_saves", 1)
		err = d.Save(v)
	case database.CommandDelete:
		stats.CounterInc("database_deletes", 1)
		v, _ = entry.Payload()
		err = d.db.DeleteStruct(v)
	default:
		err = fmt.Errorf("not implemented")
	}

	go func(command database.Command, data interface{}, err error) {
		d.listenersLock.RLock()

		for _, listener := range d.listeners {
			listener.PostLocalApply(command, data, err)
		}

		d.listenersLock.RUnlock()
	}(entry.Command, v, err)

	return err
}

// Apply implements raft.FSM.
func (d *BoltStore) Apply(l *raft.Log) interface{} {
	stats.CounterInc("database_applied", 1)
	entry := &database.LogEntry{}
	err := json.Unmarshal(l.Data, entry)
	if err != nil {
		// This should not happen..?
		fmt.Printf("%s: '%s'\n", err.Error(), string(l.Data))
		return nil
	}

	return d.ProcessLogEntry(entry)
}

// Snapshot implements raft.FSM.
func (d *BoltStore) Snapshot() (raft.FSMSnapshot, error) {
	stats.CounterInc("database_snapshot", 1)
	return &Snapshot{db: d}, nil
}

// Restore implements raft.FSM.
func (d *BoltStore) Restore(source io.ReadCloser) error {
	db := d.Storm().Bolt
	d.dbMutex.Lock()
	defer d.dbMutex.Unlock()
	defer source.Close()

	path := db.Path()
	restorePath := path + ".restoretmp"

	file, err := os.Create(restorePath)
	if err != nil {
		return err
	}
	defer file.Close()

	_, err = io.Copy(file, source)
	if err != nil {
		return err
	}

	err = db.Close()
	if err != nil {
		return err
	}

	err = os.Remove(path)
	if err != nil {
		return err
	}

	err = os.Rename(restorePath, path)
	if err != nil {
		return err
	}

	err = d.open(path)
	if err != nil {
		return err
	}

	return nil
}

// Save will save an object to the database.
func (d *BoltStore) Save(data interface{}) error {
	d.dbMutex.RLock()
	defer d.dbMutex.RUnlock()

	return d.db.Save(data)
}

// One will retrieve one (or zero) record from the database.
func (d *BoltStore) One(fieldName string, value interface{}, to interface{}) error {
	d.dbMutex.RLock()
	defer d.dbMutex.RUnlock()

	err := d.db.One(fieldName, value, to)
	if err == storm.ErrNotFound {
		return database.ErrNotFound
	}

	return err
}

// All lists all kinds of a type.
func (d *BoltStore) All(to interface{}, limit int, skip int, reverse bool) error {
	d.dbMutex.RLock()
	defer d.dbMutex.RUnlock()

	err := d.db.All(to, func(opts *index.Options) {
		opts.Limit = limit
		opts.Skip = skip
		opts.Reverse = reverse
	})

	if err == storm.ErrNotFound {
		return database.ErrNotFound
	}

	return err
}

// RegisterLocalListener implements database.LocalDatabase.
func (d *BoltStore) RegisterLocalListener(listener database.LocalListener) {
	d.listenersLock.Lock()
	defer d.listenersLock.Unlock()

	d.listeners = append(d.listeners, listener)
}
<commit_msg>Do not wait for listeners in ProcessLogEntry().<commit_after>package boltdb

import (
	"encoding/json"
	"fmt"
	"io"
	"os"
	"sync"
	"time"

	"github.com/asdine/storm"
	"github.com/asdine/storm/index"
	"github.com/boltdb/bolt"
	"github.com/hashicorp/raft"

	"github.com/gansoi/gansoi/database"
	"github.com/gansoi/gansoi/stats"
)

type (
	// BoltStore is the lowest level of the gansoi database, it represent the
	// on-disk database. BoltStore implements raft.FSM and database.LocalDatabase.
	BoltStore struct {
		dbMutex       sync.RWMutex
		db            *storm.DB
		listenersLock sync.RWMutex
		listeners     []database.LocalListener
	}
)

func init() {
	stats.CounterInit("database_saves")
	stats.CounterInit("database_deletes")
	stats.CounterInit("database_applied")
	stats.CounterInit("database_snapshot")
}

// NewBoltStore will instantiate a new BoltStore. path will be created if it
// doesn't exist.
func NewBoltStore(path string) (*BoltStore, error) {
	d := &BoltStore{}

	err := d.open(path)
	if err != nil {
		return nil, err
	}

	return d, nil
}

// Close will close the database. Accessing the database after this will
// result in a deadlock.
func (d *BoltStore) Close() error {
	d.dbMutex.RLock()
	return d.db.Close()
}

// open will open the underlying file storage.
func (d *BoltStore) open(filepath string) error {
	db, err := storm.Open(
		filepath,
		storm.BoltOptions(0600, &bolt.Options{Timeout: 1 * time.Second}),
		storm.AutoIncrement(),
	)
	if err != nil {
		return err
	}

	d.db = db

	return nil
}

// Storm will return the underlying Storm database.
func (d *BoltStore) Storm() *storm.DB {
	d.dbMutex.RLock()
	defer d.dbMutex.RUnlock()

	return d.db
}

// ProcessLogEntry will process the log entry and apply whatever needs doing.
func (d *BoltStore) ProcessLogEntry(entry *database.LogEntry) error {
	var err error

	var v interface{}

	switch entry.Command {
	case database.CommandSave:
		v, _ = entry.Payload()
		stats.CounterInc("database_saves", 1)
		err = d.Save(v)
	case database.CommandDelete:
		stats.CounterInc("database_deletes", 1)
		v, _ = entry.Payload()
		err = d.db.DeleteStruct(v)
	default:
		err = fmt.Errorf("not implemented")
	}

	go func(command database.Command, data interface{}, err error) {
		d.listenersLock.RLock()

		for _, listener := range d.listeners {
			go listener.PostLocalApply(command, data, err)
		}

		d.listenersLock.RUnlock()
	}(entry.Command, v, err)

	return err
}

// Apply implements raft.FSM.
func (d *BoltStore) Apply(l *raft.Log) interface{} {
	stats.CounterInc("database_applied", 1)
	entry := &database.LogEntry{}
	err := json.Unmarshal(l.Data, entry)
	if err != nil {
		// This should not happen..?
		fmt.Printf("%s: '%s'\n", err.Error(), string(l.Data))
		return nil
	}

	return d.ProcessLogEntry(entry)
}

// Snapshot implements raft.FSM.
func (d *BoltStore) Snapshot() (raft.FSMSnapshot, error) {
	stats.CounterInc("database_snapshot", 1)
	return &Snapshot{db: d}, nil
}

// Restore implements raft.FSM.
func (d *BoltStore) Restore(source io.ReadCloser) error {
	db := d.Storm().Bolt
	d.dbMutex.Lock()
	defer d.dbMutex.Unlock()
	defer source.Close()

	path := db.Path()
	restorePath := path + ".restoretmp"

	file, err := os.Create(restorePath)
	if err != nil {
		return err
	}
	defer file.Close()

	_, err = io.Copy(file, source)
	if err != nil {
		return err
	}

	err = db.Close()
	if err != nil {
		return err
	}

	err = os.Remove(path)
	if err != nil {
		return err
	}

	err = os.Rename(restorePath, path)
	if err != nil {
		return err
	}

	err = d.open(path)
	if err != nil {
		return err
	}

	return nil
}

// Save will save an object to the database.
func (d *BoltStore) Save(data interface{}) error {
	d.dbMutex.RLock()
	defer d.dbMutex.RUnlock()

	return d.db.Save(data)
}

// One will retrieve one (or zero) record from the database.
func (d *BoltStore) One(fieldName string, value interface{}, to interface{}) error {
	d.dbMutex.RLock()
	defer d.dbMutex.RUnlock()

	err := d.db.One(fieldName, value, to)
	if err == storm.ErrNotFound {
		return database.ErrNotFound
	}

	return err
}

// All lists all kinds of a type.
func (d *BoltStore) All(to interface{}, limit int, skip int, reverse bool) error {
	d.dbMutex.RLock()
	defer d.dbMutex.RUnlock()

	err := d.db.All(to, func(opts *index.Options) {
		opts.Limit = limit
		opts.Skip = skip
		opts.Reverse = reverse
	})

	if err == storm.ErrNotFound {
		return database.ErrNotFound
	}

	return err
}

// RegisterLocalListener implements database.LocalDatabase.
func (d *BoltStore) RegisterLocalListener(listener database.LocalListener) {
	d.listenersLock.Lock()
	defer d.listenersLock.Unlock()

	d.listeners = append(d.listeners, listener)
}
<|endoftext|>


<commit_before>package processes

import(
	"fmt"
	"strings"
	"strconv"

	"github.com/ProhtMeyhet/libgosimpleton/iotool"
	"github.com/ProhtMeyhet/libgosimpleton/system/user"
)

// find processes by your custom order. iterates over every process, your function
// must give back true if found and false if not. if true, processes will contain
// this ProcessInfo. do not, i repeat, do not retain the *ProcessInfo - it is reused.
func FindBy(filter func(*ProcessInfo) bool) (processes []*ProcessInfo) {
	process := &ProcessInfo{}
	for process.findBy(filter) {
		processes = append(processes, process.MakeCopy())
	}; return
}

/* TODO
func FindFirstBy(filter func(*ProcessInfo) bool) (process *ProcessInfo) {
	process := &ProcessInfo{}
	process.findBy(filter)
	return
}

func FindLastBy(filter func(*ProcessInfo) bool) (process *ProcessInfo) {
	find := &ProcessInfo{}
	for find.findBy(filter) {
		process = find
	}; return
}*/

// find by a generating func
func FindByGenerator(generator func() func(*ProcessInfo) bool) (processes []*ProcessInfo) {
	return FindBy(generator())
}

// walk over every process and do your thing
func Walk(stick func(*ProcessInfo)) {
	process := &ProcessInfo{}
	for process.findBy(func(process *ProcessInfo) bool {
		stick(process.MakeCopy()); return false
	}) {}
}

// walk by generating func
func WalkByGenerator(generator func() func(*ProcessInfo)) {
	Walk(generator())
}

// find a process by pid
func Find(aid uint) (process *ProcessInfo, e error) {
	process = &ProcessInfo{ id: aid }
	return process, process.findById()
}

// find a process by pid given as string
func FindByStringId(aid string) (process *ProcessInfo, e error) {
	pid, e := strconv.ParseUint(aid, 10, 0); if e != nil { return }
	return Find(uint(pid))
}

// find processes by name
func FindByName(aname string) (processes []*ProcessInfo) {
	return FindBy(func(process *ProcessInfo) bool {
		return Contains(process, aname)
	})
}

// find processes by their exact name
func FindByExactName(aname string) (processes []*ProcessInfo) {
	return FindBy(func(process *ProcessInfo) bool {
		return Exact(process, aname)
	})
}

// today is the oldest you've ever been ...
func FindOldestByName(aname string) (oldest *ProcessInfo) {
	min := uint64(0)
	Walk(func(process *ProcessInfo) {
		if !Contains(process, aname) { return }
		if min == 0 || min >= process.relativeStartTime {
			min = process.relativeStartTime
			oldest = process
		}
	}); return
}

// ... and the youngest you'll ever be again
func FindYoungestByName(aname string) (youngest *ProcessInfo) {
	max := uint64(0)
	Walk(func(process *ProcessInfo) {
		if !Contains(process, aname) { return }
		if process.relativeStartTime >= max {
			max = process.relativeStartTime
			youngest = process
		}
	}); return
}

// read from /proc/self/
func Self() (process *ProcessInfo) {
	process = &ProcessInfo{}
	handler, _ := iotool.Open(iotool.ReadOnly(), fmt.Sprintf(PROC_STAT_FILE, "self"))
	process.scanStat(handler); return
}

/***** current user *****/

// find all current users processes
// panics if current user can't be determined
func FindMyAll() (processes []*ProcessInfo) {
	user, e := user.Current(); if e != nil { panic(e) }
	return FindBy(func(process *ProcessInfo) bool {
		return User(process, user)
	})
}

// find a process by pid
// panics if current user can't be determined
func FindMy(aid uint) (process *ProcessInfo) {
	user, e := user.Current(); if e != nil { panic(e) }
	process, e = Find(aid); if e != nil { return }
	if !User(process, user) { return }
	return
}

// find processes by name
// panics if current user can't be determined
func FindMyByName(aname string) (processes []*ProcessInfo) {
	user, e := user.Current(); if e != nil { panic(e) }
	return FindBy(func(process *ProcessInfo) bool {
		return User(process, user) && Contains(process, aname)
	})
}

// find processes by their exact name
// panics if current user can't be determined
func FindMyByExactName(aname string) (processes []*ProcessInfo) {
	user, e := user.Current(); if e != nil { panic(e) }
	return FindBy(func(process *ProcessInfo) bool {
		return User(process, user) && Exact(process, aname)
	})
}

/***** filters *****/

// contains
func Contains(process *ProcessInfo, aname string) bool {
	return strings.Contains(process.name, aname)
}

// exact name
func Exact(process *ProcessInfo, aname string) bool {
	return process.name == aname
}

// user id
func User(process *ProcessInfo, user user.UserInterface) bool {
	return uint32(process.owner) == user.Id()
}
<commit_msg>system/processes: add FindAll()<commit_after>package processes

import(
	"fmt"
	"strings"
	"strconv"

	"github.com/ProhtMeyhet/libgosimpleton/iotool"
	"github.com/ProhtMeyhet/libgosimpleton/system/user"
)

// find processes by your custom order. iterates over every process, your function
// must give back true if found and false if not. if true, processes will contain
// this ProcessInfo. do not, i repeat, do not retain the *ProcessInfo - it is reused.
func FindBy(filter func(*ProcessInfo) bool) (processes []*ProcessInfo) {
	process := &ProcessInfo{}
	for process.findBy(filter) {
		processes = append(processes, process.MakeCopy())
	}; return
}

func FindAll() (processes []*ProcessInfo) {
	process := &ProcessInfo{}
	for process.findBy(func(*ProcessInfo) bool { return true } ) {
		processes = append(processes, process.MakeCopy())
	}; return
}

/* TODO
func FindFirstBy(filter func(*ProcessInfo) bool) (process *ProcessInfo) {
	process := &ProcessInfo{}
	process.findBy(filter)
	return
}

func FindLastBy(filter func(*ProcessInfo) bool) (process *ProcessInfo) {
	find := &ProcessInfo{}
	for find.findBy(filter) {
		process = find
	}; return
}*/

// find by a generating func
func FindByGenerator(generator func() func(*ProcessInfo) bool) (processes []*ProcessInfo) {
	return FindBy(generator())
}

// walk over every process and do your thing
func Walk(stick func(*ProcessInfo)) {
	process := &ProcessInfo{}
	for process.findBy(func(process *ProcessInfo) bool {
		stick(process.MakeCopy()); return false
	}) {}
}

// walk by generating func
func WalkByGenerator(generator func() func(*ProcessInfo)) {
	Walk(generator())
}

// find a process by pid
func Find(aid uint) (process *ProcessInfo, e error) {
	process = &ProcessInfo{ id: aid }
	return process, process.findById()
}

// find a process by pid given as string
func FindByStringId(aid string) (process *ProcessInfo, e error) {
	pid, e := strconv.ParseUint(aid, 10, 0); if e != nil { return }
	return Find(uint(pid))
}

// find processes by name
func FindByName(aname string) (processes []*ProcessInfo) {
	return FindBy(func(process *ProcessInfo) bool {
		return Contains(process, aname)
	})
}

// find processes by their exact name
func FindByExactName(aname string) (processes []*ProcessInfo) {
	return FindBy(func(process *ProcessInfo) bool {
		return Exact(process, aname)
	})
}

// today is the oldest you've ever been ...
func FindOldestByName(aname string) (oldest *ProcessInfo) {
	min := uint64(0)
	Walk(func(process *ProcessInfo) {
		if !Contains(process, aname) { return }
		if min == 0 || min >= process.relativeStartTime {
			min = process.relativeStartTime
			oldest = process
		}
	}); return
}

// ... and the youngest you'll ever be again
func FindYoungestByName(aname string) (youngest *ProcessInfo) {
	max := uint64(0)
	Walk(func(process *ProcessInfo) {
		if !Contains(process, aname) { return }
		if process.relativeStartTime >= max {
			max = process.relativeStartTime
			youngest = process
		}
	}); return
}

// read from /proc/self/
func Self() (process *ProcessInfo) {
	process = &ProcessInfo{}
	handler, _ := iotool.Open(iotool.ReadOnly(), fmt.Sprintf(PROC_STAT_FILE, "self"))
	process.scanStat(handler); return
}

/***** current user *****/

// find all current users processes
// panics if current user can't be determined
func FindMyAll() (processes []*ProcessInfo) {
	user, e := user.Current(); if e != nil { panic(e) }
	return FindBy(func(process *ProcessInfo) bool {
		return User(process, user)
	})
}

// find a process by pid
// panics if current user can't be determined
func FindMy(aid uint) (process *ProcessInfo) {
	user, e := user.Current(); if e != nil { panic(e) }
	process, e = Find(aid); if e != nil { return }
	if !User(process, user) { return }
	return
}

// find processes by name
// panics if current user can't be determined
func FindMyByName(aname string) (processes []*ProcessInfo) {
	user, e := user.Current(); if e != nil { panic(e) }
	return FindBy(func(process *ProcessInfo) bool {
		return User(process, user) && Contains(process, aname)
	})
}

// find processes by their exact name
// panics if current user can't be determined
func FindMyByExactName(aname string) (processes []*ProcessInfo) {
	user, e := user.Current(); if e != nil { panic(e) }
	return FindBy(func(process *ProcessInfo) bool {
		return User(process, user) && Exact(process, aname)
	})
}

/***** filters *****/

// contains
func Contains(process *ProcessInfo, aname string) bool {
	return strings.Contains(process.name, aname)
}

// exact name
func Exact(process *ProcessInfo, aname string) bool {
	return process.name == aname
}

// user id
func User(process *ProcessInfo, user user.UserInterface) bool {
	return uint32(process.owner) == user.Id()
}
<|endoftext|>


<commit_before>package dockerclient

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"sync/atomic"
	"time"
)

type DockerClient struct {
	URL           *url.URL
	HTTPClient    *http.Client
	monitorEvents int32
}

func NewDockerClient(daemonUrl string) (*DockerClient, error) {
	u, err := url.Parse(daemonUrl)
	if err != nil {
		return nil, err
	}
	httpClient := newHTTPClient(u)
	return &DockerClient{u, httpClient, 0}, nil
}

func newHTTPClient(u *url.URL) *http.Client {
	httpTransport := &http.Transport{}
	if u.Scheme == "unix" {
		socketPath := u.Path
		unixDial := func(proto string, addr string) (net.Conn, error) {
			return net.Dial("unix", socketPath)
		}
		httpTransport.Dial = unixDial
		// Override the main URL object so the HTTP lib won't complain
		u.Scheme = "http"
		u.Host = "unix.sock"
	}
	u.Path = ""
	return &http.Client{Transport: httpTransport}
}

func (client *DockerClient) doRequest(method string, path string, body []byte) ([]byte, error) {
	b := bytes.NewBuffer(body)
	req, err := http.NewRequest(method, client.URL.String()+path, b)
	if err != nil {
		return nil, err
	}
	resp, err := client.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode >= 400 {
		return nil, fmt.Errorf("%s: %s", resp.Status, data)
	}
	return data, nil
}

func (client *DockerClient) ListContainers(all bool) ([]Container, error) {
	argAll := 0
	if all == true {
		argAll = 1
	}
	args := fmt.Sprintf("?all=%d", argAll)
	data, err := client.doRequest("GET", "/v1.8/containers/json"+args, nil)
	if err != nil {
		return nil, err
	}
	ret := []Container{}
	err = json.Unmarshal(data, &ret)
	if err != nil {
		return nil, err
	}
	return ret, nil
}

func (client *DockerClient) InspectContainer(id string) (*ContainerInfo, error) {
	uri := fmt.Sprintf("/v1.8/containers/%s/json", id)
	data, err := client.doRequest("GET", uri, nil)
	if err != nil {
		return nil, err
	}
	info := &ContainerInfo{}
	err = json.Unmarshal(data, info)
	if err != nil {
		return nil, err
	}
	return info, nil
}

func (client *DockerClient) CreateContainer(config *ContainerConfig) (string, error) {
	data, err := json.Marshal(config)
	if err != nil {
		return "", err
	}
	uri := "/v1.8/containers/create"
	data, err = client.doRequest("POST", uri, data)
	if err != nil {
		return "", err
	}
	fmt.Println(string(data))
	result := make(map[string]string)
	err = json.Unmarshal(data, &result)
	if err != nil {
		return "", err
	}
	return result["Id"], nil
}

func (client *DockerClient) StartContainer(id string) error {
	uri := fmt.Sprintf("/v1.8/containers/%s/start", id)
	_, err := client.doRequest("POST", uri, nil)
	if err != nil {
		return err
	}
	return nil
}

func (client *DockerClient) StopContainer(id string, timeout int) error {
	uri := fmt.Sprintf("/v1.8/containers/%s/stop?t=%d", id, timeout)
	_, err := client.doRequest("POST", uri, nil)
	if err != nil {
		return err
	}
	return nil
}

func (client *DockerClient) RestartContainer(id string, timeout int) error {
	uri := fmt.Sprintf("/v1.8/containers/%s/restart?t=%d", id, timeout)
	_, err := client.doRequest("POST", uri, nil)
	if err != nil {
		return err
	}
	return nil
}

func (client *DockerClient) KillContainer(id string) error {
	uri := fmt.Sprintf("/v1.8/containers/%s/kill", id)
	_, err := client.doRequest("POST", uri, nil)
	if err != nil {
		return err
	}
	return nil
}

func (client *DockerClient) StartMonitorEvents(cb func(*Event, ...interface{}), args ...interface{}) {
	atomic.StoreInt32(&client.monitorEvents, 1)
	wait := 100 * time.Millisecond
	buffer := make([]byte, 4096)
	var running int32 = 1
	go func() {
		for running > 0 {
			running = atomic.LoadInt32(&client.monitorEvents)
			if running == 0 {
				break
			}
			uri := client.URL.String() + "/v1.8/events"
			resp, err := client.HTTPClient.Get(uri)
			if err != nil {
				time.Sleep(wait)
				continue
			}
			if resp.StatusCode >= 300 {
				resp.Body.Close()
				time.Sleep(wait)
				continue
			}
			for {
				_, err = resp.Body.Read(buffer)
				if err != nil {
					resp.Body.Close()
					time.Sleep(wait)
					break
				}
				event := &Event{}
				err = json.Unmarshal(buffer, event)
				if err == nil {
					cb(event, args...)
				}
			}
			time.Sleep(wait)
		}
	}()
}

func (client *DockerClient) StopAllMonitorEvents() {
	atomic.StoreInt32(&client.monitorEvents, 0)
}

func (client *DockerClient) Version() (*Version, error) {
	data, err := client.doRequest("GET", "/v1.8/version", nil)
	if err != nil {
		return nil, err
	}
	version := &Version{}
	err = json.Unmarshal(data, version)
	if err != nil {
		return nil, err
	}
	return version, nil
}
<commit_msg>Fixed event parsing<commit_after>package dockerclient

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"sync/atomic"
	"time"
)

type DockerClient struct {
	URL           *url.URL
	HTTPClient    *http.Client
	monitorEvents int32
}

func NewDockerClient(daemonUrl string) (*DockerClient, error) {
	u, err := url.Parse(daemonUrl)
	if err != nil {
		return nil, err
	}
	httpClient := newHTTPClient(u)
	return &DockerClient{u, httpClient, 0}, nil
}

func newHTTPClient(u *url.URL) *http.Client {
	httpTransport := &http.Transport{}
	if u.Scheme == "unix" {
		socketPath := u.Path
		unixDial := func(proto string, addr string) (net.Conn, error) {
			return net.Dial("unix", socketPath)
		}
		httpTransport.Dial = unixDial
		// Override the main URL object so the HTTP lib won't complain
		u.Scheme = "http"
		u.Host = "unix.sock"
	}
	u.Path = ""
	return &http.Client{Transport: httpTransport}
}

func (client *DockerClient) doRequest(method string, path string, body []byte) ([]byte, error) {
	b := bytes.NewBuffer(body)
	req, err := http.NewRequest(method, client.URL.String()+path, b)
	if err != nil {
		return nil, err
	}
	resp, err := client.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode >= 400 {
		return nil, fmt.Errorf("%s: %s", resp.Status, data)
	}
	return data, nil
}

func (client *DockerClient) ListContainers(all bool) ([]Container, error) {
	argAll := 0
	if all == true {
		argAll = 1
	}
	args := fmt.Sprintf("?all=%d", argAll)
	data, err := client.doRequest("GET", "/v1.8/containers/json"+args, nil)
	if err != nil {
		return nil, err
	}
	ret := []Container{}
	err = json.Unmarshal(data, &ret)
	if err != nil {
		return nil, err
	}
	return ret, nil
}

func (client *DockerClient) InspectContainer(id string) (*ContainerInfo, error) {
	uri := fmt.Sprintf("/v1.8/containers/%s/json", id)
	data, err := client.doRequest("GET", uri, nil)
	if err != nil {
		return nil, err
	}
	info := &ContainerInfo{}
	err = json.Unmarshal(data, info)
	if err != nil {
		return nil, err
	}
	return info, nil
}

func (client *DockerClient) CreateContainer(config *ContainerConfig) (string, error) {
	data, err := json.Marshal(config)
	if err != nil {
		return "", err
	}
	uri := "/v1.8/containers/create"
	data, err = client.doRequest("POST", uri, data)
	if err != nil {
		return "", err
	}
	fmt.Println(string(data))
	result := make(map[string]string)
	err = json.Unmarshal(data, &result)
	if err != nil {
		return "", err
	}
	return result["Id"], nil
}

func (client *DockerClient) StartContainer(id string) error {
	uri := fmt.Sprintf("/v1.8/containers/%s/start", id)
	_, err := client.doRequest("POST", uri, nil)
	if err != nil {
		return err
	}
	return nil
}

func (client *DockerClient) StopContainer(id string, timeout int) error {
	uri := fmt.Sprintf("/v1.8/containers/%s/stop?t=%d", id, timeout)
	_, err := client.doRequest("POST", uri, nil)
	if err != nil {
		return err
	}
	return nil
}

func (client *DockerClient) RestartContainer(id string, timeout int) error {
	uri := fmt.Sprintf("/v1.8/containers/%s/restart?t=%d", id, timeout)
	_, err := client.doRequest("POST", uri, nil)
	if err != nil {
		return err
	}
	return nil
}

func (client *DockerClient) KillContainer(id string) error {
	uri := fmt.Sprintf("/v1.8/containers/%s/kill", id)
	_, err := client.doRequest("POST", uri, nil)
	if err != nil {
		return err
	}
	return nil
}

func (client *DockerClient) StartMonitorEvents(cb func(*Event, ...interface{}), args ...interface{}) {
	atomic.StoreInt32(&client.monitorEvents, 1)
	wait := 100 * time.Millisecond
	buffer := make([]byte, 4096)
	var running int32 = 1
	go func() {
		for running > 0 {
			running = atomic.LoadInt32(&client.monitorEvents)
			if running == 0 {
				break
			}
			uri := client.URL.String() + "/v1.8/events"
			resp, err := client.HTTPClient.Get(uri)
			if err != nil {
				time.Sleep(wait)
				continue
			}
			if resp.StatusCode >= 300 {
				resp.Body.Close()
				time.Sleep(wait)
				continue
			}
			for {
				nBytes, err := resp.Body.Read(buffer)
				if err != nil {
					resp.Body.Close()
					time.Sleep(wait)
					break
				}
				event := &Event{}
				err = json.Unmarshal(buffer[:nBytes], event)
				if err == nil {
					cb(event, args...)
				}
			}
			time.Sleep(wait)
		}
	}()
}

func (client *DockerClient) StopAllMonitorEvents() {
	atomic.StoreInt32(&client.monitorEvents, 0)
}

func (client *DockerClient) Version() (*Version, error) {
	data, err := client.doRequest("GET", "/v1.8/version", nil)
	if err != nil {
		return nil, err
	}
	version := &Version{}
	err = json.Unmarshal(data, version)
	if err != nil {
		return nil, err
	}
	return version, nil
}
<|endoftext|>


<commit_before>package docs

import (
	"reflect"
	"testing"

	"github.com/tochti/docMa-handler/common"
	"github.com/tochti/docMa-handler/labels"
)

func Test_FindAllLabelsOfDoc(t *testing.T) {
	db := common.InitTestDB(t, AddTables, labels.AddTables)

	label := labels.Label{
		ID:   1,
		Name: "label",
	}

	doc := Doc{
		ID:   1,
		Name: "karl.pdf",
	}

	docsLabels := DocsLabels{
		DocID:   doc.ID,
		LabelID: label.ID,
	}

	if err := db.Insert(&label); err != nil {
		t.Fatal(err)
	}

	if err := db.Insert(&doc); err != nil {
		t.Fatal(err)
	}

	if err := db.Insert(&docsLabels); err != nil {
		t.Fatal(err)
	}

	r, err := FindLabelsOfDoc(db, doc.ID)
	if err != nil {
		t.Fatal(err)
	}

	expect := []labels.Label{label}
	ok := reflect.DeepEqual(expect, r)
	if !ok {
		t.Fatalf("Expect %v was %v", expect, r)
	}

}
<commit_msg>mod test name<commit_after>package docs

import (
	"reflect"
	"testing"

	"github.com/tochti/docMa-handler/common"
	"github.com/tochti/docMa-handler/labels"
)

func Test_FindLabelsOfDoc(t *testing.T) {
	db := common.InitTestDB(t, AddTables, labels.AddTables)

	label := labels.Label{
		ID:   1,
		Name: "label",
	}

	doc := Doc{
		ID:   1,
		Name: "karl.pdf",
	}

	docsLabels := DocsLabels{
		DocID:   doc.ID,
		LabelID: label.ID,
	}

	if err := db.Insert(&label); err != nil {
		t.Fatal(err)
	}

	if err := db.Insert(&doc); err != nil {
		t.Fatal(err)
	}

	if err := db.Insert(&docsLabels); err != nil {
		t.Fatal(err)
	}

	r, err := FindLabelsOfDoc(db, doc.ID)
	if err != nil {
		t.Fatal(err)
	}

	expect := []labels.Label{label}
	ok := reflect.DeepEqual(expect, r)
	if !ok {
		t.Fatalf("Expect %v was %v", expect, r)
	}

}
<|endoftext|>


<commit_before><commit_msg>Update recon url to prod (#760)<commit_after><|endoftext|>


<commit_before>package torpedo_cleverbot_plugin

import (
	"flag"
	"fmt"
	"log"

	common "github.com/tb0hdan/torpedo_common"
	"github.com/tb0hdan/torpedo_registry"
	"github.com/ugjka/cleverbot-go"
)

var (
	CleverBotAPIKey *string
	Jobs            chan ChannelItem
	WP              *WorkerPool
)

type ChannelItem struct {
	API       *torpedo_registry.BotAPI
	ChannelID interface{}
	Message   string
}

type WorkerPool struct {
	APIKey  string
	Logger  *log.Logger
	Workers map[string]chan ChannelItem
}

func (wp *WorkerPool) dispatch(jobs <-chan ChannelItem) {
	wp.Workers = make(map[string]chan ChannelItem)
	for job := range jobs {
		wch, ok := wp.Workers[fmt.Sprintf("%+v", job.ChannelID)]
		if ok {
			// worker already started, pass job item
			wch <- job
		} else {
			// start new worker and process message
			ch := make(chan ChannelItem)
			wid := fmt.Sprintf("%+v", job.ChannelID)
			wp.Workers[wid] = ch
			go wp.worker(wid, ch)
			ch <- job
		}
	}
}

func (wp *WorkerPool) worker(wid string, jobs <-chan ChannelItem) {
	session := cleverbot.New(wp.APIKey)
	wp.Logger.Printf("Worker %s start\n", wid)
	for job := range jobs {
		answer, err := session.Ask(job.Message)
		if err == nil {
			job.API.Bot.PostMessage(job.ChannelID, answer, job.API)
		} else {
			wp.Logger.Printf("Error in CleverBot worker: %+v\n", err)
		}
	}
	wp.Logger.Printf("Worker %s exit\n", wid)
}

func CleverBotBackgroundTask(cfg *torpedo_registry.ConfigStruct) {
	WP.APIKey = torpedo_registry.Config.GetConfig()["cleverbot"]
	//defer close(jobs)
	go WP.dispatch(Jobs)
}

func CleverBotProcessMessage(api *torpedo_registry.BotAPI, channel interface{}, incoming_message string) {
	channelItem := ChannelItem{api, channel, incoming_message}
	Jobs <- channelItem
	return
}

func CleverBotPreParser(cfg *torpedo_registry.ConfigStruct) {
	CleverBotAPIKey = flag.String("cleverbot", "", "CleverBot.com API Key")

}

func CleverBotPostParser(cfg *torpedo_registry.ConfigStruct) {
	cfg.SetConfig("cleverbot", *CleverBotAPIKey)
	if cfg.GetConfig()["cleverbot"] == "" {
		cfg.SetConfig("cleverbot", common.GetStripEnv("CLEVERBOT_API_KEY"))
	}
}

func init() {
	WP = &WorkerPool{}
	cu := &common.Utils{}
	WP.Logger = cu.NewLog("cleverbot-process-message")
	Jobs = make(chan ChannelItem)
	torpedo_registry.Config.RegisterParser("talk", CleverBotPreParser, CleverBotPostParser)
	torpedo_registry.Config.RegisterHelpAndHandler("talk", "Say something to bot.", CleverBotProcessMessage)
	torpedo_registry.Config.RegisterCoroutine("talk", CleverBotBackgroundTask)
}
<commit_msg>cleverbot update<commit_after>package torpedo_cleverbot_plugin

import (
	"flag"
	"fmt"
	"log"

	common "github.com/tb0hdan/torpedo_common"
	"github.com/tb0hdan/torpedo_registry"
	"github.com/ugjka/cleverbot-go"
)

var (
	CleverBotAPIKey *string
	Jobs            chan ChannelItem
	WP              *WorkerPool
)

type ChannelItem struct {
	API       *torpedo_registry.BotAPI
	ChannelID interface{}
	Message   string
}

type WorkerPool struct {
	APIKey  string
	Logger  *log.Logger
	Workers map[string]chan ChannelItem
}

func (wp *WorkerPool) dispatch(jobs <-chan ChannelItem) {
	wp.Workers = make(map[string]chan ChannelItem)
	for job := range jobs {
		wch, ok := wp.Workers[fmt.Sprintf("%+v", job.ChannelID)]
		if ok {
			// worker already started, pass job item
			wch <- job
		} else {
			// start new worker and process message
			ch := make(chan ChannelItem)
			wid := fmt.Sprintf("%+v", job.ChannelID)
			wp.Workers[wid] = ch
			go wp.worker(wid, ch)
			ch <- job
		}
	}
}

func (wp *WorkerPool) worker(wid string, jobs <-chan ChannelItem) {
	session := cleverbot.New(wp.APIKey)
	wp.Logger.Printf("Worker %s start\n", wid)
	for job := range jobs {
		answer, err := session.Ask(job.Message)
		if err == nil {
			wp.Logger.Printf("Req/Resp: `%s` -> `%s`", job.Message, answer)
			job.API.Bot.PostMessage(job.ChannelID, answer, job.API)
		} else {
			wp.Logger.Printf("Error in CleverBot worker: %+v\n", err)
		}
	}
	wp.Logger.Printf("Worker %s exit\n", wid)
}

func CleverBotBackgroundTask(cfg *torpedo_registry.ConfigStruct) {
	WP.APIKey = torpedo_registry.Config.GetConfig()["cleverbot"]
	//defer close(jobs)
	go WP.dispatch(Jobs)
}

func CleverBotProcessMessage(api *torpedo_registry.BotAPI, channel interface{}, incoming_message string) {
	_, command, _ := common.GetRequestedFeature(incoming_message)
	channelItem := ChannelItem{api, channel, command}
	Jobs <- channelItem
	return
}

func CleverBotPreParser(cfg *torpedo_registry.ConfigStruct) {
	CleverBotAPIKey = flag.String("cleverbot", "", "CleverBot.com API Key")

}

func CleverBotPostParser(cfg *torpedo_registry.ConfigStruct) {
	cfg.SetConfig("cleverbot", *CleverBotAPIKey)
	if cfg.GetConfig()["cleverbot"] == "" {
		cfg.SetConfig("cleverbot", common.GetStripEnv("CLEVERBOT_API_KEY"))
	}
}

func init() {
	WP = &WorkerPool{}
	cu := &common.Utils{}
	WP.Logger = cu.NewLog("cleverbot-process-message")
	Jobs = make(chan ChannelItem)
	torpedo_registry.Config.RegisterParser("talk", CleverBotPreParser, CleverBotPostParser)
	torpedo_registry.Config.RegisterHelpAndHandler("talk", "Say something to bot.", CleverBotProcessMessage)
	torpedo_registry.Config.RegisterCoroutine("talk", CleverBotBackgroundTask)
}
<|endoftext|>


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

package pull

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"

	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/git"
	"code.gitea.io/gitea/modules/graceful"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/notification"
	"code.gitea.io/gitea/modules/queue"
	"code.gitea.io/gitea/modules/timeutil"
	"code.gitea.io/gitea/modules/util"
)

// prQueue represents a queue to handle update pull request tests
var prQueue queue.UniqueQueue

// AddToTaskQueue adds itself to pull request test task queue.
func AddToTaskQueue(pr *models.PullRequest) {
	go func() {
		err := prQueue.PushFunc(strconv.FormatInt(pr.ID, 10), func() error {
			pr.Status = models.PullRequestStatusChecking
			err := pr.UpdateColsIfNotMerged("status")
			if err != nil {
				log.Error("AddToTaskQueue.UpdateCols[%d].(add to queue): %v", pr.ID, err)
			} else {
				log.Trace("Adding PR ID: %d to the test pull requests queue", pr.ID)
			}
			return err
		})
		if err != nil && err != queue.ErrAlreadyInQueue {
			log.Error("Error adding prID %d to the test pull requests queue: %v", pr.ID, err)
		}
	}()
}

// checkAndUpdateStatus checks if pull request is possible to leaving checking status,
// and set to be either conflict or mergeable.
func checkAndUpdateStatus(pr *models.PullRequest) {
	// Status is not changed to conflict means mergeable.
	if pr.Status == models.PullRequestStatusChecking {
		pr.Status = models.PullRequestStatusMergeable
	}

	// Make sure there is no waiting test to process before leaving the checking status.
	has, err := prQueue.Has(strconv.FormatInt(pr.ID, 10))
	if err != nil {
		log.Error("Unable to check if the queue is waiting to reprocess pr.ID %d. Error: %v", pr.ID, err)
	}

	if !has {
		if err := pr.UpdateColsIfNotMerged("merge_base", "status", "conflicted_files", "changed_protected_files"); err != nil {
			log.Error("Update[%d]: %v", pr.ID, err)
		}
	}
}

// getMergeCommit checks if a pull request got merged
// Returns the git.Commit of the pull request if merged
func getMergeCommit(pr *models.PullRequest) (*git.Commit, error) {
	if pr.BaseRepo == nil {
		var err error
		pr.BaseRepo, err = models.GetRepositoryByID(pr.BaseRepoID)
		if err != nil {
			return nil, fmt.Errorf("GetRepositoryByID: %v", err)
		}
	}

	indexTmpPath, err := ioutil.TempDir(os.TempDir(), "gitea-"+pr.BaseRepo.Name)
	if err != nil {
		return nil, fmt.Errorf("Failed to create temp dir for repository %s: %v", pr.BaseRepo.RepoPath(), err)
	}
	defer func() {
		if err := util.RemoveAll(indexTmpPath); err != nil {
			log.Warn("Unable to remove temporary index path: %s: Error: %v", indexTmpPath, err)
		}
	}()

	headFile := pr.GetGitRefName()

	// Check if a pull request is merged into BaseBranch
	_, err = git.NewCommand("merge-base", "--is-ancestor", headFile, pr.BaseBranch).
		RunInDirWithEnv(pr.BaseRepo.RepoPath(), []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()})
	if err != nil {
		// Errors are signaled by a non-zero status that is not 1
		if strings.Contains(err.Error(), "exit status 1") {
			return nil, nil
		}
		return nil, fmt.Errorf("git merge-base --is-ancestor: %v", err)
	}

	commitIDBytes, err := ioutil.ReadFile(pr.BaseRepo.RepoPath() + "/" + headFile)
	if err != nil {
		return nil, fmt.Errorf("ReadFile(%s): %v", headFile, err)
	}
	commitID := string(commitIDBytes)
	if len(commitID) < 40 {
		return nil, fmt.Errorf(`ReadFile(%s): invalid commit-ID "%s"`, headFile, commitID)
	}
	cmd := commitID[:40] + ".." + pr.BaseBranch

	// Get the commit from BaseBranch where the pull request got merged
	mergeCommit, err := git.NewCommand("rev-list", "--ancestry-path", "--merges", "--reverse", cmd).
		RunInDirWithEnv("", []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()})
	if err != nil {
		return nil, fmt.Errorf("git rev-list --ancestry-path --merges --reverse: %v", err)
	} else if len(mergeCommit) < 40 {
		// PR was maybe fast-forwarded, so just use last commit of PR
		mergeCommit = commitID[:40]
	}

	gitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath())
	if err != nil {
		return nil, fmt.Errorf("OpenRepository: %v", err)
	}
	defer gitRepo.Close()

	commit, err := gitRepo.GetCommit(mergeCommit[:40])
	if err != nil {
		return nil, fmt.Errorf("GetCommit: %v", err)
	}

	return commit, nil
}

// manuallyMerged checks if a pull request got manually merged
// When a pull request got manually merged mark the pull request as merged
func manuallyMerged(pr *models.PullRequest) bool {
	if err := pr.LoadBaseRepo(); err != nil {
		log.Error("PullRequest[%d].LoadBaseRepo: %v", pr.ID, err)
		return false
	}

	if unit, err := pr.BaseRepo.GetUnit(models.UnitTypePullRequests); err == nil {
		config := unit.PullRequestsConfig()
		if !config.AutodetectManualMerge {
			return false
		}
	} else {
		log.Error("PullRequest[%d].BaseRepo.GetUnit(models.UnitTypePullRequests): %v", pr.ID, err)
		return false
	}

	commit, err := getMergeCommit(pr)
	if err != nil {
		log.Error("PullRequest[%d].getMergeCommit: %v", pr.ID, err)
		return false
	}
	if commit != nil {
		pr.MergedCommitID = commit.ID.String()
		pr.MergedUnix = timeutil.TimeStamp(commit.Author.When.Unix())
		pr.Status = models.PullRequestStatusManuallyMerged
		merger, _ := models.GetUserByEmail(commit.Author.Email)

		// When the commit author is unknown set the BaseRepo owner as merger
		if merger == nil {
			if pr.BaseRepo.Owner == nil {
				if err = pr.BaseRepo.GetOwner(); err != nil {
					log.Error("BaseRepo.GetOwner[%d]: %v", pr.ID, err)
					return false
				}
			}
			merger = pr.BaseRepo.Owner
		}
		pr.Merger = merger
		pr.MergerID = merger.ID

		if merged, err := pr.SetMerged(); err != nil {
			log.Error("PullRequest[%d].setMerged : %v", pr.ID, err)
			return false
		} else if !merged {
			return false
		}

		notification.NotifyMergePullRequest(pr, merger)

		log.Info("manuallyMerged[%d]: Marked as manually merged into %s/%s by commit id: %s", pr.ID, pr.BaseRepo.Name, pr.BaseBranch, commit.ID.String())
		return true
	}
	return false
}

// InitializePullRequests checks and tests untested patches of pull requests.
func InitializePullRequests(ctx context.Context) {
	prs, err := models.GetPullRequestIDsByCheckStatus(models.PullRequestStatusChecking)
	if err != nil {
		log.Error("Find Checking PRs: %v", err)
		return
	}
	for _, prID := range prs {
		select {
		case <-ctx.Done():
			return
		default:
			if err := prQueue.PushFunc(strconv.FormatInt(prID, 10), func() error {
				log.Trace("Adding PR ID: %d to the pull requests patch checking queue", prID)
				return nil
			}); err != nil {
				log.Error("Error adding prID: %s to the pull requests patch checking queue %v", prID, err)
			}
		}
	}
}

// handle passed PR IDs and test the PRs
func handle(data ...queue.Data) {
	for _, datum := range data {
		id, _ := strconv.ParseInt(datum.(string), 10, 64)

		log.Trace("Testing PR ID %d from the pull requests patch checking queue", id)

		pr, err := models.GetPullRequestByID(id)
		if err != nil {
			log.Error("GetPullRequestByID[%s]: %v", datum, err)
			continue
		} else if pr.HasMerged {
			continue
		} else if manuallyMerged(pr) {
			continue
		} else if err = TestPatch(pr); err != nil {
			log.Error("testPatch[%d]: %v", pr.ID, err)
			pr.Status = models.PullRequestStatusError
			if err := pr.UpdateCols("status"); err != nil {
				log.Error("update pr [%d] status to PullRequestStatusError failed: %v", pr.ID, err)
			}
			continue
		}
		checkAndUpdateStatus(pr)
	}
}

// CheckPrsForBaseBranch check all pulls with bseBrannch
func CheckPrsForBaseBranch(baseRepo *models.Repository, baseBranchName string) error {
	prs, err := models.GetUnmergedPullRequestsByBaseInfo(baseRepo.ID, baseBranchName)
	if err != nil {
		return err
	}

	for _, pr := range prs {
		AddToTaskQueue(pr)
	}

	return nil
}

// Init runs the task queue to test all the checking status pull requests
func Init() error {
	prQueue = queue.CreateUniqueQueue("pr_patch_checker", handle, "").(queue.UniqueQueue)

	if prQueue == nil {
		return fmt.Errorf("Unable to create pr_patch_checker Queue")
	}

	go graceful.GetManager().RunWithShutdownFns(prQueue.Run)
	go graceful.GetManager().RunWithShutdownContext(InitializePullRequests)
	return nil
}
<commit_msg>Remove unnecessary goroutine (#16080)<commit_after>// Copyright 2019 The Gitea Authors.
// All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package pull

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"

	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/git"
	"code.gitea.io/gitea/modules/graceful"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/notification"
	"code.gitea.io/gitea/modules/queue"
	"code.gitea.io/gitea/modules/timeutil"
	"code.gitea.io/gitea/modules/util"
)

// prQueue represents a queue to handle update pull request tests
var prQueue queue.UniqueQueue

// AddToTaskQueue adds itself to pull request test task queue.
func AddToTaskQueue(pr *models.PullRequest) {
	err := prQueue.PushFunc(strconv.FormatInt(pr.ID, 10), func() error {
		pr.Status = models.PullRequestStatusChecking
		err := pr.UpdateColsIfNotMerged("status")
		if err != nil {
			log.Error("AddToTaskQueue.UpdateCols[%d].(add to queue): %v", pr.ID, err)
		} else {
			log.Trace("Adding PR ID: %d to the test pull requests queue", pr.ID)
		}
		return err
	})
	if err != nil && err != queue.ErrAlreadyInQueue {
		log.Error("Error adding prID %d to the test pull requests queue: %v", pr.ID, err)
	}
}

// checkAndUpdateStatus checks if pull request is possible to leaving checking status,
// and set to be either conflict or mergeable.
func checkAndUpdateStatus(pr *models.PullRequest) {
	// Status is not changed to conflict means mergeable.
	if pr.Status == models.PullRequestStatusChecking {
		pr.Status = models.PullRequestStatusMergeable
	}

	// Make sure there is no waiting test to process before leaving the checking status.
	has, err := prQueue.Has(strconv.FormatInt(pr.ID, 10))
	if err != nil {
		log.Error("Unable to check if the queue is waiting to reprocess pr.ID %d. Error: %v", pr.ID, err)
	}

	if !has {
		if err := pr.UpdateColsIfNotMerged("merge_base", "status", "conflicted_files", "changed_protected_files"); err != nil {
			log.Error("Update[%d]: %v", pr.ID, err)
		}
	}
}

// getMergeCommit checks if a pull request got merged
// Returns the git.Commit of the pull request if merged
func getMergeCommit(pr *models.PullRequest) (*git.Commit, error) {
	if pr.BaseRepo == nil {
		var err error
		pr.BaseRepo, err = models.GetRepositoryByID(pr.BaseRepoID)
		if err != nil {
			return nil, fmt.Errorf("GetRepositoryByID: %v", err)
		}
	}

	indexTmpPath, err := ioutil.TempDir(os.TempDir(), "gitea-"+pr.BaseRepo.Name)
	if err != nil {
		return nil, fmt.Errorf("Failed to create temp dir for repository %s: %v", pr.BaseRepo.RepoPath(), err)
	}
	defer func() {
		if err := util.RemoveAll(indexTmpPath); err != nil {
			log.Warn("Unable to remove temporary index path: %s: Error: %v", indexTmpPath, err)
		}
	}()

	headFile := pr.GetGitRefName()

	// Check if a pull request is merged into BaseBranch
	_, err = git.NewCommand("merge-base", "--is-ancestor", headFile, pr.BaseBranch).
		RunInDirWithEnv(pr.BaseRepo.RepoPath(), []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()})
	if err != nil {
		// Errors are signaled by a non-zero status that is not 1
		if strings.Contains(err.Error(), "exit status 1") {
			return nil, nil
		}
		return nil, fmt.Errorf("git merge-base --is-ancestor: %v", err)
	}

	commitIDBytes, err := ioutil.ReadFile(pr.BaseRepo.RepoPath() + "/" + headFile)
	if err != nil {
		return nil, fmt.Errorf("ReadFile(%s): %v", headFile, err)
	}
	commitID := string(commitIDBytes)
	if len(commitID) < 40 {
		return nil, fmt.Errorf(`ReadFile(%s): invalid commit-ID "%s"`, headFile, commitID)
	}
	cmd := commitID[:40] + ".." + pr.BaseBranch

	// Get the commit from BaseBranch where the pull request got merged
	mergeCommit, err := git.NewCommand("rev-list", "--ancestry-path", "--merges", "--reverse", cmd).
		RunInDirWithEnv("", []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()})
	if err != nil {
		return nil, fmt.Errorf("git rev-list --ancestry-path --merges --reverse: %v", err)
	} else if len(mergeCommit) < 40 {
		// PR was maybe fast-forwarded, so just use last commit of PR
		mergeCommit = commitID[:40]
	}

	gitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath())
	if err != nil {
		return nil, fmt.Errorf("OpenRepository: %v", err)
	}
	defer gitRepo.Close()

	commit, err := gitRepo.GetCommit(mergeCommit[:40])
	if err != nil {
		return nil, fmt.Errorf("GetCommit: %v", err)
	}

	return commit, nil
}

// manuallyMerged checks if a pull request got manually merged
// When a pull request got manually merged mark the pull request as merged
func manuallyMerged(pr *models.PullRequest) bool {
	if err := pr.LoadBaseRepo(); err != nil {
		log.Error("PullRequest[%d].LoadBaseRepo: %v", pr.ID, err)
		return false
	}

	if unit, err := pr.BaseRepo.GetUnit(models.UnitTypePullRequests); err == nil {
		config := unit.PullRequestsConfig()
		if !config.AutodetectManualMerge {
			return false
		}
	} else {
		log.Error("PullRequest[%d].BaseRepo.GetUnit(models.UnitTypePullRequests): %v", pr.ID, err)
		return false
	}

	commit, err := getMergeCommit(pr)
	if err != nil {
		log.Error("PullRequest[%d].getMergeCommit: %v", pr.ID, err)
		return false
	}
	if commit != nil {
		pr.MergedCommitID = commit.ID.String()
		pr.MergedUnix = timeutil.TimeStamp(commit.Author.When.Unix())
		pr.Status = models.PullRequestStatusManuallyMerged
		merger, _ := models.GetUserByEmail(commit.Author.Email)

		// When the commit author is unknown set the BaseRepo owner as merger
		if merger == nil {
			if pr.BaseRepo.Owner == nil {
				if err = pr.BaseRepo.GetOwner(); err != nil {
					log.Error("BaseRepo.GetOwner[%d]: %v", pr.ID, err)
					return false
				}
			}
			merger = pr.BaseRepo.Owner
		}
		pr.Merger = merger
		pr.MergerID = merger.ID

		if merged, err := pr.SetMerged(); err != nil {
			log.Error("PullRequest[%d].setMerged : %v", pr.ID, err)
			return false
		} else if !merged {
			return false
		}

		notification.NotifyMergePullRequest(pr, merger)

		log.Info("manuallyMerged[%d]: Marked as manually merged into %s/%s by commit id: %s", pr.ID, pr.BaseRepo.Name, pr.BaseBranch, commit.ID.String())
		return true
	}
	return false
}

// InitializePullRequests checks and tests untested patches of pull requests.
func InitializePullRequests(ctx context.Context) {
	prs, err := models.GetPullRequestIDsByCheckStatus(models.PullRequestStatusChecking)
	if err != nil {
		log.Error("Find Checking PRs: %v", err)
		return
	}
	for _, prID := range prs {
		select {
		case <-ctx.Done():
			return
		default:
			if err := prQueue.PushFunc(strconv.FormatInt(prID, 10), func() error {
				log.Trace("Adding PR ID: %d to the pull requests patch checking queue", prID)
				return nil
			}); err != nil {
				log.Error("Error adding prID: %s to the pull requests patch checking queue %v", prID, err)
			}
		}
	}
}

// handle passed PR IDs and test the PRs
func handle(data ...queue.Data) {
	for _, datum := range data {
		id, _ := strconv.ParseInt(datum.(string), 10, 64)

		log.Trace("Testing PR ID %d from the pull requests patch checking queue", id)

		pr, err := models.GetPullRequestByID(id)
		if err != nil {
			log.Error("GetPullRequestByID[%s]: %v", datum, err)
			continue
		} else if pr.HasMerged {
			continue
		} else if manuallyMerged(pr) {
			continue
		} else if err = TestPatch(pr); err != nil {
			log.Error("testPatch[%d]: %v", pr.ID, err)
			pr.Status = models.PullRequestStatusError
			if err := pr.UpdateCols("status"); err != nil {
				log.Error("update pr [%d] status to PullRequestStatusError failed: %v", pr.ID, err)
			}
			continue
		}
		checkAndUpdateStatus(pr)
	}
}

// CheckPrsForBaseBranch check all pulls with bseBrannch
func CheckPrsForBaseBranch(baseRepo *models.Repository, baseBranchName string) error {
	prs, err := models.GetUnmergedPullRequestsByBaseInfo(baseRepo.ID, baseBranchName)
	if err != nil {
		return err
	}

	for _, pr := range prs {
		AddToTaskQueue(pr)
	}

	return nil
}

// Init runs the task queue to test all the checking status pull requests
func Init() error {
	prQueue = queue.CreateUniqueQueue("pr_patch_checker", handle, "").(queue.UniqueQueue)

	if prQueue == nil {
		return fmt.Errorf("Unable to create pr_patch_checker Queue")
	}

	go graceful.GetManager().RunWithShutdownFns(prQueue.Run)
	go graceful.GetManager().RunWithShutdownContext(InitializePullRequests)
	return nil
}
<|endoftext|>