<commit_before>package envcnf

import (
	"fmt"
	"os"
	"reflect"
	"testing"
)

// Here's how you'd use the Parse function with a sample config.
func ExampleParse() {
	/* Here is how a sample config file could look like:

		    # put this into your .envrc, if you're using direnv
		    # or name it `run.sh` and add an invocation of your exe at the end
		    # or `source` it manually in your shell and run exe from there

		    # config values...
	      export ACME-COORP_Environment=production

				export ACME-COORP_Listen_internal_Addr=127.0.0.1:80
				export ACME-COORP_Listen_internal_HTTPS=false # or any of: FALSE, False, 1, f, F

				export ACME-COORP_Listen_public_Addr=1.2.3.4:443
				export ACME-COORP_Listen_public_HTTPS=true # or any of: TRUE, True, 1, t, T

			  export ACME-COORP_ChRoot=/var/empty

			  export ACME-COORP_MyFoo_Values_0=3
				export ACME-COORP_MyFoo_Values_1=2
				export ACME-COORP_MyFoo_Values_2=1
				export ACME-COORP_MyFoo_Values_3=0

		    # ./acme_secretsauce
	*/

	// meanwhile in your source code...
	type NetCnf struct {
		Addr  string
		HTTPS bool
	}

	type MySection struct {
		Values []uint64
	}

	type MyCnf struct {
		Environment string
		Listen      map[string]NetCnf
		ChRoot      string
		MyFoo       MySection
	}

	var config MyCnf
	if err := Parse(&config, "ACME-COORP", "_"); err != nil {
		// Handle error
	}
	fmt.Println(config)
	/*
			    MyCnf{
			    Environment: "production",
			    Listen: map{
			    "internal": NetCnf{
			      Addr: "127.0.0.1:80",
			      HTTPS: false,
			    }
			    "external": NetCnf{
			      Addr: "1.2.3.4:443",
			      HTTPS: false,
			    }
		      ChRoot: "/var/empty",
		      MyFoo: int{3, 2, 1, 0},
			  }
	*/
	// TADA !
}

func TestExample(t *testing.T) {
	os.Setenv("ACME-COORP_Environment", "production")
	defer os.Unsetenv("ACME-COORP_Environment")

	os.Setenv("ACME-COORP_Listen_internal_Addr", "127.0.0.1:80")
	defer os.Unsetenv("ACME-COORP_Listen_internal_Addr")

	os.Setenv("ACME-COORP_Listen_internal_HTTPS", "false")
	defer os.Unsetenv("ACME-COORP_Listen_internal_HTTPS")

	os.Setenv("ACME-COORP_Listen_public_Addr", "1.2.3.4:443")
	defer os.Unsetenv("ACME-COORP_Listen_public_Addr")

	os.Setenv("ACME-COORP_Listen_public_HTTPS", "true")
	defer os.Unsetenv("ACME-COORP_Listen_public_HTTPS")

	os.Setenv("ACME-COORP_ChRoot", "/var/empty")
	defer os.Unsetenv("ACME-COORP_ChRoot")

	os.Setenv("ACME-COORP_MyFoo_Values_0", "3")
	defer os.Unsetenv("ACME-COORP_MyFoo_Values_0")

	os.Setenv("ACME-COORP_MyFoo_Values_1", "2")
	defer os.Unsetenv("ACME-COORP_MyFoo_Values_1")

	os.Setenv("ACME-COORP_MyFoo_Values_2", "1")
	defer os.Unsetenv("ACME-COORP_MyFoo_Values_2")

	os.Setenv("ACME-COORP_MyFoo_Values_3", "0")
	defer os.Unsetenv("ACME-COORP_MyFoo_Values_3")

	type NetCnf struct {
		Addr  string
		HTTPS bool
	}

	type MySection struct {
		Values []uint64
	}

	type MyCnf struct {
		Environment string
		Listen      map[string]NetCnf
		ChRoot      string
		MyFoo       MySection
	}

	var expect = MyCnf{
		Environment: "production",
		Listen: map[string]NetCnf{
			"internal": NetCnf{
				Addr:  "127.0.0.1:80",
				HTTPS: false,
			},
			"public": NetCnf{
				Addr:  "1.2.3.4:443",
				HTTPS: true,
			},
		},
		ChRoot: "/var/empty",
		MyFoo: MySection{
			Values: []uint64{
				3, 2, 1, 0,
			},
		},
	}

	var config MyCnf
	config.Listen = make(map[string]NetCnf)
	config.MyFoo.Values = make([]uint64, 0)
	t.Logf("before parse:\n%#v\n", config)

	if err := Parse(&config, "ACME-COORP", "_"); err != nil {
		t.Fatalf("Parse error: %v\n%#v\n", err, config)
	}
	if !reflect.DeepEqual(config, expect) {
		t.Fatalf("Unexpected Values parsed:\nHAVE:%#v\nWANT:%#v\n", config, expect)
	}
}
<commit_msg>polishing the example<commit_after>package envcnf

import (
	"fmt"
	"os"
	"reflect"
	"testing"
)

// Here's how you'd use the Parse function with a sample config.
func ExampleParse() {
	// you'd normally set those outside the program, of course.
	os.Setenv("ACME-COORP_Environment", "production")

	os.Setenv("ACME-COORP_Listen_internal_Addr", "127.0.0.1:80")
	os.Setenv("ACME-COORP_Listen_internal_HTTPS", "false")

	os.Setenv("ACME-COORP_Listen_public_Addr", "1.2.3.4:443")
	os.Setenv("ACME-COORP_Listen_public_HTTPS", "true")

	os.Setenv("ACME-COORP_ChRoot", "/var/empty")

	os.Setenv("ACME-COORP_MyFoo_Values_0", "3")
	os.Setenv("ACME-COORP_MyFoo_Values_1", "2")
	os.Setenv("ACME-COORP_MyFoo_Values_2", "1")
	os.Setenv("ACME-COORP_MyFoo_Values_3", "0")

	// here are the sample configuration types we'll be parsing into
	type NetCnf struct {
		Addr  string
		HTTPS bool
	}

	type MySection struct {
		Values []uint64
	}

	type MyCnf struct {
		Environment string
		Listen      map[string]NetCnf
		ChRoot      string
		MyFoo       MySection
	}

	// and this is how you'd parse this
	var config MyCnf

	// making these two calls unneccessary is on the TODO list ;-)
	config.Listen = make(map[string]NetCnf)
	config.MyFoo.Values = make([]uint64, 0)

	if err := Parse(&config, "ACME-COORP", "_"); err != nil {
		// Handle error
	}

	fmt.Printf("%#v", config)
	/* gives the following output:
	   envcnf.MyCnf{
	     Environment:"production",
	     Listen:map[string]envcnf.NetCnf{
	       "internal":envcnf.NetCnf{
	         Addr:"127.0.0.1:80",
	         HTTPS:false
	       },
	       "public":envcnf.NetCnf{
	         Addr:"1.2.3.4:443",
	         HTTPS:true
	       }
	     },
	     ChRoot:"/var/empty",
	     MyFoo:envcnf.MySection{
	       Values:[]uint64{0x3, 0x2, 0x1, 0x0}
	     }
	   }
	*/
	// Output:
	// envcnf.MyCnf{Environment:"production", Listen:map[string]envcnf.NetCnf{"public":envcnf.NetCnf{Addr:"1.2.3.4:443", HTTPS:true}, "internal":envcnf.NetCnf{Addr:"127.0.0.1:80", HTTPS:false}}, ChRoot:"/var/empty", MyFoo:envcnf.MySection{Values:[]uint64{0x3, 0x2, 0x1, 0x0}}}
}

func TestExample(t *testing.T) {
	os.Setenv("ACME-COORP_Environment", "production")
	defer os.Unsetenv("ACME-COORP_Environment")

	os.Setenv("ACME-COORP_Listen_internal_Addr", "127.0.0.1:80")
	defer os.Unsetenv("ACME-COORP_Listen_internal_Addr")

	os.Setenv("ACME-COORP_Listen_internal_HTTPS", "false")
	defer os.Unsetenv("ACME-COORP_Listen_internal_HTTPS")

	os.Setenv("ACME-COORP_Listen_public_Addr", "1.2.3.4:443")
	defer os.Unsetenv("ACME-COORP_Listen_public_Addr")

	os.Setenv("ACME-COORP_Listen_public_HTTPS", "true")
	defer os.Unsetenv("ACME-COORP_Listen_public_HTTPS")

	os.Setenv("ACME-COORP_ChRoot", "/var/empty")
	defer os.Unsetenv("ACME-COORP_ChRoot")

	os.Setenv("ACME-COORP_MyFoo_Values_0", "3")
	defer os.Unsetenv("ACME-COORP_MyFoo_Values_0")

	os.Setenv("ACME-COORP_MyFoo_Values_1", "2")
	defer os.Unsetenv("ACME-COORP_MyFoo_Values_1")

	os.Setenv("ACME-COORP_MyFoo_Values_2", "1")
	defer os.Unsetenv("ACME-COORP_MyFoo_Values_2")

	os.Setenv("ACME-COORP_MyFoo_Values_3", "0")
	defer os.Unsetenv("ACME-COORP_MyFoo_Values_3")

	type NetCnf struct {
		Addr  string
		HTTPS bool
	}

	type MySection struct {
		Values []uint64
	}

	type MyCnf struct {
		Environment string
		Listen      map[string]NetCnf
		ChRoot      string
		MyFoo       MySection
	}

	var expect = MyCnf{
		Environment: "production",
		Listen: map[string]NetCnf{
			"internal": NetCnf{
				Addr:  "127.0.0.1:80",
				HTTPS: false,
			},
			"public": NetCnf{
				Addr:  "1.2.3.4:443",
				HTTPS: true,
			},
		},
		ChRoot: "/var/empty",
		MyFoo: MySection{
			Values: []uint64{
				3, 2, 1, 0,
			},
		},
	}

	var config MyCnf
	config.Listen = make(map[string]NetCnf)
	config.MyFoo.Values = make([]uint64, 0)

	if err := Parse(&config, "ACME-COORP", "_"); err != nil {
		t.Fatalf("Parse error: %v\n%#v\n", err, config)
	}
	if !reflect.DeepEqual(config, expect) {
		t.Fatalf("Unexpected Values parsed:\nHAVE:%#v\nWANT:%#v\n", config, expect)
	}
	t.Logf("parsed:\n%#v\n", config)
}
<|endoftext|>


<commit_before>package diff_test

import (
	"bytes"
	"testing"

	"github.com/schemalex/schemalex/diff"
	"github.com/stretchr/testify/assert"
)

func TestDiff(t *testing.T) {
	type Spec struct {
		Before string
		After  string
		Expect string
	}

	specs := []Spec{
		// drop table
		{
			Before: "CREATE TABLE `hoge` ( `id` integer not null ); CREATE TABLE `fuga` ( `id` INTEGER NOT NULL );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL );",
			Expect: "DROP TABLE `hoge`;",
		},
		// create table
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL );",
			After:  "CREATE TABLE `hoge` ( `id` INTEGER NOT NULL ) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT 'table comment'; CREATE TABLE `fuga` ( `id` INTEGER NOT NULL );",
			Expect: "CREATE TABLE `hoge` (\n`id` INTEGER NOT NULL\n) ENGINE = InnoDB, DEFAULT CHARACTER SET = utf8mb4, COMMENT = 'table comment';",
		},
		// drop column
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL, `c` VARCHAR (20) NOT NULL DEFAULT 'xxx' );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL );",
			Expect: "ALTER TABLE `fuga` DROP COLUMN `c`;",
		},
		// add column
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL, `c` VARCHAR (20) NOT NULL DEFAULT 'xxx');",
			Expect: "ALTER TABLE `fuga` ADD COLUMN `c` VARCHAR (20) NOT NULL DEFAULT \"xxx\";",
		},
		// change column
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL );",
			After:  "CREATE TABLE `fuga` ( `id` BIGINT NOT NULL );",
			Expect: "ALTER TABLE `fuga` CHANGE COLUMN `id` `id` BIGINT NOT NULL;",
		},
		// change column with comment
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL COMMENT 'fuga is good' );",
			Expect: "ALTER TABLE `fuga` CHANGE COLUMN `id` `id` INTEGER NOT NULL COMMENT 'fuga is good';",
		},
		// drop primary key
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT );",
			Expect: "ALTER TABLE `fuga` DROP INDEX PRIMARY KEY;",
		},
		// add primary key
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) );",
			Expect: "ALTER TABLE `fuga` ADD PRIMARY KEY (`id`);",
		},
		// drop unique key
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT, CONSTRAINT `symbol` UNIQUE KEY `uniq_id` USING BTREE (`id`) );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT );",
			Expect: "ALTER TABLE `fuga` DROP INDEX `uniq_id`;",
		},
		// add unique key
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT, CONSTRAINT `symbol` UNIQUE KEY `uniq_id` USING BTREE (`id`) );",
			Expect: "ALTER TABLE `fuga` ADD CONSTRAINT `symbol` UNIQUE INDEX `uniq_id` USING BTREE (`id`);",
		},
		// not change index
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT, CONSTRAINT `symbol` UNIQUE KEY `uniq_id` USING BTREE (`id`) );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT, CONSTRAINT `symbol` UNIQUE KEY `uniq_id` USING BTREE (`id`) );",
			Expect: "",
		},
		// multi modify
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT, `aid` INTEGER NOT NULL, `bid` INTEGER NOT NULL, INDEX `ab` (`aid`, `bid`) );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT, `aid` INTEGER NOT NULL, `cid` INTEGER NOT NULL, INDEX `ac` (`aid`, `cid`) );",
			Expect: "ALTER TABLE `fuga` DROP INDEX `ab`;\nALTER TABLE `fuga` DROP COLUMN `bid`;\nALTER TABLE `fuga` ADD COLUMN `cid` INTEGER NOT NULL;\nALTER TABLE `fuga` ADD INDEX `ac` (`aid`, `cid`);",
		},
	}

	var buf bytes.Buffer
	for _, spec := range specs {
		buf.Reset()

		if !assert.NoError(t, diff.Strings(&buf, spec.Before, spec.After), "diff.String should succeed") {
			return
		}
		if !assert.Equal(t, spec.Expect, buf.String(), "result SQL should match") {
			return
		}
	}
}
<commit_msg>FOREIGN KEY を設定しているとdiffでdrop index + add foreign key が必ず出る<commit_after>package diff_test

import (
	"bytes"
	"testing"

	"github.com/schemalex/schemalex/diff"
	"github.com/stretchr/testify/assert"
)

func TestDiff(t *testing.T) {
	type Spec struct {
		Before string
		After  string
		Expect string
	}

	specs := []Spec{
		// drop table
		{
			Before: "CREATE TABLE `hoge` ( `id` integer not null ); CREATE TABLE `fuga` ( `id` INTEGER NOT NULL );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL );",
			Expect: "DROP TABLE `hoge`;",
		},
		// create table
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL );",
			After:  "CREATE TABLE `hoge` ( `id` INTEGER NOT NULL ) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT 'table comment'; CREATE TABLE `fuga` ( `id` INTEGER NOT NULL );",
			Expect: "CREATE TABLE `hoge` (\n`id` INTEGER NOT NULL\n) ENGINE = InnoDB, DEFAULT CHARACTER SET = utf8mb4, COMMENT = 'table comment';",
		},
		// drop column
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL, `c` VARCHAR (20) NOT NULL DEFAULT 'xxx' );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL );",
			Expect: "ALTER TABLE `fuga` DROP COLUMN `c`;",
		},
		// add column
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL, `c` VARCHAR (20) NOT NULL DEFAULT 'xxx');",
			Expect: "ALTER TABLE `fuga` ADD COLUMN `c` VARCHAR (20) NOT NULL DEFAULT \"xxx\";",
		},
		// change column
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL );",
			After:  "CREATE TABLE `fuga` ( `id` BIGINT NOT NULL );",
			Expect: "ALTER TABLE `fuga` CHANGE COLUMN `id` `id` BIGINT NOT NULL;",
		},
		// change column with comment
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL COMMENT 'fuga is good' );",
			Expect: "ALTER TABLE `fuga` CHANGE COLUMN `id` `id` INTEGER NOT NULL COMMENT 'fuga is good';",
		},
		// drop primary key
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT );",
			Expect: "ALTER TABLE `fuga` DROP INDEX PRIMARY KEY;",
		},
		// add primary key
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`) );",
			Expect: "ALTER TABLE `fuga` ADD PRIMARY KEY (`id`);",
		},
		// drop unique key
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT, CONSTRAINT `symbol` UNIQUE KEY `uniq_id` USING BTREE (`id`) );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT );",
			Expect: "ALTER TABLE `fuga` DROP INDEX `uniq_id`;",
		},
		// add unique key
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT, CONSTRAINT `symbol` UNIQUE KEY `uniq_id` USING BTREE (`id`) );",
			Expect: "ALTER TABLE `fuga` ADD CONSTRAINT `symbol` UNIQUE INDEX `uniq_id` USING BTREE (`id`);",
		},
		// not change index
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT, CONSTRAINT `symbol` UNIQUE KEY `uniq_id` USING BTREE (`id`) );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT, CONSTRAINT `symbol` UNIQUE KEY `uniq_id` USING BTREE (`id`) );",
			Expect: "",
		},
		// not change FOREIGN KEY
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT, `fid` INTEGER NOT NULL, FOREIGN KEY fk (fid) REFERENCES f (id) );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT, `fid` INTEGER NOT NULL, FOREIGN KEY fk (fid) REFERENCES f (id) );",
			Expect: "",
		},
		// multi modify
		{
			Before: "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT, `aid` INTEGER NOT NULL, `bid` INTEGER NOT NULL, INDEX `ab` (`aid`, `bid`) );",
			After:  "CREATE TABLE `fuga` ( `id` INTEGER NOT NULL AUTO_INCREMENT, `aid` INTEGER NOT NULL, `cid` INTEGER NOT NULL, INDEX `ac` (`aid`, `cid`) );",
			Expect: "ALTER TABLE `fuga` DROP INDEX `ab`;\nALTER TABLE `fuga` DROP COLUMN `bid`;\nALTER TABLE `fuga` ADD COLUMN `cid` INTEGER NOT NULL;\nALTER TABLE `fuga` ADD INDEX `ac` (`aid`, `cid`);",
		},
	}

	var buf bytes.Buffer
	for _, spec := range specs {
		buf.Reset()

		if !assert.NoError(t, diff.Strings(&buf, spec.Before, spec.After), "diff.String should succeed") {
			return
		}
		if !assert.Equal(t, spec.Expect, buf.String(), "result SQL should match") {
			return
		}
	}
}
<|endoftext|>


<commit_before>package main

import "fmt"
import "math"

// AI can cheat and peek at all cards in the stack.

// The general strategy is to play greedily. The AI will ignore the player's
// actions and try to as quickly as possible to knock and end the game. This
// means it will simply look for nearest neighbors of cards in its hand that
// is currently not in a meld. If the card on the stack is not within 2 range,
// it will draw a card from the deck. If it has to decide between two cards
// with one pairing to discard, it will always discard the greater value card.

// CheckIfCardIsNearestNeighbor - will check if card on the top of the stack is
// a nearest neighbor.
func (h *Hand) CheckIfCardIsNearestNeighbor(c Card) bool {
	for _, card := range *h {
		if c.value == card.value+1 ||
			c.value == card.value-1 ||
			c.value == card.value {
			return true
		}
	}
	return false
}

// CardDistance - gives us the relative likelihood of the card being useful in
// our hand based on how far away it is from all the other cards in our hand.
func (u *Deadwood) CardDistance(c Card) int {
	distance := 0.0
	for _, card := range *u {
		distance += math.Abs(float64(card.value) - float64(c.value))
	}
	return int(distance)
}

// ChooseCardToDiscard will decide between cards to discard. The theory is that
// a good strategy is to get rid of the highest value card first in order to get
// closer to knocking. Since the game is a race to knock, we should try to
// the chances to do so. Saving slots for nearest neighbors in hopes of drawing
// the right card is not good unless we have an idea of what cards are going to
// appear. We could implement that in the future.
func (u *Deadwood) ChooseCardToDiscard() Card {
	cardToDiscard := Card{}
	max := 0
	for _, card := range *u {
		if card.value > max {
			max = card.value
			cardToDiscard = card
		}
	}
	return cardToDiscard
}

// AIActions - describes what the AI is going to do.
func AIActions(p *Player, deck *Deck, stack *Stack, knock *bool, draw *bool, gin *bool) {
	total := p.Hand.CheckTotal()

	if len(*deck) == 0 {
		*draw = true
		return
	}

	if p.Hand.CheckTotal() <= 10 {
		if total == 0 {
			*gin = true
		}
		*knock = true
		fmt.Printf("\nAI knocks!\n")
		return
	}

	// Sum total strategy.
	fauxHand := Hand{}
	cardFromTopOfStack, _ := GetCardFromPrettyPrint(stack.PeekAtStack())
	fauxHand = append(fauxHand, p.Hand...)
	fauxHand = append(fauxHand, cardFromTopOfStack)
	leftOverCards := fauxHand.CheckDeadwood()
	cardToDiscard := leftOverCards.ChooseCardToDiscard()
	umeldedCardsWithoutDraw := p.Hand.CheckDeadwood()
	deadWoodToDiscard := umeldedCardsWithoutDraw.ChooseCardToDiscard()

	// Nearest neighbor strategy
	nearestNeighbor := p.Hand.CheckIfCardIsNearestNeighbor(cardFromTopOfStack)

	if !nearestNeighbor {
		if cardToDiscard == cardFromTopOfStack {
			p.Hand.DrawCard(deck)
			fmt.Printf("\nAI drew from the deck!\n")
		} else if cardToDiscard.value < cardFromTopOfStack.value {
			p.Hand.DrawCard(deck)
			fmt.Printf("\nAI drew from the deck!\n")
		} else if leftOverCards.ContainsCard(cardFromTopOfStack) {
			p.Hand.DrawCard(deck)
			fmt.Printf("\nAI drew from the deck!\n")
		} else {
			p.Hand.DrawCard(stack)
			fmt.Printf("\nAI drew from the stack!\n")
		}
	} else {
		// If the card on the stack is worse than our worse card, then draw
		// from the deck.
		if umeldedCardsWithoutDraw.CardDistance(cardFromTopOfStack) > umeldedCardsWithoutDraw.CardDistance(deadWoodToDiscard) {
			p.Hand.DrawCard(deck)
			fmt.Printf("\nAI drew from the deck!\n")
			// Or if the card on the stack will become one of our deadwood
			// cards, we then draw from the deck.
		} else if leftOverCards.ContainsCard(cardFromTopOfStack) {
			p.Hand.DrawCard(deck)
			fmt.Printf("\nAI drew from the deck!\n")
		} else {
			p.Hand.DrawCard(stack)
			fmt.Printf("\nAI drew from the stack!\n")
		}
	}

	remainingCards := p.Hand.CheckDeadwood()
	discardedCard, _ := p.Hand.DiscardCard(remainingCards.ChooseCardToDiscard(), stack)
	fmt.Printf("%s discarded %s\n", p.name, discardedCard.PrettyPrintCard())
	return
}
<commit_msg>Card must also have the same suit to be nearest neighbor.<commit_after>package main

import "fmt"
import "math"

// AI can cheat and peek at all cards in the stack.

// The general strategy is to play greedily. The AI will ignore the player's
// actions and try to as quickly as possible to knock and end the game. This
// means it will simply look for nearest neighbors of cards in its hand that
// is currently not in a meld. If the card on the stack is not within 2 range,
// it will draw a card from the deck. If it has to decide between two cards
// with one pairing to discard, it will always discard the greater value card.

// CheckIfCardIsNearestNeighbor - will check if card on the top of the stack is
// a nearest neighbor.
func (h *Hand) CheckIfCardIsNearestNeighbor(c Card) bool {
	for _, card := range *h {
		if (c.value == card.value+1 && c.suit == card.suit) ||
			(c.value == card.value-1 && c.suit == card.suit) ||
			c.value == card.value {
			return true
		}
	}
	return false
}

// CardDistance - gives us the relative likelihood of the card being useful in
// our hand based on how far away it is from all the other cards in our hand.
func (u *Deadwood) CardDistance(c Card) int {
	distance := 0.0
	for _, card := range *u {
		distance += math.Abs(float64(card.value) - float64(c.value))
	}
	return int(distance)
}

// ChooseCardToDiscard will decide between cards to discard. The theory is that
// a good strategy is to get rid of the highest value card first in order to get
// closer to knocking. Since the game is a race to knock, we should try to
// the chances to do so. Saving slots for nearest neighbors in hopes of drawing
// the right card is not good unless we have an idea of what cards are going to
// appear. We could implement that in the future.
func (u *Deadwood) ChooseCardToDiscard() Card {
	cardToDiscard := Card{}
	max := 0
	for _, card := range *u {
		if card.value > max {
			max = card.value
			cardToDiscard = card
		}
	}
	return cardToDiscard
}

// AIActions - describes what the AI is going to do.
func AIActions(p *Player, deck *Deck, stack *Stack, knock *bool, draw *bool, gin *bool) {
	total := p.Hand.CheckTotal()

	if len(*deck) == 0 {
		*draw = true
		return
	}

	if p.Hand.CheckTotal() <= 10 {
		if total == 0 {
			*gin = true
		}
		*knock = true
		fmt.Printf("\nAI knocks!\n")
		return
	}

	// Sum total strategy.
	fauxHand := Hand{}
	cardFromTopOfStack, _ := GetCardFromPrettyPrint(stack.PeekAtStack())
	fauxHand = append(fauxHand, p.Hand...)
	fauxHand = append(fauxHand, cardFromTopOfStack)
	leftOverCards := fauxHand.CheckDeadwood()
	cardToDiscard := leftOverCards.ChooseCardToDiscard()
	umeldedCardsWithoutDraw := p.Hand.CheckDeadwood()
	deadWoodToDiscard := umeldedCardsWithoutDraw.ChooseCardToDiscard()

	// Nearest neighbor strategy
	nearestNeighbor := p.Hand.CheckIfCardIsNearestNeighbor(cardFromTopOfStack)

	if !nearestNeighbor {
		if cardToDiscard == cardFromTopOfStack {
			p.Hand.DrawCard(deck)
			fmt.Printf("\nAI drew from the deck!\n")
		} else if cardToDiscard.value < cardFromTopOfStack.value {
			p.Hand.DrawCard(deck)
			fmt.Printf("\nAI drew from the deck!\n")
		} else if leftOverCards.ContainsCard(cardFromTopOfStack) {
			p.Hand.DrawCard(deck)
			fmt.Printf("\nAI drew from the deck!\n")
		} else {
			p.Hand.DrawCard(stack)
			fmt.Printf("\nAI drew from the stack!\n")
		}
	} else {
		// If the card on the stack is worse than our worse card, then draw
		// from the deck.
		if umeldedCardsWithoutDraw.CardDistance(cardFromTopOfStack) > umeldedCardsWithoutDraw.CardDistance(deadWoodToDiscard) {
			p.Hand.DrawCard(deck)
			fmt.Printf("\nAI drew from the deck!\n")
			// Or if the card on the stack will become one of our deadwood
			// cards, we then draw from the deck.
		} else if leftOverCards.ContainsCard(cardFromTopOfStack) {
			p.Hand.DrawCard(deck)
			fmt.Printf("\nAI drew from the deck!\n")
		} else {
			p.Hand.DrawCard(stack)
			fmt.Printf("\nAI drew from the stack!\n")
		}
	}

	remainingCards := p.Hand.CheckDeadwood()
	discardedCard, _ := p.Hand.DiscardCard(remainingCards.ChooseCardToDiscard(), stack)
	fmt.Printf("%s discarded %s\n", p.name, discardedCard.PrettyPrintCard())
	return
}
<|endoftext|>


<commit_before>package smoke

import (
	"fmt"
	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
	"io"
	"net"
	"net/http"
	"strings"
	"sync"
)

var _ = Describe("Loggregator:", func() {
	var testConfig = GetConfig()
	var useExistingApp = (testConfig.LoggingApp != "")
	var appName string

	Describe("cf logs", func() {
		BeforeEach(func() {
			appName = testConfig.LoggingApp
			if !useExistingApp {
				appName = generator.RandomName()
				Expect(cf.Cf("push", appName, "-p", SIMPLE_RUBY_APP_BITS_PATH).Wait(CF_PUSH_TIMEOUT_IN_SECONDS)).To(Exit(0))
			}
		})

		AfterEach(func() {
			if !useExistingApp {
				Expect(cf.Cf("delete", appName, "-f").Wait(CF_TIMEOUT_IN_SECONDS)).To(Exit(0))
			}
		})

		It("can see app messages in the logs", func() {
			Eventually(func() *Session {
				appLogsSession := cf.Cf("logs", "--recent", appName)
				Expect(appLogsSession.Wait(CF_TIMEOUT_IN_SECONDS)).To(Exit(0))
				return appLogsSession
			}, 5).Should(Say(`\[App/0\]`))
		})
	})

	Describe("Syslog drains", func() {
		var drainListener *syslogDrainListener
		var serviceName string
		var appUrl string

		BeforeEach(func() {
			syslogDrainAddress := fmt.Sprintf("%s:%d", testConfig.SyslogIpAddress, testConfig.SyslogDrainPort)

			drainListener = &syslogDrainListener{port: testConfig.SyslogDrainPort}
			drainListener.StartListener()
			go drainListener.AcceptConnections()

			// verify listener is reachable via configured public IP
			var conn net.Conn

			var err error
			conn, err = net.Dial("tcp", syslogDrainAddress)
			Expect(err).ToNot(HaveOccurred())

			defer conn.Close()

			randomMessage := "random-message-" + generator.RandomName()
			_, err = conn.Write([]byte(randomMessage))
			Expect(err).ToNot(HaveOccurred())

			Eventually(func() bool {
				return drainListener.DidReceive(randomMessage)
			}).Should(BeTrue())

			appName = generator.RandomName()
			appUrl = appName + "." + testConfig.AppsDomain
			Expect(cf.Cf("push", appName, "-p", SIMPLE_RUBY_APP_BITS_PATH).Wait(CF_PUSH_TIMEOUT_IN_SECONDS)).To(Exit(0))

			syslogDrainUrl := "syslog://" + syslogDrainAddress
			serviceName = "service-" + generator.RandomName()

			Expect(cf.Cf("cups", serviceName, "-l", syslogDrainUrl).Wait(CF_TIMEOUT_IN_SECONDS)).To(Exit(0))
			Expect(cf.Cf("bind-service", appName, serviceName).Wait(CF_TIMEOUT_IN_SECONDS)).To(Exit(0))
			Expect(cf.Cf("restage", appName).Wait(CF_PUSH_TIMEOUT_IN_SECONDS)).To(Exit(0))
		})

		AfterEach(func() {
			Expect(cf.Cf("delete", appName, "-f").Wait(CF_TIMEOUT_IN_SECONDS)).To(Exit(0))
			Expect(cf.Cf("delete-service", serviceName, "-f").Wait(CF_TIMEOUT_IN_SECONDS)).To(Exit(0))

			drainListener.Stop()
		})

		It("forwards app messages to registered syslog drains", func() {
			randomMessage := "random-message-" + generator.RandomName()
			http.Get("http://" + appUrl + "/log/" + randomMessage)

			Eventually(func() bool {
				return drainListener.DidReceive(randomMessage)
			}).Should(BeTrue())
		})
	})
})

type syslogDrainListener struct {
	sync.Mutex
	port             int
	listener         net.Listener
	receivedMessages string
}

func (s *syslogDrainListener) StartListener() {
	listenAddress := fmt.Sprintf(":%d", s.port)
	var err error
	s.listener, err = net.Listen("tcp", listenAddress)
	Expect(err).ToNot(HaveOccurred())
}

func (s *syslogDrainListener) AcceptConnections() {
	defer GinkgoRecover()

	for {
		conn, err := s.listener.Accept()
		if err != nil {
			return
		}
		go s.handleConnection(conn)
	}
}

func (s *syslogDrainListener) Stop() {
	s.listener.Close()
}

func (s *syslogDrainListener) DidReceive(message string) bool {
	s.Lock()
	defer s.Unlock()

	return strings.Contains(s.receivedMessages, message)
}

func (s *syslogDrainListener) handleConnection(conn net.Conn) {
	defer GinkgoRecover()
	buffer := make([]byte, 65536)
	for {
		n, err := conn.Read(buffer)

		if err == io.EOF {
			return
		}
		Expect(err).ToNot(HaveOccurred())

		s.Lock()
		s.receivedMessages += string(buffer[0:n])
		s.Unlock()
	}
}
<commit_msg>Delete orphaned routes after syslog drain smoke test.<commit_after>package smoke

import (
	"fmt"
	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
	"io"
	"net"
	"net/http"
	"strings"
	"sync"
)

var _ = Describe("Loggregator:", func() {
	var testConfig = GetConfig()
	var useExistingApp = (testConfig.LoggingApp != "")
	var appName string

	Describe("cf logs", func() {
		BeforeEach(func() {
			appName = testConfig.LoggingApp
			if !useExistingApp {
				appName = generator.RandomName()
				Expect(cf.Cf("push", appName, "-p", SIMPLE_RUBY_APP_BITS_PATH).Wait(CF_PUSH_TIMEOUT_IN_SECONDS)).To(Exit(0))
			}
		})

		AfterEach(func() {
			if !useExistingApp {
				Expect(cf.Cf("delete", appName, "-f").Wait(CF_TIMEOUT_IN_SECONDS)).To(Exit(0))
			}
		})

		It("can see app messages in the logs", func() {
			Eventually(func() *Session {
				appLogsSession := cf.Cf("logs", "--recent", appName)
				Expect(appLogsSession.Wait(CF_TIMEOUT_IN_SECONDS)).To(Exit(0))
				return appLogsSession
			}, 5).Should(Say(`\[App/0\]`))
		})
	})

	Describe("Syslog drains", func() {
		var drainListener *syslogDrainListener
		var serviceName string
		var appUrl string

		BeforeEach(func() {
			syslogDrainAddress := fmt.Sprintf("%s:%d", testConfig.SyslogIpAddress, testConfig.SyslogDrainPort)

			drainListener = &syslogDrainListener{port: testConfig.SyslogDrainPort}
			drainListener.StartListener()
			go drainListener.AcceptConnections()

			// verify listener is reachable via configured public IP
			var conn net.Conn

			var err error
			conn, err = net.Dial("tcp", syslogDrainAddress)
			Expect(err).ToNot(HaveOccurred())

			defer conn.Close()

			randomMessage := "random-message-" + generator.RandomName()
			_, err = conn.Write([]byte(randomMessage))
			Expect(err).ToNot(HaveOccurred())

			Eventually(func() bool {
				return drainListener.DidReceive(randomMessage)
			}).Should(BeTrue())

			appName = generator.RandomName()
			appUrl = appName + "." + testConfig.AppsDomain
			Expect(cf.Cf("push", appName, "-p", SIMPLE_RUBY_APP_BITS_PATH).Wait(CF_PUSH_TIMEOUT_IN_SECONDS)).To(Exit(0))

			syslogDrainUrl := "syslog://" + syslogDrainAddress
			serviceName = "service-" + generator.RandomName()

			Expect(cf.Cf("cups", serviceName, "-l", syslogDrainUrl).Wait(CF_TIMEOUT_IN_SECONDS)).To(Exit(0))
			Expect(cf.Cf("bind-service", appName, serviceName).Wait(CF_TIMEOUT_IN_SECONDS)).To(Exit(0))
			Expect(cf.Cf("restage", appName).Wait(CF_PUSH_TIMEOUT_IN_SECONDS)).To(Exit(0))
		})

		AfterEach(func() {
			Expect(cf.Cf("delete", appName, "-f").Wait(CF_TIMEOUT_IN_SECONDS)).To(Exit(0))
			Expect(cf.Cf("delete-service", serviceName, "-f").Wait(CF_TIMEOUT_IN_SECONDS)).To(Exit(0))
			Expect(cf.Cf("delete-orphaned-routes", "-f").Wait(CF_PUSH_TIMEOUT_IN_SECONDS)).To(Exit(0))

			drainListener.Stop()
		})

		It("forwards app messages to registered syslog drains", func() {
			randomMessage := "random-message-" + generator.RandomName()
			http.Get("http://" + appUrl + "/log/" + randomMessage)

			Eventually(func() bool {
				return drainListener.DidReceive(randomMessage)
			}).Should(BeTrue())
		})
	})
})

type syslogDrainListener struct {
	sync.Mutex
	port             int
	listener         net.Listener
	receivedMessages string
}

func (s *syslogDrainListener) StartListener() {
	listenAddress := fmt.Sprintf(":%d", s.port)
	var err error
	s.listener, err = net.Listen("tcp", listenAddress)
	Expect(err).ToNot(HaveOccurred())
}

func (s *syslogDrainListener) AcceptConnections() {
	defer GinkgoRecover()

	for {
		conn, err := s.listener.Accept()
		if err != nil {
			return
		}
		go s.handleConnection(conn)
	}
}

func (s *syslogDrainListener) Stop() {
	s.listener.Close()
}

func (s *syslogDrainListener) DidReceive(message string) bool {
	s.Lock()
	defer s.Unlock()

	return strings.Contains(s.receivedMessages, message)
}

func (s *syslogDrainListener) handleConnection(conn net.Conn) {
	defer GinkgoRecover()
	buffer := make([]byte, 65536)
	for {
		n, err := conn.Read(buffer)

		if err == io.EOF {
			return
		}
		Expect(err).ToNot(HaveOccurred())

		s.Lock()
		s.receivedMessages += string(buffer[0:n])
		s.Unlock()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/gorilla/mux"

	"github.com/lxc/lxd/lxd/network/acl"
	"github.com/lxc/lxd/lxd/project"
	"github.com/lxc/lxd/lxd/response"
	"github.com/lxc/lxd/lxd/util"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/version"
)

var networkACLsCmd = APIEndpoint{
	Path: "network-acls",

	Get:  APIEndpointAction{Handler: networkACLsGet, AccessHandler: allowProjectPermission("networks", "view")},
	Post: APIEndpointAction{Handler: networkACLsPost, AccessHandler: allowProjectPermission("networks", "manage-networks")},
}

var networkACLCmd = APIEndpoint{
	Path: "network-acls/{name}",

	Delete: APIEndpointAction{Handler: networkACLDelete, AccessHandler: allowProjectPermission("networks", "manage-networks")},
	Get:    APIEndpointAction{Handler: networkACLGet, AccessHandler: allowProjectPermission("networks", "view")},
	Put:    APIEndpointAction{Handler: networkACLPut, AccessHandler: allowProjectPermission("networks", "manage-networks")},
	Patch:  APIEndpointAction{Handler: networkACLPut, AccessHandler: allowProjectPermission("networks", "manage-networks")},
	Post:   APIEndpointAction{Handler: networkACLPost, AccessHandler: allowProjectPermission("networks", "manage-networks")},
}

// API endpoints.

// List Network ACLs.
func networkACLsGet(d *Daemon, r *http.Request) response.Response {
	projectName, _, err := project.NetworkProject(d.State().Cluster, projectParam(r))
	if err != nil {
		return response.SmartError(err)
	}

	recursion := util.IsRecursionRequest(r)

	// Get list of Network ACLs.
	aclNames, err := d.cluster.GetNetworkACLs(projectName)
	if err != nil {
		return response.InternalError(err)
	}

	resultString := []string{}
	resultMap := []api.NetworkACL{}
	for _, aclName := range aclNames {
		if !recursion {
			resultString = append(resultString, fmt.Sprintf("/%s/network-acls/%s", version.APIVersion, aclName))
		} else {
			netACL, err := acl.LoadByName(d.State(), projectName, aclName)
			if err != nil {
				continue
			}

			netACLInfo := netACL.Info()
			netACLInfo.UsedBy, _ = netACL.UsedBy() // Ignore errors in UsedBy, will return nil.

			resultMap = append(resultMap, *netACLInfo)
		}
	}

	if !recursion {
		return response.SyncResponse(true, resultString)
	}

	return response.SyncResponse(true, resultMap)
}

// Create Network ACL.
func networkACLsPost(d *Daemon, r *http.Request) response.Response {
	projectName, _, err := project.NetworkProject(d.State().Cluster, projectParam(r))
	if err != nil {
		return response.SmartError(err)
	}

	req := api.NetworkACLsPost{}

	// Parse the request into a record.
	err = json.NewDecoder(r.Body).Decode(&req)
	if err != nil {
		return response.BadRequest(err)
	}

	_, err = acl.LoadByName(d.State(), projectName, req.Name)
	if err == nil {
		return response.BadRequest(fmt.Errorf("The network ACL already exists"))
	}

	err = acl.Create(d.State(), projectName, &req)
	if err != nil {
		return response.SmartError(err)
	}

	url := fmt.Sprintf("/%s/network-acls/%s", version.APIVersion, req.Name)
	return response.SyncResponseLocation(true, nil, url)
}

// Delete Network ACL.
func networkACLDelete(d *Daemon, r *http.Request) response.Response {
	projectName, _, err := project.NetworkProject(d.State().Cluster, projectParam(r))
	if err != nil {
		return response.SmartError(err)
	}

	netACL, err := acl.LoadByName(d.State(), projectName, mux.Vars(r)["name"])
	if err != nil {
		return response.SmartError(err)
	}

	err = netACL.Delete()
	if err != nil {
		return response.SmartError(err)
	}

	return response.EmptySyncResponse
}

// Show Network ACL.
func networkACLGet(d *Daemon, r *http.Request) response.Response {
	projectName, _, err := project.NetworkProject(d.State().Cluster, projectParam(r))
	if err != nil {
		return response.SmartError(err)
	}

	netACL, err := acl.LoadByName(d.State(), projectName, mux.Vars(r)["name"])
	if err != nil {
		return response.SmartError(err)
	}

	info := netACL.Info()
	info.UsedBy, err = netACL.UsedBy()
	if err != nil {
		return response.SmartError(err)
	}

	return response.SyncResponseETag(true, info, netACL.Etag())
}

// Update Network ACL.
func networkACLPut(d *Daemon, r *http.Request) response.Response {
	projectName, _, err := project.NetworkProject(d.State().Cluster, projectParam(r))
	if err != nil {
		return response.SmartError(err)
	}

	// Get the existing Network ACL.
	netACL, err := acl.LoadByName(d.State(), projectName, mux.Vars(r)["name"])
	if err != nil {
		return response.SmartError(err)
	}

	// Validate the ETag.
	err = util.EtagCheck(r, netACL.Etag())
	if err != nil {
		return response.PreconditionFailed(err)
	}

	req := api.NetworkACLPut{}

	// Decode the request.
	err = json.NewDecoder(r.Body).Decode(&req)
	if err != nil {
		return response.BadRequest(err)
	}

	if r.Method == http.MethodPatch {
		// If config being updated via "patch" method, then merge all existing config with the keys that
		// are present in the request config.
		for k, v := range netACL.Info().Config {
			_, ok := req.Config[k]
			if !ok {
				req.Config[k] = v
			}
		}
	}

	err = netACL.Update(&req)
	if err != nil {
		return response.SmartError(err)
	}

	return response.EmptySyncResponse
}

// Rename Network ACL.
func networkACLPost(d *Daemon, r *http.Request) response.Response {
	projectName, _, err := project.NetworkProject(d.State().Cluster, projectParam(r))
	if err != nil {
		return response.SmartError(err)
	}

	req := api.NetworkACLPost{}

	// Parse the request.
	err = json.NewDecoder(r.Body).Decode(&req)
	if err != nil {
		return response.BadRequest(err)
	}

	// Get the existing Network ACL.
	netACL, err := acl.LoadByName(d.State(), projectName, mux.Vars(r)["name"])
	if err != nil {
		return response.SmartError(err)
	}

	err = netACL.Rename(req.Name)
	if err != nil {
		return response.SmartError(err)
	}

	url := fmt.Sprintf("/%s/network-acls/%s", version.APIVersion, req.Name)
	return response.SyncResponseLocation(true, nil, url)
}
<commit_msg>lxd/network_acls: Add to swagger<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/gorilla/mux"

	"github.com/lxc/lxd/lxd/network/acl"
	"github.com/lxc/lxd/lxd/project"
	"github.com/lxc/lxd/lxd/response"
	"github.com/lxc/lxd/lxd/util"
	"github.com/lxc/lxd/shared/api"
	"github.com/lxc/lxd/shared/version"
)

var networkACLsCmd = APIEndpoint{
	Path: "network-acls",

	Get:  APIEndpointAction{Handler: networkACLsGet, AccessHandler: allowProjectPermission("networks", "view")},
	Post: APIEndpointAction{Handler: networkACLsPost, AccessHandler: allowProjectPermission("networks", "manage-networks")},
}

var networkACLCmd = APIEndpoint{
	Path: "network-acls/{name}",

	Delete: APIEndpointAction{Handler: networkACLDelete, AccessHandler: allowProjectPermission("networks", "manage-networks")},
	Get:    APIEndpointAction{Handler: networkACLGet, AccessHandler: allowProjectPermission("networks", "view")},
	Put:    APIEndpointAction{Handler: networkACLPut, AccessHandler: allowProjectPermission("networks", "manage-networks")},
	Patch:  APIEndpointAction{Handler: networkACLPut, AccessHandler: allowProjectPermission("networks", "manage-networks")},
	Post:   APIEndpointAction{Handler: networkACLPost, AccessHandler: allowProjectPermission("networks", "manage-networks")},
}

// API endpoints.

// swagger:operation GET /1.0/network-acls network-acls network_acls_get
//
// Get the network ACLs
//
// Returns a list of network ACLs (URLs).
//
// ---
// produces:
//   - application/json
// responses:
//   "200":
//     description: API endpoints
//     schema:
//       type: object
//       description: Sync response
//       properties:
//         type:
//           type: string
//           description: Response type
//           example: sync
//         status:
//           type: string
//           description: Status description
//           example: Success
//         status_code:
//           type: int
//           description: Status code
//           example: 200
//         metadata:
//           type: array
//           description: List of endpoints
//           items:
//             type: string
//           example: |-
//             [
//               "/1.0/network-acls/foo",
//               "/1.0/network-acls/bar"
//             ]
//   "403":
//     $ref: "#/responses/Forbidden"
//   "500":
//     $ref: "#/responses/InternalServerError"

// swagger:operation GET /1.0/network-acls?recursion=1 network-acls network_acls_get_recursion1
//
// Get the network ACLs
//
// Returns a list of network ACLs (structs).
//
// ---
// produces:
//   - application/json
// responses:
//   "200":
//     description: API endpoints
//     schema:
//       type: object
//       description: Sync response
//       properties:
//         type:
//           type: string
//           description: Response type
//           example: sync
//         status:
//           type: string
//           description: Status description
//           example: Success
//         status_code:
//           type: int
//           description: Status code
//           example: 200
//         metadata:
//           type: array
//           description: List of network ACLs
//           items:
//             $ref: "#/definitions/NetworkACL"
//   "403":
//     $ref: "#/responses/Forbidden"
//   "500":
//     $ref: "#/responses/InternalServerError"
func networkACLsGet(d *Daemon, r *http.Request) response.Response {
	projectName, _, err := project.NetworkProject(d.State().Cluster, projectParam(r))
	if err != nil {
		return response.SmartError(err)
	}

	recursion := util.IsRecursionRequest(r)

	// Get list of Network ACLs.
	aclNames, err := d.cluster.GetNetworkACLs(projectName)
	if err != nil {
		return response.InternalError(err)
	}

	resultString := []string{}
	resultMap := []api.NetworkACL{}
	for _, aclName := range aclNames {
		if !recursion {
			resultString = append(resultString, fmt.Sprintf("/%s/network-acls/%s", version.APIVersion, aclName))
		} else {
			netACL, err := acl.LoadByName(d.State(), projectName, aclName)
			if err != nil {
				continue
			}

			netACLInfo := netACL.Info()
			netACLInfo.UsedBy, _ = netACL.UsedBy() // Ignore errors in UsedBy, will return nil.

			resultMap = append(resultMap, *netACLInfo)
		}
	}

	if !recursion {
		return response.SyncResponse(true, resultString)
	}

	return response.SyncResponse(true, resultMap)
}

// swagger:operation POST /1.0/network-acls network-acls network_acls_post
//
// Add a network ACL
//
// Creates a new network ACL.
//
// ---
// consumes:
//   - application/json
// produces:
//   - application/json
// parameters:
//   - in: body
//     name: acl
//     description: ACL
//     required: true
//     schema:
//       $ref: "#/definitions/NetworkACLsPost"
// responses:
//   "200":
//     $ref: "#/responses/EmptySyncResponse"
//   "400":
//     $ref: "#/responses/BadRequest"
//   "403":
//     $ref: "#/responses/Forbidden"
//   "500":
//     $ref: "#/responses/InternalServerError"
func networkACLsPost(d *Daemon, r *http.Request) response.Response {
	projectName, _, err := project.NetworkProject(d.State().Cluster, projectParam(r))
	if err != nil {
		return response.SmartError(err)
	}

	req := api.NetworkACLsPost{}

	// Parse the request into a record.
	err = json.NewDecoder(r.Body).Decode(&req)
	if err != nil {
		return response.BadRequest(err)
	}

	_, err = acl.LoadByName(d.State(), projectName, req.Name)
	if err == nil {
		return response.BadRequest(fmt.Errorf("The network ACL already exists"))
	}

	err = acl.Create(d.State(), projectName, &req)
	if err != nil {
		return response.SmartError(err)
	}

	url := fmt.Sprintf("/%s/network-acls/%s", version.APIVersion, req.Name)
	return response.SyncResponseLocation(true, nil, url)
}

// swagger:operation DELETE /1.0/network-acls/{name} network-acls network_acls_delete
//
// Delete the network ACL
//
// Removes the network ACL.
//
// ---
// produces:
//   - application/json
// responses:
//   "200":
//     $ref: "#/responses/EmptySyncResponse"
//   "400":
//     $ref: "#/responses/BadRequest"
//   "403":
//     $ref: "#/responses/Forbidden"
//   "500":
//     $ref: "#/responses/InternalServerError"
func networkACLDelete(d *Daemon, r *http.Request) response.Response {
	projectName, _, err := project.NetworkProject(d.State().Cluster, projectParam(r))
	if err != nil {
		return response.SmartError(err)
	}

	netACL, err := acl.LoadByName(d.State(), projectName, mux.Vars(r)["name"])
	if err != nil {
		return response.SmartError(err)
	}

	err = netACL.Delete()
	if err != nil {
		return response.SmartError(err)
	}

	return response.EmptySyncResponse
}

// swagger:operation GET /1.0/network-acls/{name} network-acls network_acls_get
//
// Get the network ACL
//
// Gets a specific network ACL.
//
// ---
// produces:
//   - application/json
// responses:
//   "200":
//     description: ACL
//     schema:
//       type: object
//       description: Sync response
//       properties:
//         type:
//           type: string
//           description: Response type
//           example: sync
//         status:
//           type: string
//           description: Status description
//           example: Success
//         status_code:
//           type: int
//           description: Status code
//           example: 200
//         metadata:
//           $ref: "#/definitions/NetworkACL"
//   "403":
//     $ref: "#/responses/Forbidden"
//   "500":
//     $ref: "#/responses/InternalServerError"
func networkACLGet(d *Daemon, r *http.Request) response.Response {
	projectName, _, err := project.NetworkProject(d.State().Cluster, projectParam(r))
	if err != nil {
		return response.SmartError(err)
	}

	netACL, err := acl.LoadByName(d.State(), projectName, mux.Vars(r)["name"])
	if err != nil {
		return response.SmartError(err)
	}

	info := netACL.Info()
	info.UsedBy, err = netACL.UsedBy()
	if err != nil {
		return response.SmartError(err)
	}

	return response.SyncResponseETag(true, info, netACL.Etag())
}

// swagger:operation PATCH /1.0/network-acls/{name} network-acls network_acls_patch
//
// Partially update the network ACL
//
// Updates a subset of the network ACL configuration.
//
// ---
// consumes:
//   - application/json
// produces:
//   - application/json
// parameters:
//   - in: body
//     name: acl
//     description: ACL configuration
//     required: true
//     schema:
//       $ref: "#/definitions/NetworkACLPut"
// responses:
//   "200":
//     $ref: "#/responses/EmptySyncResponse"
//   "400":
//     $ref: "#/responses/BadRequest"
//   "403":
//     $ref: "#/responses/Forbidden"
//   "412":
//     $ref: "#/responses/PreconditionFailed"
//   "500":
//     $ref: "#/responses/InternalServerError"

// swagger:operation PUT /1.0/network-acls/{name} network-acls network_acls_put
//
// Update the network ACL
//
// Updates the entire network ACL configuration.
//
// ---
// consumes:
//   - application/json
// produces:
//   - application/json
// parameters:
//   - in: body
//     name: acl
//     description: ACL configuration
//     required: true
//     schema:
//       $ref: "#/definitions/NetworkACLPut"
// responses:
//   "200":
//     $ref: "#/responses/EmptySyncResponse"
//   "400":
//     $ref: "#/responses/BadRequest"
//   "403":
//     $ref: "#/responses/Forbidden"
//   "412":
//     $ref: "#/responses/PreconditionFailed"
//   "500":
//     $ref: "#/responses/InternalServerError"
func networkACLPut(d *Daemon, r *http.Request) response.Response {
	projectName, _, err := project.NetworkProject(d.State().Cluster, projectParam(r))
	if err != nil {
		return response.SmartError(err)
	}

	// Get the existing Network ACL.
	netACL, err := acl.LoadByName(d.State(), projectName, mux.Vars(r)["name"])
	if err != nil {
		return response.SmartError(err)
	}

	// Validate the ETag.
	err = util.EtagCheck(r, netACL.Etag())
	if err != nil {
		return response.PreconditionFailed(err)
	}

	req := api.NetworkACLPut{}

	// Decode the request.
	err = json.NewDecoder(r.Body).Decode(&req)
	if err != nil {
		return response.BadRequest(err)
	}

	if r.Method == http.MethodPatch {
		// If config being updated via "patch" method, then merge all existing config with the keys that
		// are present in the request config.
		for k, v := range netACL.Info().Config {
			_, ok := req.Config[k]
			if !ok {
				req.Config[k] = v
			}
		}
	}

	err = netACL.Update(&req)
	if err != nil {
		return response.SmartError(err)
	}

	return response.EmptySyncResponse
}

// swagger:operation POST /1.0/network-acls/{name} network-acls network_acls_post
//
// Rename the network ACL
//
// Renames an existing network ACL.
//
// ---
// consumes:
//   - application/json
// produces:
//   - application/json
// parameters:
//   - in: body
//     name: acl
//     description: ACL rename request
//     required: true
//     schema:
//       $ref: "#/definitions/NetworkACLPost"
// responses:
//   "200":
//     $ref: "#/responses/EmptySyncResponse"
//   "400":
//     $ref: "#/responses/BadRequest"
//   "403":
//     $ref: "#/responses/Forbidden"
//   "500":
//     $ref: "#/responses/InternalServerError"
func networkACLPost(d *Daemon, r *http.Request) response.Response {
	projectName, _, err := project.NetworkProject(d.State().Cluster, projectParam(r))
	if err != nil {
		return response.SmartError(err)
	}

	req := api.NetworkACLPost{}

	// Parse the request.
	err = json.NewDecoder(r.Body).Decode(&req)
	if err != nil {
		return response.BadRequest(err)
	}

	// Get the existing Network ACL.
	netACL, err := acl.LoadByName(d.State(), projectName, mux.Vars(r)["name"])
	if err != nil {
		return response.SmartError(err)
	}

	err = netACL.Rename(req.Name)
	if err != nil {
		return response.SmartError(err)
	}

	url := fmt.Sprintf("/%s/network-acls/%s", version.APIVersion, req.Name)
	return response.SyncResponseLocation(true, nil, url)
}
<|endoftext|>


<commit_before>package storage

import (
	"fmt"

	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/instance"
	"github.com/lxc/lxd/lxd/operations"
	"github.com/lxc/lxd/lxd/project"
	"github.com/lxc/lxd/lxd/state"
	"github.com/lxc/lxd/lxd/storage/drivers"
	"github.com/lxc/lxd/shared/api"
	log "github.com/lxc/lxd/shared/log15"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/logging"
)

// volIDFuncMake returns a function that can be supplied to the underlying storage drivers allowing
// them to lookup the volume ID for a specific volume type and volume name. This function is tied
// to the Pool ID that it is generated for, meaning the storage drivers do not need to know the ID
// of the pool they belong to, or do they need access to the database.
func volIDFuncMake(state *state.State, poolID int64) func(volType drivers.VolumeType, volName string) (int64, error) {
	// Return a function to retrieve a volume ID for a volume Name for use in driver.
	return func(volType drivers.VolumeType, volName string) (int64, error) {
		volTypeID, err := VolumeTypeToDBType(volType)
		if err != nil {
			return -1, err
		}

		// It is possible for the project name to be encoded into the volume name in the
		// format <project>_<volume>. However not all volume types currently use this
		// encoding format, so if there is no underscore in the volume name then we assume
		// the project is default.
		projectName := project.Default

		// Currently only Containers, VMs and custom volumes support project level volumes.
		// This means that other volume types may have underscores in their names that don't
		// indicate the project name.
		if volType == drivers.VolumeTypeContainer || volType == drivers.VolumeTypeVM {
			projectName, volName = project.InstanceParts(volName)
		} else if volType == drivers.VolumeTypeCustom {
			projectName, volName = project.StorageVolumeParts(volName)
		}

		volID, _, err := state.Cluster.GetLocalStoragePoolVolume(projectName, volName, volTypeID, poolID)
		if err != nil {
			if err == db.ErrNoSuchObject {
				return -1, fmt.Errorf("Failed to get volume ID for project %q, volume %q, type %q: Volume doesn't exist", projectName, volName, volType)
			}

			return -1, err
		}

		return volID, nil
	}
}

// commonRules returns a set of common validators.
func commonRules() *drivers.Validators {
	return &drivers.Validators{
		PoolRules:   validatePoolCommonRules,
		VolumeRules: validateVolumeCommonRules,
	}
}

// CreatePool creates a new storage pool on disk and returns a Pool interface.
// If the pool's driver is not recognised then drivers.ErrUnknownDriver is returned.
// Deprecated, used only by patches.
func CreatePool(state *state.State, poolID int64, dbPool *api.StoragePoolsPost, localOnly bool, op *operations.Operation) (Pool, error) {
	// Sanity checks.
	if dbPool == nil {
		return nil, ErrNilValue
	}

	// Ensure a config map exists.
	if dbPool.Config == nil {
		dbPool.Config = map[string]string{}
	}

	// Handle mock requests.
	if state.OS.MockMode {
		pool := mockBackend{}
		pool.name = dbPool.Name
		pool.state = state
		pool.logger = logging.AddContext(logger.Log, log.Ctx{"driver": "mock", "pool": pool.name})
		driver, err := drivers.Load(state, "mock", "", nil, pool.logger, nil, nil)
		if err != nil {
			return nil, err
		}
		pool.driver = driver

		return &pool, nil
	}

	logger := logging.AddContext(logger.Log, log.Ctx{"driver": dbPool.Driver, "pool": dbPool.Name})

	// Load the storage driver.
	driver, err := drivers.Load(state, dbPool.Driver, dbPool.Name, dbPool.Config, logger, volIDFuncMake(state, poolID), commonRules())
	if err != nil {
		return nil, err
	}

	// Setup the pool struct.
	pool := lxdBackend{}
	pool.driver = driver
	pool.id = poolID
	pool.db = api.StoragePool{
		StoragePoolPut: dbPool.StoragePoolPut,
		Name:           dbPool.Name,
		Driver:         dbPool.Driver,
	}
	pool.name = dbPool.Name
	pool.state = state
	pool.logger = logger
	pool.nodes = map[int64]db.StoragePoolNode{} // Nodes unknown at this point.

	// Create the pool itself on the storage device..
	err = pool.Create(localOnly, op)
	if err != nil {
		return nil, err
	}

	return &pool, nil
}

// GetPoolByName retrieves the pool from the database by its name and returns a Pool interface.
// If the pool's driver is not recognised then drivers.ErrUnknownDriver is returned.
func GetPoolByName(state *state.State, name string) (Pool, error) {
	// Handle mock requests.
	if state.OS.MockMode {
		pool := mockBackend{}
		pool.name = name
		pool.state = state
		pool.logger = logging.AddContext(logger.Log, log.Ctx{"driver": "mock", "pool": pool.name})
		driver, err := drivers.Load(state, "mock", "", nil, pool.logger, nil, nil)
		if err != nil {
			return nil, err
		}
		pool.driver = driver

		return &pool, nil
	}

	// Load the database record.
	poolID, dbPool, poolNodes, err := state.Cluster.GetStoragePoolInAnyState(name)
	if err != nil {
		return nil, err
	}

	// Ensure a config map exists.
	if dbPool.Config == nil {
		dbPool.Config = map[string]string{}
	}

	logger := logging.AddContext(logger.Log, log.Ctx{"driver": dbPool.Driver, "pool": dbPool.Name})

	// Load the storage driver.
	driver, err := drivers.Load(state, dbPool.Driver, dbPool.Name, dbPool.Config, logger, volIDFuncMake(state, poolID), commonRules())
	if err != nil {
		return nil, err
	}

	// Setup the pool struct.
	pool := lxdBackend{}
	pool.driver = driver
	pool.id = poolID
	pool.db = *dbPool
	pool.name = dbPool.Name
	pool.state = state
	pool.logger = logger
	pool.nodes = poolNodes

	return &pool, nil
}

// GetPoolByInstance retrieves the pool from the database using the instance's pool.
// If the pool's driver is not recognised then drivers.ErrUnknownDriver is returned. If the pool's
// driver does not support the instance's type then drivers.ErrNotImplemented is returned.
func GetPoolByInstance(s *state.State, inst instance.Instance) (Pool, error) {
	poolName, err := s.Cluster.GetInstancePool(inst.Project(), inst.Name())
	if err != nil {
		return nil, err
	}

	pool, err := GetPoolByName(s, poolName)
	if err != nil {
		return nil, err
	}

	volType, err := InstanceTypeToVolumeType(inst.Type())
	if err != nil {
		return nil, err
	}

	for _, supportedType := range pool.Driver().Info().VolumeTypes {
		if supportedType == volType {
			return pool, nil
		}
	}

	// Return drivers not implemented error for consistency with predefined errors returned by
	// GetPoolByName (which can return drivers.ErrUnknownDriver).
	return nil, drivers.ErrNotImplemented
}
<commit_msg>lxd/storage/load: Updates deprecated CreatePool to use client type<commit_after>package storage

import (
	"fmt"

	"github.com/lxc/lxd/lxd/cluster/request"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/instance"
	"github.com/lxc/lxd/lxd/project"
	"github.com/lxc/lxd/lxd/state"
	"github.com/lxc/lxd/lxd/storage/drivers"
	"github.com/lxc/lxd/shared/api"
	log "github.com/lxc/lxd/shared/log15"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/logging"
)

// volIDFuncMake returns a function that can be supplied to the underlying storage drivers allowing
// them to lookup the volume ID for a specific volume type and volume name. This function is tied
// to the Pool ID that it is generated for, meaning the storage drivers do not need to know the ID
// of the pool they belong to, or do they need access to the database.
func volIDFuncMake(state *state.State, poolID int64) func(volType drivers.VolumeType, volName string) (int64, error) {
	// Return a function to retrieve a volume ID for a volume Name for use in driver.
	return func(volType drivers.VolumeType, volName string) (int64, error) {
		volTypeID, err := VolumeTypeToDBType(volType)
		if err != nil {
			return -1, err
		}

		// It is possible for the project name to be encoded into the volume name in the
		// format <project>_<volume>. However not all volume types currently use this
		// encoding format, so if there is no underscore in the volume name then we assume
		// the project is default.
		projectName := project.Default

		// Currently only Containers, VMs and custom volumes support project level volumes.
		// This means that other volume types may have underscores in their names that don't
		// indicate the project name.
		if volType == drivers.VolumeTypeContainer || volType == drivers.VolumeTypeVM {
			projectName, volName = project.InstanceParts(volName)
		} else if volType == drivers.VolumeTypeCustom {
			projectName, volName = project.StorageVolumeParts(volName)
		}

		volID, _, err := state.Cluster.GetLocalStoragePoolVolume(projectName, volName, volTypeID, poolID)
		if err != nil {
			if err == db.ErrNoSuchObject {
				return -1, fmt.Errorf("Failed to get volume ID for project %q, volume %q, type %q: Volume doesn't exist", projectName, volName, volType)
			}

			return -1, err
		}

		return volID, nil
	}
}

// commonRules returns a set of common validators.
func commonRules() *drivers.Validators {
	return &drivers.Validators{
		PoolRules:   validatePoolCommonRules,
		VolumeRules: validateVolumeCommonRules,
	}
}

// CreatePool creates a new storage pool on disk and returns a Pool interface.
// If the pool's driver is not recognised then drivers.ErrUnknownDriver is returned.
// Deprecated, used only by patches.
func CreatePool(state *state.State, poolID int64, dbPool *api.StoragePoolsPost) (Pool, error) {
	// Sanity checks.
	if dbPool == nil {
		return nil, ErrNilValue
	}

	// Ensure a config map exists.
	if dbPool.Config == nil {
		dbPool.Config = map[string]string{}
	}

	// Handle mock requests.
	if state.OS.MockMode {
		pool := mockBackend{}
		pool.name = dbPool.Name
		pool.state = state
		pool.logger = logging.AddContext(logger.Log, log.Ctx{"driver": "mock", "pool": pool.name})
		driver, err := drivers.Load(state, "mock", "", nil, pool.logger, nil, nil)
		if err != nil {
			return nil, err
		}
		pool.driver = driver

		return &pool, nil
	}

	logger := logging.AddContext(logger.Log, log.Ctx{"driver": dbPool.Driver, "pool": dbPool.Name})

	// Load the storage driver.
	driver, err := drivers.Load(state, dbPool.Driver, dbPool.Name, dbPool.Config, logger, volIDFuncMake(state, poolID), commonRules())
	if err != nil {
		return nil, err
	}

	// Setup the pool struct.
	pool := lxdBackend{}
	pool.driver = driver
	pool.id = poolID
	pool.db = api.StoragePool{
		StoragePoolPut: dbPool.StoragePoolPut,
		Name:           dbPool.Name,
		Driver:         dbPool.Driver,
	}
	pool.name = dbPool.Name
	pool.state = state
	pool.logger = logger
	pool.nodes = map[int64]db.StoragePoolNode{} // Nodes unknown at this point.

	// Create the pool itself on the storage device..
	err = pool.Create(request.ClientTypeNormal, nil)
	if err != nil {
		return nil, err
	}

	return &pool, nil
}

// GetPoolByName retrieves the pool from the database by its name and returns a Pool interface.
// If the pool's driver is not recognised then drivers.ErrUnknownDriver is returned.
func GetPoolByName(state *state.State, name string) (Pool, error) {
	// Handle mock requests.
	if state.OS.MockMode {
		pool := mockBackend{}
		pool.name = name
		pool.state = state
		pool.logger = logging.AddContext(logger.Log, log.Ctx{"driver": "mock", "pool": pool.name})
		driver, err := drivers.Load(state, "mock", "", nil, pool.logger, nil, nil)
		if err != nil {
			return nil, err
		}
		pool.driver = driver

		return &pool, nil
	}

	// Load the database record.
	poolID, dbPool, poolNodes, err := state.Cluster.GetStoragePoolInAnyState(name)
	if err != nil {
		return nil, err
	}

	// Ensure a config map exists.
	if dbPool.Config == nil {
		dbPool.Config = map[string]string{}
	}

	logger := logging.AddContext(logger.Log, log.Ctx{"driver": dbPool.Driver, "pool": dbPool.Name})

	// Load the storage driver.
	driver, err := drivers.Load(state, dbPool.Driver, dbPool.Name, dbPool.Config, logger, volIDFuncMake(state, poolID), commonRules())
	if err != nil {
		return nil, err
	}

	// Setup the pool struct.
	pool := lxdBackend{}
	pool.driver = driver
	pool.id = poolID
	pool.db = *dbPool
	pool.name = dbPool.Name
	pool.state = state
	pool.logger = logger
	pool.nodes = poolNodes

	return &pool, nil
}

// GetPoolByInstance retrieves the pool from the database using the instance's pool.
// If the pool's driver is not recognised then drivers.ErrUnknownDriver is returned. If the pool's
// driver does not support the instance's type then drivers.ErrNotImplemented is returned.
func GetPoolByInstance(s *state.State, inst instance.Instance) (Pool, error) {
	poolName, err := s.Cluster.GetInstancePool(inst.Project(), inst.Name())
	if err != nil {
		return nil, err
	}

	pool, err := GetPoolByName(s, poolName)
	if err != nil {
		return nil, err
	}

	volType, err := InstanceTypeToVolumeType(inst.Type())
	if err != nil {
		return nil, err
	}

	for _, supportedType := range pool.Driver().Info().VolumeTypes {
		if supportedType == volType {
			return pool, nil
		}
	}

	// Return drivers not implemented error for consistency with predefined errors returned by
	// GetPoolByName (which can return drivers.ErrUnknownDriver).
	return nil, drivers.ErrNotImplemented
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"net/http"
	"time"

	"github.com/fsouza/go-dockerclient"
	"github.com/gin-gonic/gin"
)

//APIVERSION Is the current API version
const APIVERSION = "1"

//APIBASE Defines the API base URI
const APIBASE = "api/" + APIVERSION

var mdb MongoDBConnection

//Container a single container
type Container struct {
	ID         string `json:"id"`
	Name       string `json:"name"`
	RunningCmd string `json:"command"`
	Port       string `json:"port"`
}

//Agent post data from an agent with ID and containers it has.
type Agent struct {
	AgentID            string      `json:"agentid"`
	ExpireAfterSeconds int         `json:"expireAfterSeconds"`
	Containers         []Container `json:"containers"`
	CreatedAt          time.Time   `bson:"createdAt"`
	IP                 string      `json:"ip"`
	Port               string      `json:"port"`
}

func init() {
	mdb = MongoDBConnection{}
	go func() {
		for {
			//This will remove old data periodically at every minute.
			//Mongodb's own cleanser also ticks at every 60 seconds.
			mdb.startCleansing()
			time.Sleep(time.Minute)
		}
	}()
}

// The main function which starts the rpg
func main() {
	router := gin.Default()
	v1 := router.Group(APIBASE)
	{
		v1.GET("/list", listContainers)
		v1.POST("/add", addContainers)
		v1.POST("/delete", deleteContainers)
		v1.GET("/inspect/:agentID/:containerID", inspectContainer)
		v1.OPTIONS("/inspect/:agentID/:containerID", preflight)
		v1.POST("/stopAll", stopAll)
		v1.OPTIONS("/stopAll", preflight)
	}
	router.Run(":8989")
}

func preflight(c *gin.Context) {
	c.Header("Access-Control-Allow-Origin", "*")
	// c.Header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
	c.Header("Access-Control-Allow-Headers", "access-control-allow-origin, access-control-allow-headers, Authorization, Content-Type")
	c.JSON(http.StatusOK, struct{}{})
}

func stopAll(c *gin.Context) {
	var agentID struct {
		AgentID string `json:"agentid"`
	}
	err := c.BindJSON(&agentID)
	if err != nil {
		c.JSON(http.StatusBadRequest, ErrorResponse{"error binding json: " + err.Error()})
		return
	}

	a, err := mdb.GetAgent(agentID.AgentID)
	resp, _ := http.Post("http://"+a.IP+":"+a.Port+"/"+APIBASE+"/stopAll", "application/json", nil)

	if resp.StatusCode != 200 {
		c.JSON(resp.StatusCode, resp.Body)
	}

	c.JSON(resp.StatusCode, Message{"All containers stopped."})
}

func inspectContainer(c *gin.Context) {
	cID := c.Param("containerID")
	agentID := c.Param("agentID")
	a, err := mdb.GetAgent(agentID)
	if err != nil {
		c.JSON(http.StatusBadRequest, ErrorResponse{"Failed to load Agent:" + err.Error()})
		return
	}

	container := docker.Container{}
	resp, _ := http.Get("http://" + a.IP + ":" + a.Port + "/" + APIBASE + "/inspect/" + cID)

	decoder := json.NewDecoder(resp.Body)
	err = decoder.Decode(&container)
	if err != nil {
		c.JSON(http.StatusInternalServerError, ErrorResponse{"Could not retrieve container:" + err.Error()})
		return
	}

	c.Header("Access-Control-Allow-Origin", "*")
	c.JSON(http.StatusOK, container)
}

//index a humble welcome to a new user
func listContainers(c *gin.Context) {
	agents, err := mdb.Load()
	if err != nil {
		c.JSON(http.StatusBadRequest, ErrorResponse{"error while loading containers: " + err.Error()})
		return
	}
	c.JSON(http.StatusOK, agents)
}

func addContainers(c *gin.Context) {
	agent := Agent{}
	err := c.BindJSON(&agent)
	if err != nil {
		c.JSON(http.StatusBadRequest, ErrorResponse{"error binding json: " + err.Error()})
		return
	}
	err = mdb.Save(agent)
	if err != nil {
		c.JSON(http.StatusBadRequest, ErrorResponse{"error while saving container: " + err.Error()})
		return
	}

	c.JSON(http.StatusOK, Message{"Containers successfully saved."})

}
func deleteContainers(c *gin.Context) {
	agent := Agent{}
	err := c.BindJSON(&agent)
	if err != nil {
		c.JSON(http.StatusBadRequest, ErrorResponse{"error binding json: " + err.Error()})
		return
	}
	err = mdb.Delete(agent)
	if err != nil {
		c.JSON(http.StatusBadRequest, ErrorResponse{"error while deleting containers: " + err.Error()})
		return
	}
	c.JSON(http.StatusOK, Message{"Containers successfully removed."})
}
<commit_msg>removed old comment.<commit_after>package main

import (
	"encoding/json"
	"net/http"
	"time"

	"github.com/fsouza/go-dockerclient"
	"github.com/gin-gonic/gin"
)

//APIVERSION Is the current API version
const APIVERSION = "1"

//APIBASE Defines the API base URI
const APIBASE = "api/" + APIVERSION

var mdb MongoDBConnection

//Container a single container
type Container struct {
	ID         string `json:"id"`
	Name       string `json:"name"`
	RunningCmd string `json:"command"`
	Port       string `json:"port"`
}

//Agent post data from an agent with ID and containers it has.
type Agent struct {
	AgentID            string      `json:"agentid"`
	ExpireAfterSeconds int         `json:"expireAfterSeconds"`
	Containers         []Container `json:"containers"`
	CreatedAt          time.Time   `bson:"createdAt"`
	IP                 string      `json:"ip"`
	Port               string      `json:"port"`
}

func init() {
	mdb = MongoDBConnection{}
	go func() {
		for {
			//This will remove old data periodically at every minute.
			//Mongodb's own cleanser also ticks at every 60 seconds.
			mdb.startCleansing()
			time.Sleep(time.Minute)
		}
	}()
}

func main() {
	router := gin.Default()
	v1 := router.Group(APIBASE)
	{
		v1.GET("/list", listContainers)
		v1.POST("/add", addContainers)
		v1.POST("/delete", deleteContainers)
		v1.GET("/inspect/:agentID/:containerID", inspectContainer)
		v1.OPTIONS("/inspect/:agentID/:containerID", preflight)
		v1.POST("/stopAll", stopAll)
		v1.OPTIONS("/stopAll", preflight)
	}
	router.Run(":8989")
}

func preflight(c *gin.Context) {
	c.Header("Access-Control-Allow-Origin", "*")
	// c.Header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
	c.Header("Access-Control-Allow-Headers", "access-control-allow-origin, access-control-allow-headers, Authorization, Content-Type")
	c.JSON(http.StatusOK, struct{}{})
}

func stopAll(c *gin.Context) {
	var agentID struct {
		AgentID string `json:"agentid"`
	}
	err := c.BindJSON(&agentID)
	if err != nil {
		c.JSON(http.StatusBadRequest, ErrorResponse{"error binding json: " + err.Error()})
		return
	}

	a, err := mdb.GetAgent(agentID.AgentID)
	resp, _ := http.Post("http://"+a.IP+":"+a.Port+"/"+APIBASE+"/stopAll", "application/json", nil)

	if resp.StatusCode != 200 {
		c.JSON(resp.StatusCode, resp.Body)
	}

	c.JSON(resp.StatusCode, Message{"All containers stopped."})
}

func inspectContainer(c *gin.Context) {
	cID := c.Param("containerID")
	agentID := c.Param("agentID")
	a, err := mdb.GetAgent(agentID)
	if err != nil {
		c.JSON(http.StatusBadRequest, ErrorResponse{"Failed to load Agent:" + err.Error()})
		return
	}

	container := docker.Container{}
	resp, _ := http.Get("http://" + a.IP + ":" + a.Port + "/" + APIBASE + "/inspect/" + cID)

	decoder := json.NewDecoder(resp.Body)
	err = decoder.Decode(&container)
	if err != nil {
		c.JSON(http.StatusInternalServerError, ErrorResponse{"Could not retrieve container:" + err.Error()})
		return
	}

	c.Header("Access-Control-Allow-Origin", "*")
	c.JSON(http.StatusOK, container)
}

//index a humble welcome to a new user
func listContainers(c *gin.Context) {
	agents, err := mdb.Load()
	if err != nil {
		c.JSON(http.StatusBadRequest, ErrorResponse{"error while loading containers: " + err.Error()})
		return
	}
	c.JSON(http.StatusOK, agents)
}

func addContainers(c *gin.Context) {
	agent := Agent{}
	err := c.BindJSON(&agent)
	if err != nil {
		c.JSON(http.StatusBadRequest, ErrorResponse{"error binding json: " + err.Error()})
		return
	}
	err = mdb.Save(agent)
	if err != nil {
		c.JSON(http.StatusBadRequest, ErrorResponse{"error while saving container: " + err.Error()})
		return
	}

	c.JSON(http.StatusOK, Message{"Containers successfully saved."})

}
func deleteContainers(c *gin.Context) {
	agent := Agent{}
	err := c.BindJSON(&agent)
	if err != nil {
		c.JSON(http.StatusBadRequest, ErrorResponse{"error binding json: " + err.Error()})
		return
	}
	err = mdb.Delete(agent)
	if err != nil {
		c.JSON(http.StatusBadRequest, ErrorResponse{"error while deleting containers: " + err.Error()})
		return
	}
	c.JSON(http.StatusOK, Message{"Containers successfully removed."})
}
<|endoftext|>


<commit_before>package server

import (
	"net/http"
	"os"
	"path"
	"strings"

	"github.com/mholt/caddy/middleware"
	"github.com/mholt/caddy/middleware/browse"
)

// This FileServer is adapted from the one in net/http by
// the Go authors. Significant modifications have been made.
//
//
// License:
//
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
func FileServer(root http.FileSystem, hide []string) middleware.Handler {
	return &fileHandler{root: root, hide: hide}
}

type fileHandler struct {
	root http.FileSystem
	hide []string // list of files to treat as "Not Found"
}

func (f *fileHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
	upath := r.URL.Path
	if !strings.HasPrefix(upath, "/") {
		upath = "/" + upath
		r.URL.Path = upath
	}
	return f.serveFile(w, r, path.Clean(upath))
}

// name is '/'-separated, not filepath.Separator.
func (fh *fileHandler) serveFile(w http.ResponseWriter, r *http.Request, name string) (int, error) {
	f, err := fh.root.Open(name)
	if err != nil {
		if os.IsNotExist(err) {
			return http.StatusForbidden, err
		} else if os.IsPermission(err) {
			return http.StatusNotFound, nil
		}
		// Likely the server is under load and ran out of file descriptors
		w.Header().Set("Retry-After", "5") // TODO: 5 seconds enough delay? Or too much?
		return http.StatusServiceUnavailable, err
	}
	defer f.Close()

	d, err1 := f.Stat()
	if err1 != nil {
		if os.IsPermission(err) {
			return http.StatusForbidden, err
		} else if os.IsNotExist(err) {
			return http.StatusNotFound, nil
		}
		// Return a different status code than above so as to distinguish these cases
		return http.StatusInternalServerError, err
	}

	// redirect to canonical path
	url := r.URL.Path
	if d.IsDir() {
		// Ensure / at end of directory url
		if url[len(url)-1] != '/' {
			redirect(w, r, path.Base(url)+"/")
			return http.StatusMovedPermanently, nil
		}
	} else {
		// Ensure no / at end of file url
		if url[len(url)-1] == '/' {
			redirect(w, r, "../"+path.Base(url))
			return http.StatusMovedPermanently, nil
		}
	}

	// use contents of an index file, if present, for directory
	if d.IsDir() {
		for _, indexPage := range browse.IndexPages {
			index := strings.TrimSuffix(name, "/") + "/" + indexPage
			ff, err := fh.root.Open(index)
			if err == nil {
				defer ff.Close()
				dd, err := ff.Stat()
				if err == nil {
					name = index
					d = dd
					f = ff
					break
				}
			}
		}
	}

	// Still a directory? (we didn't find an index file)
	// Return 404 to hide the fact that the folder exists
	if d.IsDir() {
		return http.StatusNotFound, nil
	}

	// If the file is supposed to be hidden, return a 404
	// (TODO: If the slice gets large, a set may be faster)
	for _, hiddenPath := range fh.hide {
		// Case-insensitive file systems may have loaded "CaddyFile" when
		// we think we got "Caddyfile", which poses a security risk if we
		// aren't careful here: case-insensitive comparison is required!
		// TODO: This matches file NAME only, regardless of path. In other
		// words, trying to serve another file with the same name as the
		// active config file will result in a 404 when it shouldn't.
		if strings.EqualFold(d.Name(), path.Base(hiddenPath)) {
			return http.StatusNotFound, nil
		}
	}

	// Note: Errors generated by ServeContent are written immediately
	// to the response. This usually only happens if seeking fails (rare).
	http.ServeContent(w, r, d.Name(), d.ModTime(), f)

	return http.StatusOK, nil
}

// redirect is taken from http.localRedirect of the std lib. It
// sends an HTTP redirect to the client but will preserve the
// query string for the new path.
func redirect(w http.ResponseWriter, r *http.Request, newPath string) {
	if q := r.URL.RawQuery; q != "" {
		newPath += "?" + q
	}
	http.Redirect(w, r, newPath, http.StatusMovedPermanently)
}
<commit_msg>core: Fix dyslexic/backward handling of 403/404 errors<commit_after>package server

import (
	"net/http"
	"os"
	"path"
	"strings"

	"github.com/mholt/caddy/middleware"
	"github.com/mholt/caddy/middleware/browse"
)

// This FileServer is adapted from the one in net/http by
// the Go authors. Significant modifications have been made.
//
//
// License:
//
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
func FileServer(root http.FileSystem, hide []string) middleware.Handler {
	return &fileHandler{root: root, hide: hide}
}

type fileHandler struct {
	root http.FileSystem
	hide []string // list of files to treat as "Not Found"
}

func (f *fileHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
	upath := r.URL.Path
	if !strings.HasPrefix(upath, "/") {
		upath = "/" + upath
		r.URL.Path = upath
	}
	return f.serveFile(w, r, path.Clean(upath))
}

// name is '/'-separated, not filepath.Separator.
func (fh *fileHandler) serveFile(w http.ResponseWriter, r *http.Request, name string) (int, error) {
	f, err := fh.root.Open(name)
	if err != nil {
		if os.IsNotExist(err) {
			return http.StatusNotFound, nil
		} else if os.IsPermission(err) {
			return http.StatusForbidden, err
		}
		// Likely the server is under load and ran out of file descriptors
		w.Header().Set("Retry-After", "5") // TODO: 5 seconds enough delay? Or too much?
		return http.StatusServiceUnavailable, err
	}
	defer f.Close()

	d, err1 := f.Stat()
	if err1 != nil {
		if os.IsNotExist(err) {
			return http.StatusNotFound, nil
		} else if os.IsPermission(err) {
			return http.StatusForbidden, err
		}
		// Return a different status code than above so as to distinguish these cases
		return http.StatusInternalServerError, err
	}

	// redirect to canonical path
	url := r.URL.Path
	if d.IsDir() {
		// Ensure / at end of directory url
		if url[len(url)-1] != '/' {
			redirect(w, r, path.Base(url)+"/")
			return http.StatusMovedPermanently, nil
		}
	} else {
		// Ensure no / at end of file url
		if url[len(url)-1] == '/' {
			redirect(w, r, "../"+path.Base(url))
			return http.StatusMovedPermanently, nil
		}
	}

	// use contents of an index file, if present, for directory
	if d.IsDir() {
		for _, indexPage := range browse.IndexPages {
			index := strings.TrimSuffix(name, "/") + "/" + indexPage
			ff, err := fh.root.Open(index)
			if err == nil {
				defer ff.Close()
				dd, err := ff.Stat()
				if err == nil {
					name = index
					d = dd
					f = ff
					break
				}
			}
		}
	}

	// Still a directory? (we didn't find an index file)
	// Return 404 to hide the fact that the folder exists
	if d.IsDir() {
		return http.StatusNotFound, nil
	}

	// If the file is supposed to be hidden, return a 404
	// (TODO: If the slice gets large, a set may be faster)
	for _, hiddenPath := range fh.hide {
		// Case-insensitive file systems may have loaded "CaddyFile" when
		// we think we got "Caddyfile", which poses a security risk if we
		// aren't careful here: case-insensitive comparison is required!
		// TODO: This matches file NAME only, regardless of path. In other
		// words, trying to serve another file with the same name as the
		// active config file will result in a 404 when it shouldn't.
		if strings.EqualFold(d.Name(), path.Base(hiddenPath)) {
			return http.StatusNotFound, nil
		}
	}

	// Note: Errors generated by ServeContent are written immediately
	// to the response. This usually only happens if seeking fails (rare).
	http.ServeContent(w, r, d.Name(), d.ModTime(), f)

	return http.StatusOK, nil
}

// redirect is taken from http.localRedirect of the std lib. It
// sends an HTTP redirect to the client but will preserve the
// query string for the new path.
func redirect(w http.ResponseWriter, r *http.Request, newPath string) {
	if q := r.URL.RawQuery; q != "" {
		newPath += "?" + q
	}
	http.Redirect(w, r, newPath, http.StatusMovedPermanently)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
)

type GameState struct {
	Time        uint64                 `json:"time"`
	Ships       map[string]*Ship       `json:"ships"`
	Projectiles map[string]*Projectile `json:"projectiles"`
	Asteroids   map[string]*Asteroid   `json:"asteroids"`
}

func CreateGameState(t uint64) *GameState {
	return &GameState{
		Time:        t,
		Ships:       make(map[string]*Ship),
		Projectiles: make(map[string]*Projectile),
		Asteroids:   make(map[string]*Asteroid),
	}
}

func (s *GameState) Tick(t uint64) *GameState {
	if t < s.Time {
		log.Fatalf("Tried to call tick with timestamp lower than previous tick: %d, %d", s.Time, t)
		return nil
	}

	// TODO: If t == s.Time, do a clone of game objects and return, since no time will have elapsed?

	// create new state
	state := CreateGameState(t)

	for _, o := range s.Ships {
		p := o.Tick(t, s)
		if p != nil {
			state.Ships[p.Id] = p
		}
	}

	for _, o := range s.Projectiles {
		p := o.Tick(t, s)
		if p != nil {
			state.Projectiles[p.Id] = p
		}
	}

	for _, o := range s.Asteroids {
		p := o.Tick(t, s)
		if p != nil {
			state.Asteroids[p.Id] = p
		}
	}

	// TODO: Come up with a better way to look up collisions.
	// From https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection

	for _, s := range state.Ships {
		if !s.Alive {
			continue
		}

		// check for ship-ship collisions
		for _, os := range state.Ships {
			if !s.Alive || !os.Alive || s.Id == os.Id {
				continue
			}

			if IsColliding(s.Position, settings.constants.ShipRadius, os.Position, settings.constants.ShipRadius) {
				log.Println(fmt.Sprintf("Ship %v collided with Ship %v", s.Id, os.Id))
				s.Alive = false
				s.Died = t
				os.Alive = false
				os.Died = t
			}
		}

		if !s.Alive {
			continue
		}

		// check for ship-projectile collisions
		for _, p := range state.Projectiles {
			if !s.Alive || !p.Alive || s.Id == p.Owner {
				continue
			}

			if IsColliding(s.Position, settings.constants.ShipRadius, p.Position, settings.constants.ProjectileRadius) {
				log.Println(fmt.Sprintf("Ship %v collided with Projectile %v", s.Id, p.Id))
				s.Alive = false
				s.Died = t
				p.Alive = false
				p.Died = t
			}
		}

		if !s.Alive {
			continue
		}

		// check for ship-asteroid collisions
		for _, a := range state.Asteroids {
			if !s.Alive || !a.Alive {
				continue
			}

			if IsColliding(s.Position, settings.constants.ShipRadius, a.Position, a.Radius) {
				log.Println(fmt.Sprintf("Ship %v collided with Asteroid %v", s.Id, a.Id))
				s.Alive = false
				s.Died = t
			}
		}
	}

	return state
}
<commit_msg>Added detection of projectile/asteroid collisions.<commit_after>package main

import (
	"fmt"
	"log"
)

type GameState struct {
	Time        uint64                 `json:"time"`
	Ships       map[string]*Ship       `json:"ships"`
	Projectiles map[string]*Projectile `json:"projectiles"`
	Asteroids   map[string]*Asteroid   `json:"asteroids"`
}

func CreateGameState(t uint64) *GameState {
	return &GameState{
		Time:        t,
		Ships:       make(map[string]*Ship),
		Projectiles: make(map[string]*Projectile),
		Asteroids:   make(map[string]*Asteroid),
	}
}

func (s *GameState) Tick(t uint64) *GameState {
	if t < s.Time {
		log.Fatalf("Tried to call tick with timestamp lower than previous tick: %d, %d", s.Time, t)
		return nil
	}

	// TODO: If t == s.Time, do a clone of game objects and return, since no time will have elapsed?

	// create new state
	state := CreateGameState(t)

	for _, o := range s.Ships {
		p := o.Tick(t, s)
		if p != nil {
			state.Ships[p.Id] = p
		}
	}

	for _, o := range s.Projectiles {
		p := o.Tick(t, s)
		if p != nil {
			state.Projectiles[p.Id] = p
		}
	}

	for _, o := range s.Asteroids {
		p := o.Tick(t, s)
		if p != nil {
			state.Asteroids[p.Id] = p
		}
	}

	// TODO: Come up with a better way to look up collisions.
	// From https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection

	for _, s := range state.Ships {
		if !s.Alive {
			continue
		}

		// check for ship-ship collisions
		for _, os := range state.Ships {
			if !s.Alive || !os.Alive || s.Id == os.Id {
				continue
			}

			if IsColliding(s.Position, settings.constants.ShipRadius, os.Position, settings.constants.ShipRadius) {
				log.Println(fmt.Sprintf("Ship %v collided with Ship %v", s.Id, os.Id))
				s.Alive = false
				s.Died = t
				os.Alive = false
				os.Died = t
			}
		}

		if !s.Alive {
			continue
		}

		// check for ship-projectile collisions
		for _, p := range state.Projectiles {
			if !s.Alive || !p.Alive || s.Id == p.Owner {
				continue
			}

			if IsColliding(s.Position, settings.constants.ShipRadius, p.Position, settings.constants.ProjectileRadius) {
				log.Println(fmt.Sprintf("Ship %v collided with Projectile %v", s.Id, p.Id))
				s.Alive = false
				s.Died = t
				p.Alive = false
				p.Died = t
			}
		}

		if !s.Alive {
			continue
		}

		// check for ship-asteroid collisions
		for _, a := range state.Asteroids {
			if !s.Alive || !a.Alive {
				continue
			}

			if IsColliding(s.Position, settings.constants.ShipRadius, a.Position, a.Radius) {
				log.Println(fmt.Sprintf("Ship %v collided with Asteroid %v", s.Id, a.Id))
				s.Alive = false
				s.Died = t
			}
		}
	}

	for _, a := range state.Asteroids {
		if !a.Alive {
			continue
		}

		// check for asteroid-projectile collisions
		for _, p := range state.Projectiles {
			if !a.Alive || !p.Alive {
				continue
			}

			if IsColliding(a.Position, a.Radius, p.Position, settings.constants.ProjectileRadius) {
				log.Println(fmt.Sprintf("Asteroid %v collided with Projectile %v", a.Id, p.Id))
				// TODO: Asteroid should break apart
				p.Alive = false
				p.Died = t
			}
		}

		// TODO: Asteroids should bounce off of each other
		// check for asteroid-asteroid collisions
		// for _, oa := range state.Asteroids {
		// 	if !a.Alive || !oa.Alive || a.Id == oa.Id {
		// 		continue
		// 	}
		//
		// 	if IsColliding(a.Position, a.Radius, oa.Position, oa.Radius) {
		// 		log.Println(fmt.Sprintf("Asteroid %v collided with Asteroid %v", a.Id, oa.Id))
		// 	}
		// }
	}

	return state
}
<|endoftext|>


<commit_before>package matlab

import (
	"fmt"
	"os/exec"
	"path/filepath"

	"github.com/pkg/errors"
	"github.com/satori/go.uuid"

	"github.com/at15/mk-fld/server/util"
)

var log = util.Logger

type Job struct {
	JobOption
	JobID string
}

type JobOption struct {
	MFile     string
	InputFile string
	LogFile   string
}

func NewJob(opt JobOption) (*Job, error) {
	if opt.MFile != "" {
		opt.MFile, _ = filepath.Abs(opt.MFile)
	} else {
		return &Job{}, errors.New("m file must be set")
	}
	if opt.InputFile != "" {
		opt.InputFile, _ = filepath.Abs(opt.InputFile)
	} else {
		return &Job{}, errors.New("input file must be set")
	}
	if opt.LogFile != "" {
		opt.LogFile, _ = filepath.Abs(opt.LogFile)
	} else {
		return &Job{}, errors.New("log file must be set")
	}
	return &Job{
		JobOption: opt,
		JobID:     uuid.NewV4().String(),
	}, nil
}

func (j *Job) Run() {
	script := fmt.Sprintf("jobId='%s';inputFile='%s';logFile='%s';cd('%s');run('%s');exit;",
		j.JobID, j.InputFile, j.LogFile, filepath.Dir(j.MFile), j.MFile)
	log.Info(script)
	cmd := exec.Command("matlab", "-nosplash", "-nodesktop", "-nojvm", "-noFigureWindows", "-minimize",
		"-r", script)
	cmd.Run()
}
<commit_msg>[Server] MATLAB can also generate UUID<commit_after>package matlab

import (
	"fmt"
	"os/exec"
	"path/filepath"

	"github.com/pkg/errors"
	"github.com/satori/go.uuid"

	"github.com/at15/mk-fld/server/util"
)

var log = util.Logger

type Job struct {
	JobOption
	JobID string
}

type JobOption struct {
	MFile     string
	InputFile string
	LogFile   string
}

func NewJob(opt JobOption) (*Job, error) {
	if opt.MFile != "" {
		opt.MFile, _ = filepath.Abs(opt.MFile)
	} else {
		return &Job{}, errors.New("m file must be set")
	}
	if opt.InputFile != "" {
		opt.InputFile, _ = filepath.Abs(opt.InputFile)
	} else {
		return &Job{}, errors.New("input file must be set")
	}
	if opt.LogFile != "" {
		opt.LogFile, _ = filepath.Abs(opt.LogFile)
	} else {
		return &Job{}, errors.New("log file must be set")
	}

	// NOTE: uuid = char(java.util.UUID.randomUUID); can be used in matlab to generate uuid as well
	return &Job{
		JobOption: opt,
		JobID:     uuid.NewV4().String(),
	}, nil
}

func (j *Job) Run() {
	script := fmt.Sprintf("jobId='%s';inputFile='%s';logFile='%s';cd('%s');run('%s');exit;",
		j.JobID, j.InputFile, j.LogFile, filepath.Dir(j.MFile), j.MFile)
	log.Info(script)
	cmd := exec.Command("matlab", "-nosplash", "-nodesktop", "-nojvm", "-noFigureWindows", "-minimize",
		"-r", script)
	cmd.Run()
}
<|endoftext|>


<commit_before>package service

import (
	"fmt"
	"io/ioutil"
	"os"
	"runtime"
	"strings"

	"github.com/juju/errors"

	"github.com/juju/juju/service/common"
	"github.com/juju/juju/version"
)

var jujuVersion = version.Current

// DiscoverService returns an interface to a service apropriate
// for the current system
func DiscoverService(name string, conf common.Conf) (Service, error) {
	initName, err := discoverLocalInitSystem()
	if errors.IsNotFound(err) {
		// Fall back to checking the juju version.
		versionInitName, ok := VersionInitSystem(jujuVersion)
		if !ok {
			return nil, errors.Annotate(err, "nor on local host")
		}
		initName = versionInitName
	}
	if err != nil {
		return nil, errors.Trace(err)
	}

	service, err := NewService(name, conf, initName)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return service, nil
}

// VersionInitSystem returns an init system name based on the provided
// version info. If one cannot be identified then false if returned
// for the second return value.
func VersionInitSystem(vers version.Binary) (string, bool) {
	switch vers.OS {
	case version.Windows:
		return InitSystemWindows, true
	case version.Ubuntu:
		switch vers.Series {
		case "precise", "quantal", "raring", "saucy", "trusty", "utopic":
			return InitSystemUpstart, true
		case "":
			return "", false
		default:
			// Check for pre-precise releases.
			os, _ := version.GetOSFromSeries(vers.Series)
			if os == version.Unknown {
				return "", false
			}
			// vivid and later
			return InitSystemSystemd, true
		}
		// TODO(ericsnow) Support other OSes, like version.CentOS.
	default:
		return "", false
	}
}

const pid1 = "/proc/1/cmdline"

type initSystem struct {
	executable string
	name       string
}

var linuxExecutables = []initSystem{
	// Note that some systems link /sbin/init to whatever init system
	// is supported, so in the future we may need some other way to
	// identify upstart uniquely.
	{"/sbin/init", InitSystemUpstart},
	{"/sbin/upstart", InitSystemUpstart},
	{"/sbin/systemd", InitSystemSystemd},
	{"/bin/systemd", InitSystemSystemd},
	{"/lib/systemd/systemd", InitSystemSystemd},
}

func identifyInitSystem(executable string) (string, bool) {
	for _, initSystem := range linuxExecutables {
		if executable == initSystem.executable {
			return initSystem.name, true
		}
	}
	return "", false
}

var runtimeOS = runtime.GOOS
var pid1File = pid1

func discoverLocalInitSystem() (string, error) {
	if runtimeOS == "windows" {
		return InitSystemWindows, nil
	}

	data, err := ioutil.ReadFile(pid1File)
	if os.IsNotExist(err) {
		return "", errors.NotFoundf("init system")
	}
	if err != nil {
		return "", errors.Trace(err)
	}
	out := strings.Trim(strings.TrimSpace(string(data)), "\x00")
	executable := strings.Fields(out)[0]

	initName, ok := identifyInitSystem(executable)
	if !ok {
		return "", errors.NotFoundf("init system (based on %q)", executable)
	}
	logger.Debugf("discovered init system %q from executable %q", initName, executable)
	return initName, nil
}

// TODO(ericsnow) Is it too much to cat once for each executable?
const initSystemTest = `[[ "$(cat ` + pid1 + ` | awk '{print $1}')" == "%s" ]]`

// newShellSelectCommand creates a bash if statement with an if
// (or elif) clause for each of the executables in linuxExecutables.
// The body of each clause comes from calling the provided handler with
// the init system name. If the handler does not support the args then
// it returns a false "ok" value.
func newShellSelectCommand(handler func(string) (string, bool)) string {
	// TODO(ericsnow) Allow passing in "initSystems ...string".
	executables := linuxExecutables

	// TODO(ericsnow) build the command in a better way?

	cmdAll := ""
	for _, initSystem := range executables {
		cmd, ok := handler(initSystem.name)
		if !ok {
			continue
		}

		test := fmt.Sprintf(initSystemTest, initSystem.executable)
		cmd = fmt.Sprintf("if %s; then %s\n", test, cmd)
		if cmdAll != "" {
			cmd = "el" + cmd
		}
		cmdAll += cmd
	}
	if cmdAll != "" {
		cmdAll += "" +
			"else exit 1\n" +
			"fi"
	}
	return cmdAll
}
<commit_msg>Add a missing else.<commit_after>package service

import (
	"fmt"
	"io/ioutil"
	"os"
	"runtime"
	"strings"

	"github.com/juju/errors"

	"github.com/juju/juju/service/common"
	"github.com/juju/juju/version"
)

var jujuVersion = version.Current

// DiscoverService returns an interface to a service apropriate
// for the current system
func DiscoverService(name string, conf common.Conf) (Service, error) {
	initName, err := discoverLocalInitSystem()
	if errors.IsNotFound(err) {
		// Fall back to checking the juju version.
		versionInitName, ok := VersionInitSystem(jujuVersion)
		if !ok {
			return nil, errors.Annotate(err, "nor on local host")
		}
		initName = versionInitName
	} else if err != nil {
		return nil, errors.Trace(err)
	}

	service, err := NewService(name, conf, initName)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return service, nil
}

// VersionInitSystem returns an init system name based on the provided
// version info. If one cannot be identified then false if returned
// for the second return value.
func VersionInitSystem(vers version.Binary) (string, bool) {
	switch vers.OS {
	case version.Windows:
		return InitSystemWindows, true
	case version.Ubuntu:
		switch vers.Series {
		case "precise", "quantal", "raring", "saucy", "trusty", "utopic":
			return InitSystemUpstart, true
		case "":
			return "", false
		default:
			// Check for pre-precise releases.
			os, _ := version.GetOSFromSeries(vers.Series)
			if os == version.Unknown {
				return "", false
			}
			// vivid and later
			return InitSystemSystemd, true
		}
		// TODO(ericsnow) Support other OSes, like version.CentOS.
	default:
		return "", false
	}
}

const pid1 = "/proc/1/cmdline"

type initSystem struct {
	executable string
	name       string
}

var linuxExecutables = []initSystem{
	// Note that some systems link /sbin/init to whatever init system
	// is supported, so in the future we may need some other way to
	// identify upstart uniquely.
	{"/sbin/init", InitSystemUpstart},
	{"/sbin/upstart", InitSystemUpstart},
	{"/sbin/systemd", InitSystemSystemd},
	{"/bin/systemd", InitSystemSystemd},
	{"/lib/systemd/systemd", InitSystemSystemd},
}

func identifyInitSystem(executable string) (string, bool) {
	for _, initSystem := range linuxExecutables {
		if executable == initSystem.executable {
			return initSystem.name, true
		}
	}
	return "", false
}

var runtimeOS = runtime.GOOS
var pid1File = pid1

func discoverLocalInitSystem() (string, error) {
	if runtimeOS == "windows" {
		return InitSystemWindows, nil
	}

	data, err := ioutil.ReadFile(pid1File)
	if os.IsNotExist(err) {
		return "", errors.NotFoundf("init system")
	}
	if err != nil {
		return "", errors.Trace(err)
	}
	out := strings.Trim(strings.TrimSpace(string(data)), "\x00")
	executable := strings.Fields(out)[0]

	initName, ok := identifyInitSystem(executable)
	if !ok {
		return "", errors.NotFoundf("init system (based on %q)", executable)
	}
	logger.Debugf("discovered init system %q from executable %q", initName, executable)
	return initName, nil
}

// TODO(ericsnow) Is it too much to cat once for each executable?
const initSystemTest = `[[ "$(cat ` + pid1 + ` | awk '{print $1}')" == "%s" ]]`

// newShellSelectCommand creates a bash if statement with an if
// (or elif) clause for each of the executables in linuxExecutables.
// The body of each clause comes from calling the provided handler with
// the init system name. If the handler does not support the args then
// it returns a false "ok" value.
func newShellSelectCommand(handler func(string) (string, bool)) string {
	// TODO(ericsnow) Allow passing in "initSystems ...string".
	executables := linuxExecutables

	// TODO(ericsnow) build the command in a better way?

	cmdAll := ""
	for _, initSystem := range executables {
		cmd, ok := handler(initSystem.name)
		if !ok {
			continue
		}

		test := fmt.Sprintf(initSystemTest, initSystem.executable)
		cmd = fmt.Sprintf("if %s; then %s\n", test, cmd)
		if cmdAll != "" {
			cmd = "el" + cmd
		}
		cmdAll += cmd
	}
	if cmdAll != "" {
		cmdAll += "" +
			"else exit 1\n" +
			"fi"
	}
	return cmdAll
}
<|endoftext|>