<commit_before>package main

import (
	"bytes"
	"exec"
	"flag"
	"fmt"
	"html"
	"http"
	"io"
	"json"
	"log"
	"os"
	"path/filepath"
	"strings"
)

var packages = []string{
	"bash",
	"grep",
	"kernel",
	"curl",
	"libcurl",
	"rtorrent",
	"libX11",
	"failthis",
}

const (
	watershed = "http://api.oswatershed.org/api/0.1/package.json?package=%s&cb=go"
	debian    = "http://packages.debian.org/%s/%s"
	drelease  = "wheezy"
)

const (
	ARCHLINUX = iota
)

var (
	isHome     = flag.Bool("home", false, "open package homepage in browser")
	isBroken   = flag.Bool("b", false, "print out broken upstream versions")
	isCheck    = flag.Bool("c", false, "check upstream version against our versions")
	isSync     = flag.Bool("s", false, "sync oswatershed and srpkgs cache")
	isLongDesc = flag.Bool("ld", false, "get long description from debian packages")
	srcPath    = flag.String("path", "/home/strings/github/vanilla/srcpkgs/", "path to srcpkgs")
	browser    = flag.String("browser", "chromium", "broswer to use")
)

type Distro struct {
	Version string
}

type Package struct {
	Name    string "package"
	Latest  string
	Vanilla string
	Distros []Distro
	Check   bool
}

func init() {
	log.SetPrefix("")
	log.SetFlags(log.Lshortfile)
}

func main() {
	flag.Parse()
	if *isHome {
		pack := flag.Arg(0)
		err := home(pack)
		if err != nil {
			log.Print(err)
		}
		return
	}
	if *isSync {
		err := sync()
		if err != nil {
			log.Print(err)
		}
		return
	}
	if *isBroken {
		err := broken()
		if err != nil {
			fmt.Println(err)
		}
		return
	}
	if *isCheck {
		err := check()
		if err != nil {
			fmt.Println(err)
		}
		return
	}
	if *isLongDesc {
		err := longDesc(flag.Arg(0))
		if err != nil {
			fmt.Println(err)
		}
		return
	}
	if len(flag.Args()) != 1 {
		flag.Usage()
	}
	pack, err := latest(flag.Arg(0))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(pack.Latest)
}

func home(pack string) os.Error {
	template := filepath.Join(*srcPath, pack, "template")
	home, err := getVar(template, "homepage")
	if err != nil {
		return err
	}
	fmt.Println("opening", home)
	err = exec.Command(*browser, home).Run()
	if err != nil {
		return err
	}
	return nil
}

func broken() os.Error {
	cache, err := loadCache()
	if err != nil {
		return err
	}
	for _, p := range *cache {
		if !p.Check {
			fmt.Printf("%v\n", p.Name)
		}
	}
	return nil

}

func check() os.Error {
	cache, err := loadCache()
	if err != nil {
		return err
	}
	fmt.Printf("%-20.20s %-20.20s %-20.20s %-20.20s\n", "name", "vanilla", "upstream", "archlinux")
	for _, p := range *cache {
		if p.Latest != p.Vanilla && p.Check {
			fmt.Printf("%-20.20s %-20.20s %-20.20s %-20.20s\n", p.Name, p.Vanilla, p.Latest, p.Distros[ARCHLINUX].Version)
		}
	}
	fmt.Printf("%-20.20s %-20.20s %-20.20s %-20.20s\n", "name", "vanilla", "upstream", "archlinux")
	return nil
}

func sync() os.Error {
	cache := map[string]*Package{}
	templates, err := filepath.Glob(*srcPath + "/*/template")
	if err != nil {
		log.Fatal(err)
	}
	for i, template := range templates {
		_, err := os.Stat(template)
		if err != nil {
			return err
		}
		dir, _ := filepath.Split(template)
		pname := filepath.Base(dir)
		ver, err := getVar(template, "version")
		if err != nil {
			return err
		}
		pack, err := latest(pname)
		if err != nil {
			p := new(Package)
			p.Name = pname
			p.Check = false
			p.Vanilla = ver
			fmt.Printf("%04.0v %-20.20s %s\n", i, pname, "error")
			cache[pname] = p
			continue
		}
		pack.Vanilla = ver
		pack.Check = true
		cache[pname] = pack
		fmt.Printf("%04.0v %-20.20s %-10.10s\n", i, pname, pack.Latest)
	}
	f, err := os.Create(*srcPath + "/upstream.json")
	if err != nil {
		return err
	}
	defer f.Close()
	b, err := json.Marshal(cache)
	if err != nil {
		return err
	}
	buf := new(bytes.Buffer)
	err = json.Indent(buf, b, "", "\t")
	if err != nil {
		return err
	}
	_, err = io.Copy(f, buf)
	if err != nil {
		return err
	}
	return nil
}

func loadCache() (*map[string]*Package, os.Error) {
	cache := &map[string]*Package{}
	fd, err := os.Open(*srcPath + "upstream.json")
	if err != nil {
		return nil, err
	}
	defer fd.Close()
	err = json.NewDecoder(fd).Decode(cache)
	if err != nil {
		return nil, err
	}
	return cache, nil
}

func getVar(template string, shvar string) (string, os.Error) {
	os.Setenv("XBPS_SRCPKGDIR", *srcPath)
	fd, err := os.Open(template)
	if err != nil {
		return "", err
	}
	defer fd.Close()
	buf := new(bytes.Buffer)
	buf.WriteString("Add_dependency(){ :\n }\n")
	io.Copy(buf, fd)
	buf.WriteString("echo $" + shvar)
	cmd := exec.Command("sh")
	cmd.Stdin = buf
	output, err := cmd.CombinedOutput()
	if err != nil {
		println(template)
		log.Println(err, string(output))
		return "", err
	}
	svar := strings.Replace(string(output), "\n", "", -1)
	if svar == "" {
		return "", fmt.Errorf("%s not found in %s", shvar, template)
	}
	return svar, err
}

func longDesc(name string) os.Error {
	client := new(http.Client)
	url := fmt.Sprintf(debian, drelease, name)
	res, err := client.Do(request(url))
	if err != nil {
		log.Fatal(err)
		return err
	}
	if res.StatusCode != 200 {
		return fmt.Errorf("Http GET error %s", res.Status)
	}
	buf := new(bytes.Buffer)
	_, err = io.Copy(buf, res.Body)
	if err != nil {
		return err
	}
	doc, err := html.Parse(buf)
	if err != nil {
		return err
	}
	//TODO: move this to a proper function
	var f func(*html.Node)
	f = func(n *html.Node) {
		if n.Type == html.ElementNode && n.Data == "div" {
			if len(n.Attr) > 0 {
				if n.Attr[0].Val == "pdesc" {
					fmt.Printf("%s\n\n", n.Child[1].Child[0].Data)
					fmt.Printf("*long desc*\n%s", n.Child[1].Child[2].Child[0].Data)
				}
			}
		}
		for _, c := range n.Child {
			f(c)
		}
	}
	f(doc)
	return nil
}

func latest(name string) (*Package, os.Error) {
	client := new(http.Client)
	url := fmt.Sprintf(watershed, name)
	res, err := client.Do(request(url))
	if err != nil {
		log.Fatal(err)
		return nil, err
	}
	if res.StatusCode != 200 {
		return nil, fmt.Errorf("Http GET error %s", res.Status)
	}
	buf := new(bytes.Buffer)
	io.Copy(buf, res.Body)
	p := new(Package)
	b := buf.Bytes()
	err = json.Unmarshal(b[3:len(b)-1], p)
	if err != nil {
		fmt.Println(err)
		return p, err
	}
	return p, nil
}

func request(url string) *http.Request {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		log.Fatal(err)
		return nil
	}
	req.ProtoMajor = 1
	req.ProtoMinor = 1
	req.TransferEncoding = []string{"chunked"}
	//FIXME: Debian doesnt always return compressed
	//req.Header.Set("Accept-Encoding", "gzip,deflate")
	req.Header.Set("Connection", "keep-alive")
	return req
}
<commit_msg>if there is no -home target print out usage.<commit_after>package main

import (
	"bytes"
	"exec"
	"flag"
	"fmt"
	"html"
	"http"
	"io"
	"json"
	"log"
	"os"
	"path/filepath"
	"strings"
)

const (
	watershed = "http://api.oswatershed.org/api/0.1/package.json?package=%s&cb=go"
	debian    = "http://packages.debian.org/%s/%s"
	drelease  = "wheezy"
)

const (
	ARCHLINUX = iota
)

var (
	isHome     = flag.Bool("home", false, "open package homepage in browser")
	isBroken   = flag.Bool("b", false, "print out broken upstream versions")
	isCheck    = flag.Bool("c", false, "check upstream version against our versions")
	isSync     = flag.Bool("s", false, "sync oswatershed and srpkgs cache")
	isLongDesc = flag.Bool("ld", false, "get long description from debian packages")
	srcPath    = flag.String("path", "/home/strings/github/vanilla/srcpkgs/", "path to srcpkgs")
	browser    = flag.String("browser", "chromium", "broswer to use")
)

type Distro struct {
	Version string
}

type Package struct {
	Name    string "package"
	Latest  string
	Vanilla string
	Distros []Distro
	Check   bool
}

func init() {
	log.SetPrefix("")
	log.SetFlags(log.Lshortfile)
}

func main() {
	flag.Parse()
	if *isHome {
		pack := flag.Arg(0)
		if pack == "" {
			flag.Usage()
			return
		}
		err := home(pack)
		if err != nil {
			log.Print(err)
		}
		return
	}
	if *isSync {
		err := sync()
		if err != nil {
			log.Print(err)
		}
		return
	}
	if *isBroken {
		err := broken()
		if err != nil {
			fmt.Println(err)
		}
		return
	}
	if *isCheck {
		err := check()
		if err != nil {
			fmt.Println(err)
		}
		return
	}
	if *isLongDesc {
		err := longDesc(flag.Arg(0))
		if err != nil {
			fmt.Println(err)
		}
		return
	}
	if len(flag.Args()) != 1 {
		flag.Usage()
	}
	pack, err := latest(flag.Arg(0))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(pack.Latest)
}

func home(pack string) os.Error {
	template := filepath.Join(*srcPath, pack, "template")
	home, err := getVar(template, "homepage")
	if err != nil {
		return err
	}
	fmt.Println("opening", home)
	err = exec.Command(*browser, home).Run()
	if err != nil {
		return err
	}
	return nil
}

func broken() os.Error {
	cache, err := loadCache()
	if err != nil {
		return err
	}
	for _, p := range *cache {
		if !p.Check {
			fmt.Printf("%v\n", p.Name)
		}
	}
	return nil

}

func check() os.Error {
	cache, err := loadCache()
	if err != nil {
		return err
	}
	fmt.Printf("%-20.20s %-20.20s %-20.20s %-20.20s\n", "name", "vanilla", "upstream", "archlinux")
	for _, p := range *cache {
		if p.Latest != p.Vanilla && p.Check {
			fmt.Printf("%-20.20s %-20.20s %-20.20s %-20.20s\n", p.Name, p.Vanilla, p.Latest, p.Distros[ARCHLINUX].Version)
		}
	}
	fmt.Printf("%-20.20s %-20.20s %-20.20s %-20.20s\n", "name", "vanilla", "upstream", "archlinux")
	return nil
}

func sync() os.Error {
	cache := map[string]*Package{}
	templates, err := filepath.Glob(*srcPath + "/*/template")
	if err != nil {
		log.Fatal(err)
	}
	for i, template := range templates {
		_, err := os.Stat(template)
		if err != nil {
			return err
		}
		dir, _ := filepath.Split(template)
		pname := filepath.Base(dir)
		ver, err := getVar(template, "version")
		if err != nil {
			return err
		}
		pack, err := latest(pname)
		if err != nil {
			p := new(Package)
			p.Name = pname
			p.Check = false
			p.Vanilla = ver
			fmt.Printf("%04.0v %-20.20s %s\n", i, pname, "error")
			cache[pname] = p
			continue
		}
		pack.Vanilla = ver
		pack.Check = true
		cache[pname] = pack
		fmt.Printf("%04.0v %-20.20s %-10.10s\n", i, pname, pack.Latest)
	}
	f, err := os.Create(*srcPath + "/upstream.json")
	if err != nil {
		return err
	}
	defer f.Close()
	b, err := json.Marshal(cache)
	if err != nil {
		return err
	}
	buf := new(bytes.Buffer)
	err = json.Indent(buf, b, "", "\t")
	if err != nil {
		return err
	}
	_, err = io.Copy(f, buf)
	if err != nil {
		return err
	}
	return nil
}

func loadCache() (*map[string]*Package, os.Error) {
	cache := &map[string]*Package{}
	fd, err := os.Open(*srcPath + "upstream.json")
	if err != nil {
		return nil, err
	}
	defer fd.Close()
	err = json.NewDecoder(fd).Decode(cache)
	if err != nil {
		return nil, err
	}
	return cache, nil
}

func getVar(template string, shvar string) (string, os.Error) {
	os.Setenv("XBPS_SRCPKGDIR", *srcPath)
	fd, err := os.Open(template)
	if err != nil {
		return "", err
	}
	defer fd.Close()
	buf := new(bytes.Buffer)
	buf.WriteString("Add_dependency(){ :\n }\n")
	io.Copy(buf, fd)
	buf.WriteString("echo $" + shvar)
	cmd := exec.Command("sh")
	cmd.Stdin = buf
	output, err := cmd.CombinedOutput()
	if err != nil {
		println(template)
		log.Println(err, string(output))
		return "", err
	}
	svar := strings.Replace(string(output), "\n", "", -1)
	if svar == "" {
		return "", fmt.Errorf("%s not found in %s", shvar, template)
	}
	return svar, err
}

func longDesc(name string) os.Error {
	client := new(http.Client)
	url := fmt.Sprintf(debian, drelease, name)
	res, err := client.Do(request(url))
	if err != nil {
		log.Fatal(err)
		return err
	}
	if res.StatusCode != 200 {
		return fmt.Errorf("Http GET error %s", res.Status)
	}
	buf := new(bytes.Buffer)
	_, err = io.Copy(buf, res.Body)
	if err != nil {
		return err
	}
	doc, err := html.Parse(buf)
	if err != nil {
		return err
	}
	//TODO: move this to a proper function
	var f func(*html.Node)
	f = func(n *html.Node) {
		if n.Type == html.ElementNode && n.Data == "div" {
			if len(n.Attr) > 0 {
				if n.Attr[0].Val == "pdesc" {
					fmt.Printf("%s\n\n", n.Child[1].Child[0].Data)
					fmt.Printf("*long desc*\n%s", n.Child[1].Child[2].Child[0].Data)
				}
			}
		}
		for _, c := range n.Child {
			f(c)
		}
	}
	f(doc)
	return nil
}

func latest(name string) (*Package, os.Error) {
	client := new(http.Client)
	url := fmt.Sprintf(watershed, name)
	res, err := client.Do(request(url))
	if err != nil {
		log.Fatal(err)
		return nil, err
	}
	if res.StatusCode != 200 {
		return nil, fmt.Errorf("Http GET error %s", res.Status)
	}
	buf := new(bytes.Buffer)
	io.Copy(buf, res.Body)
	p := new(Package)
	b := buf.Bytes()
	err = json.Unmarshal(b[3:len(b)-1], p)
	if err != nil {
		fmt.Println(err)
		return p, err
	}
	return p, nil
}

func request(url string) *http.Request {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		log.Fatal(err)
		return nil
	}
	req.ProtoMajor = 1
	req.ProtoMinor = 1
	req.TransferEncoding = []string{"chunked"}
	//FIXME: Debian doesnt always return compressed
	//req.Header.Set("Accept-Encoding", "gzip,deflate")
	req.Header.Set("Connection", "keep-alive")
	return req
}
<|endoftext|>


<commit_before>package cfutil

import (
	"errors"
	"fmt"
	consul "github.com/hashicorp/consul/api"
	"net/url"
	"os"
	"strconv"
	"strings"
)

// Services() returns the list of services available from the
// Consul cluster
func Services() ([]string, error) {
	client, err := NewConsulClient()
	if err != nil {
		return nil, err
	}
	catalogServices, _, err := client.Catalog().Services(nil)
	if err != nil {
		return []string{}, err
	}
	var services []string
	for k := range catalogServices {
		services = append(services, k)
	}
	return services, nil
}

func DiscoverServiceURL(serviceName, tags string) (string, error) {
	client, err := NewConsulClient()
	if err != nil {
		return "", err
	}
	services, _, err := client.Catalog().Service(serviceName, tags, nil)
	if err != nil {
		return "", fmt.Errorf("Service `%s` not found: %s", serviceName, err)
	}
	if len(services) > 0 {
		return CreateURLFromServiceCatalog(services[0])
	}
	return "", fmt.Errorf("Service `%s` not found", serviceName)

}

func CreateURLFromServiceCatalog(catalog *consul.CatalogService) (string, error) {
	var serviceURL url.URL
	if catalog.ServicePort == 443 {
		serviceURL.Scheme = "https"
		serviceURL.Host = catalog.ServiceAddress
	} else {
		serviceURL.Scheme = "http"
		serviceURL.Host = fmt.Sprintf("%s:%d", catalog.ServiceAddress, catalog.ServicePort)
	}
	return serviceURL.String(), nil
}

// Use ServiceRegister() to register your app in the Consul cluster
// Optionally you can provide a health endpoint on your URL and
// a number of tags to make your service more discoverable
func ServiceRegister(name string, path string, tags ...string) error {
	appEnv, _ := Current()
	client, err := NewConsulClient()
	if err != nil {
		return err
	}
	schema, port := schemaAndPortForServices()

	appURL, _ := url.Parse(schema + "://" + appEnv.ApplicationURIs[0])
	splitted := strings.Split(appURL.Host, ":")
	hostWithoutPort := splitted[0]
	if hostWithoutPort == "" {
		hostWithoutPort = "localhost"
	}
	if len(splitted) > 1 {
		addedPort, err := strconv.Atoi(splitted[1])
		if err == nil && addedPort != port {
			port = addedPort
		}
	}

	err = client.Agent().ServiceRegister(&consul.AgentServiceRegistration{
		Name:    name,
		Address: hostWithoutPort,
		Port:    port,
		Tags:    tags,
		Check: &consul.AgentServiceCheck{
			HTTP:     fmt.Sprintf(schema + "://" + appURL.Host + path),
			Interval: "60s",
		},
	})
	if err != nil {
		return err
	}
	return nil
}

// NewConsulClient() returns a new consul client which you can use to
// access the Consul cluster HTTP API. It uses `CONSUL_MASTER` and
// `CONSUL_TOKEN` environment variables to set up the HTTP API connection.
func NewConsulClient() (*consul.Client, error) {
	dialScheme, dialHost, err := consulDialstring("consul")
	if err != nil {
		return nil, err
	}
	client, consulErr := consul.NewClient(&consul.Config{
		Address: dialHost,
		Scheme:  dialScheme,
		Token:   os.Getenv("CONSUL_TOKEN"),
	})
	if consulErr != nil {
		return nil, consulErr
	}
	return client, nil
}

func GetConsulKey(mooncoreKey string) (string, error) {
	ns := ConsulNamespace()
	key := "mooncore/" + ns + "/" + mooncoreKey
	client, err := NewConsulClient()
	if err != nil {
		return "", err
	}
	kvPair, _, err := client.KV().Get(key, nil)
	if err != nil {
		return "", err
	}
	if kvPair == nil || kvPair.Value == nil {
		return "", fmt.Errorf("Key not found: %s", mooncoreKey)
	}
	return string(kvPair.Value), nil
}

func ConsulDatacenter() (string, error) {
	client, err := NewConsulClient()
	if err != nil {
		return "", err
	}
	self, err := client.Agent().Self()
	if err != nil {
		return "", err
	}
	dc, ok := self["Config"]["Datacenter"].(string)
	if !ok {
		return "", fmt.Errorf("Invalid lookup for Datacenter")
	}
	return dc, nil
}

func ConsulNamespace() string {
	return os.Getenv("CONSUL_NAMESPACE")
}

func consulDialstring(serviceName string) (string, string, error) {
	consulMaster := ""
	if consulMaster = os.Getenv("CONSUL_MASTER"); consulMaster != "" {
		parsed, err := url.Parse(consulMaster)
		if err == nil {
			return parsed.Scheme, parsed.Host, nil
		}
	}
	return "", "", errors.New("CONSUL_MASTER not found or invalid url")
}

func schemaAndPortForServices() (string, int) {
	if ForceHTTP() {
		return "http", 80
	}
	return "https", 443
}
<commit_msg>Print error message<commit_after>package cfutil

import (
	"errors"
	"fmt"
	consul "github.com/hashicorp/consul/api"
	"net/url"
	"os"
	"strconv"
	"strings"
)

// Services() returns the list of services available from the
// Consul cluster
func Services() ([]string, error) {
	client, err := NewConsulClient()
	if err != nil {
		return nil, err
	}
	catalogServices, _, err := client.Catalog().Services(nil)
	if err != nil {
		return []string{}, err
	}
	var services []string
	for k := range catalogServices {
		services = append(services, k)
	}
	return services, nil
}

func DiscoverServiceURL(serviceName, tags string) (string, error) {
	client, err := NewConsulClient()
	if err != nil {
		return "", err
	}
	services, _, err := client.Catalog().Service(serviceName, tags, nil)
	if err != nil {
		return "", fmt.Errorf("Service `%s` not found: %s", serviceName, err)
	}
	if len(services) > 0 {
		return CreateURLFromServiceCatalog(services[0])
	}
	return "", fmt.Errorf("Service `%s` not found", serviceName)

}

func CreateURLFromServiceCatalog(catalog *consul.CatalogService) (string, error) {
	var serviceURL url.URL
	if catalog.ServicePort == 443 {
		serviceURL.Scheme = "https"
		serviceURL.Host = catalog.ServiceAddress
	} else {
		serviceURL.Scheme = "http"
		serviceURL.Host = fmt.Sprintf("%s:%d", catalog.ServiceAddress, catalog.ServicePort)
	}
	return serviceURL.String(), nil
}

// Use ServiceRegister() to register your app in the Consul cluster
// Optionally you can provide a health endpoint on your URL and
// a number of tags to make your service more discoverable
func ServiceRegister(name string, path string, tags ...string) error {
	appEnv, _ := Current()
	client, err := NewConsulClient()
	if err != nil {
		return err
	}
	schema, port := schemaAndPortForServices()

	appURL, _ := url.Parse(schema + "://" + appEnv.ApplicationURIs[0])
	splitted := strings.Split(appURL.Host, ":")
	hostWithoutPort := splitted[0]
	if hostWithoutPort == "" {
		hostWithoutPort = "localhost"
	}
	if len(splitted) > 1 {
		addedPort, err := strconv.Atoi(splitted[1])
		if err == nil && addedPort != port {
			port = addedPort
		}
	}

	err = client.Agent().ServiceRegister(&consul.AgentServiceRegistration{
		Name:    name,
		Address: hostWithoutPort,
		Port:    port,
		Tags:    tags,
		Check: &consul.AgentServiceCheck{
			HTTP:     fmt.Sprintf(schema + "://" + appURL.Host + path),
			Interval: "60s",
		},
	})
	if err != nil {
		return err
	}
	return nil
}

// NewConsulClient() returns a new consul client which you can use to
// access the Consul cluster HTTP API. It uses `CONSUL_MASTER` and
// `CONSUL_TOKEN` environment variables to set up the HTTP API connection.
func NewConsulClient() (*consul.Client, error) {
	dialScheme, dialHost, err := consulDialstring("consul")
	if err != nil {
		return nil, err
	}
	client, consulErr := consul.NewClient(&consul.Config{
		Address: dialHost,
		Scheme:  dialScheme,
		Token:   os.Getenv("CONSUL_TOKEN"),
	})
	if consulErr != nil {
		return nil, consulErr
	}
	return client, nil
}

func GetConsulKey(mooncoreKey string) (string, error) {
	ns := ConsulNamespace()
	key := "mooncore/" + ns + "/" + mooncoreKey
	client, err := NewConsulClient()
	if err != nil {
		return "", err
	}
	kvPair, _, err := client.KV().Get(key, nil)
	if err != nil {
		return "", err
	}
	if kvPair == nil || kvPair.Value == nil {
		return "", fmt.Errorf("Key not found: %s", mooncoreKey)
	}
	return string(kvPair.Value), nil
}

func ConsulDatacenter() (string, error) {
	client, err := NewConsulClient()
	if err != nil {
		return "", err
	}
	self, err := client.Agent().Self()
	if err != nil {
		return "", err
	}
	dc, ok := self["Config"]["Datacenter"].(string)
	if !ok {
		return "", fmt.Errorf("Invalid lookup for Datacenter")
	}
	return dc, nil
}

func ConsulNamespace() string {
	return os.Getenv("CONSUL_NAMESPACE")
}

func consulDialstring(serviceName string) (string, string, error) {
	consulMaster := ""
	if consulMaster = os.Getenv("CONSUL_MASTER"); consulMaster != "" {
		parsed, err := url.Parse(consulMaster)
		if err == nil {
			return parsed.Scheme, parsed.Host, nil
		}
	}
	return "", "", fmt.Errorf("CONSUL_MASTER not found or invalid url: %s", consulMaster)
}

func schemaAndPortForServices() (string, int) {
	if ForceHTTP() {
		return "http", 80
	}
	return "https", 443
}
<|endoftext|>


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

package docker

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/dotcloud/docker"
	dclient "github.com/fsouza/go-dockerclient"
	"github.com/globocom/config"
	"github.com/globocom/docker-cluster/cluster"
	"github.com/globocom/docker-cluster/storage"
	"github.com/globocom/tsuru/action"
	"github.com/globocom/tsuru/fs"
	"github.com/globocom/tsuru/log"
	"github.com/globocom/tsuru/provision"
	"io"
	"labix.org/v2/mgo/bson"
	"strings"
	"sync"
)

var (
	dCluster *cluster.Cluster
	cmutext  sync.Mutex
	fsystem  fs.Fs
)

const pushTries = 5

func dockerCluster() *cluster.Cluster {
	cmutext.Lock()
	defer cmutext.Unlock()
	if dCluster == nil {
		servers, _ := config.GetList("docker:servers")
		if len(servers) < 1 {
			log.Fatal(`Tsuru is misconfigured. Setting "docker:servers" is mandatory`)
		}
		nodes := []cluster.Node{}
		for index, server := range servers {
			node := cluster.Node{
				ID:      fmt.Sprintf("server%d", index),
				Address: server,
			}
			nodes = append(nodes, node)
		}
		if segregate, _ := config.GetBool("docker:segregate"); segregate {
			var scheduler segregatedScheduler
			dCluster, _ = cluster.New(&scheduler, nodes...)
		} else {
			dCluster, _ = cluster.New(nil, nodes...)
		}
		if redisServer, err := config.GetString("docker:scheduler:redis-server"); err == nil {
			if password, err := config.GetString("docker:scheduler:redis-password"); err == nil {
				dCluster.SetStorage(storage.AuthenticatedRedis(redisServer, password))
			} else {
				dCluster.SetStorage(storage.Redis(redisServer))
			}
		}
	}
	return dCluster
}

func filesystem() fs.Fs {
	if fsystem == nil {
		fsystem = fs.OsFs{}
	}
	return fsystem
}

// runCmd executes commands and log the given stdout and stderror.
func runCmd(cmd string, args ...string) (string, error) {
	out := bytes.Buffer{}
	err := executor().Execute(cmd, args, nil, &out, &out)
	log.Printf("running the cmd: %s with the args: %s", cmd, args)
	if err != nil {
		return "", &cmdError{cmd: cmd, args: args, err: err, out: out.String()}
	}
	return out.String(), nil
}

func getPort() (string, error) {
	return config.GetString("docker:run-cmd:port")
}

type container struct {
	ID       string `bson:"_id"`
	AppName  string
	Type     string
	IP       string
	Port     string
	HostPort string
	Status   string
	Version  string
	Image    string
}

func (c *container) getAddress() string {
	hostAddr, err := config.Get("docker:host-address")
	if err != nil {
		log.Printf("Failed to obtain container address: %s", err.Error())
		return ""
	}
	return fmt.Sprintf("http://%s:%s", hostAddr, c.HostPort)
}

// newContainer creates a new container in Docker and stores it in the database.
func newContainer(app provision.App, imageId string, cmds []string) (container, error) {
	cont := container{
		AppName: app.GetName(),
		Type:    app.GetPlatform(),
	}
	port, err := getPort()
	if err != nil {
		log.Printf("error on getting port for container %s - %s", cont.AppName, port)
		return container{}, err
	}
	config := docker.Config{
		Image:        imageId,
		Cmd:          cmds,
		PortSpecs:    []string{port},
		AttachStdin:  false,
		AttachStdout: false,
		AttachStderr: false,
	}
	c, err := dockerCluster().CreateContainer(&config)
	if err != nil {
		log.Printf("error on creating container in docker %s - %s", cont.AppName, err.Error())
		return container{}, err
	}
	cont.ID = c.ID
	cont.Port = port
	return cont, nil
}

// hostPort returns the host port mapped for the container.
func (c *container) hostPort() (string, error) {
	if c.Port == "" {
		return "", errors.New("Container does not contain any mapped port")
	}
	dockerContainer, err := dockerCluster().InspectContainer(c.ID)
	if err != nil {
		return "", err
	}
	if dockerContainer.NetworkSettings != nil {
		mappedPorts := dockerContainer.NetworkSettings.PortMapping
		if port, ok := mappedPorts["Tcp"][c.Port]; ok {
			return port, nil
		}
	}
	return "", fmt.Errorf("Container port %s is not mapped to any host port", c.Port)
}

// ip returns the ip for the container.
func (c *container) ip() (string, error) {
	dockerContainer, err := dockerCluster().InspectContainer(c.ID)
	if err != nil {
		return "", err
	}
	if dockerContainer.NetworkSettings == nil {
		msg := "Error when getting container information. NetworkSettings is missing."
		log.Print(msg)
		return "", errors.New(msg)
	}
	instanceIP := dockerContainer.NetworkSettings.IPAddress
	if instanceIP == "" {
		msg := "error: Can't get ipaddress..."
		log.Print(msg)
		return "", errors.New(msg)
	}
	log.Printf("Instance IpAddress: %s", instanceIP)
	return instanceIP, nil
}

func (c *container) setStatus(status string) error {
	c.Status = status
	coll := collection()
	defer coll.Database.Session.Close()
	return coll.UpdateId(c.ID, c)
}

func (c *container) setImage(imageId string) error {
	c.Image = imageId
	coll := collection()
	defer coll.Database.Session.Close()
	return coll.UpdateId(c.ID, c)
}

func deploy(app provision.App, version string, w io.Writer) (string, error) {
	commands, err := deployCmds(app, version)
	if err != nil {
		return "", err
	}
	imageId := getImage(app)
	actions := []*action.Action{&createContainer, &startContainer, &insertContainer}
	pipeline := action.NewPipeline(actions...)
	err = pipeline.Execute(app, imageId, commands)
	if err != nil {
		log.Printf("error on execute deploy pipeline for app %s - %s", app.GetName(), err.Error())
		return "", err
	}
	c := pipeline.Result().(container)
	for {
		result, err := c.stopped()
		if err != nil {
			log.Printf("error on stopped for container %s - %s", c.ID, err.Error())
			return "", err
		}
		if result {
			break
		}
	}
	err = c.logs(w)
	if err != nil {
		log.Printf("error on get logs for container %s - %s", c.ID, err.Error())
		return "", err
	}
	imageId, err = c.commit()
	if err != nil {
		log.Printf("error on commit container %s - %s", c.ID, err.Error())
		return "", err
	}
	c.remove()
	return imageId, nil
}

func start(app provision.App, imageId string, w io.Writer) (*container, error) {
	commands, err := runCmds()
	if err != nil {
		return nil, err
	}
	actions := []*action.Action{&createContainer, &startContainer, &setIp, &setHostPort, &insertContainer, &addRoute}
	pipeline := action.NewPipeline(actions...)
	err = pipeline.Execute(app, imageId, commands)
	if err != nil {
		return nil, err
	}
	c := pipeline.Result().(container)
	err = c.setImage(imageId)
	if err != nil {
		return nil, err
	}
	err = c.setStatus("running")
	if err != nil {
		return nil, err
	}
	return &c, nil
}

// remove removes a docker container.
func (c *container) remove() error {
	address := c.getAddress()
	log.Printf("Removing container %s from docker", c.ID)
	err := dockerCluster().RemoveContainer(c.ID)
	if err != nil {
		log.Printf("Failed to remove container from docker: %s", err)
	}
	runCmd("ssh-keygen", "-R", c.IP)
	log.Printf("Removing container %s from database", c.ID)
	coll := collection()
	defer coll.Database.Session.Close()
	if err := coll.RemoveId(c.ID); err != nil {
		log.Printf("Failed to remove container from database: %s", err)
	}
	r, err := getRouter()
	if err != nil {
		log.Printf("Failed to obtain router: %s", err)
	}
	if err := r.RemoveRoute(c.AppName, address); err != nil {
		log.Printf("Failed to remove route: %s", err)
	}
	return nil
}

func (c *container) ssh(stdout, stderr io.Writer, cmd string, args ...string) error {
	stderr = &filter{w: stderr, content: []byte("unable to resolve host")}
	user, err := config.GetString("docker:ssh:user")
	if err != nil {
		return err
	}
	sshArgs := []string{c.IP, "-l", user, "-o", "StrictHostKeyChecking no"}
	if keyFile, err := config.GetString("docker:ssh:private-key"); err == nil {
		sshArgs = append(sshArgs, "-i", keyFile)
	}
	sshArgs = append(sshArgs, "--", cmd)
	sshArgs = append(sshArgs, args...)
	return executor().Execute("ssh", sshArgs, nil, stdout, stderr)
}

// commit commits an image in docker based in the container
// and returns the image repository.
func (c *container) commit() (string, error) {
	log.Printf("commiting container %s", c.ID)
	repository := buildImageName(c.AppName)
	opts := dclient.CommitContainerOptions{Container: c.ID, Repository: repository}
	image, err := dockerCluster().CommitContainer(opts)
	if err != nil {
		log.Printf("Could not commit docker image: %s", err.Error())
		return "", err
	}
	log.Printf("image %s generated from container %s", image.ID, c.ID)
	replicateImage(repository)
	return repository, nil
}

// stopped returns true if the container is stopped.
func (c *container) stopped() (bool, error) {
	dockerContainer, err := dockerCluster().InspectContainer(c.ID)
	if err != nil {
		log.Printf("error on get log for container %s: %s", c.ID, err)
		return false, err
	}
	return !dockerContainer.State.Running, nil
}

// stop stops the container.
func (c *container) stop() error {
	err := dockerCluster().StopContainer(c.ID, 10)
	if err != nil {
		log.Printf("error on stop container %s: %s", c.ID, err)
	}
	return err
}

// logs returns logs for the container.
func (c *container) logs(w io.Writer) error {
	opts := dclient.AttachToContainerOptions{
		Container:    c.ID,
		Logs:         true,
		Stdout:       true,
		OutputStream: w,
	}
	err := dockerCluster().AttachToContainer(opts)
	if err != nil {
		return err
	}
	opts = dclient.AttachToContainerOptions{
		Container:    c.ID,
		Logs:         true,
		Stderr:       true,
		OutputStream: w,
	}
	return dockerCluster().AttachToContainer(opts)
}

func getContainer(id string) (*container, error) {
	var c container
	coll := collection()
	defer coll.Database.Session.Close()
	err := coll.Find(bson.M{"_id": id}).One(&c)
	if err != nil {
		return nil, err
	}
	return &c, nil
}

func listAppContainers(appName string) ([]container, error) {
	var containers []container
	err := collection().Find(bson.M{"appname": appName}).All(&containers)
	return containers, err
}

// getImage returns the image name or id from an app.
func getImage(app provision.App) string {
	var c container
	collection().Find(bson.M{"appname": app.GetName()}).One(&c)
	if c.Image != "" {
		return c.Image
	}
	repoNamespace, err := config.GetString("docker:repository-namespace")
	if err != nil {
		return ""
	}
	return fmt.Sprintf("%s/%s", repoNamespace, app.GetPlatform())
}

// removeImage removes an image from docker registry
func removeImage(imageId string) error {
	return dockerCluster().RemoveImage(imageId)
}

type cmdError struct {
	cmd  string
	args []string
	err  error
	out  string
}

func (e *cmdError) Error() string {
	command := e.cmd + " " + strings.Join(e.args, " ")
	return fmt.Sprintf("Failed to run command %q (%s): %s.", command, e.err, e.out)
}

// replicateImage replicates the given image through all nodes in the cluster.
func replicateImage(name string) error {
	var buf bytes.Buffer
	if registry, err := config.GetString("docker:registry"); err == nil {
		if !strings.HasPrefix(name, registry) {
			name = registry + "/" + name
		}
		pushOpts := dclient.PushImageOptions{Name: name}
		for i := 0; i < pushMaxTry; i++ {
			err := dockerCluster().PushImage(pushOpts, &buf)
			if err == nil {
				buf.Reset()
				break
			}
			log.Printf("[docker] Failed to push image %q (%s): %s", name, err, buf.String())
			buf.Reset()
		}
		pullOpts := dclient.PullImageOptions{Repository: name}
		err = dockerCluster().PullImage(pullOpts, &buf)
		if err != nil {
			log.Printf("[docker] Failed to replicate image %q through nodes (%s): %s", name, err, buf.String())
			return err
		}
	}
	return nil
}

func buildImageName(appName string) string {
	parts := make([]string, 0, 3)
	registry, _ := config.GetString("docker:registry")
	if registry != "" {
		parts = append(parts, registry)
	}
	repoNamespace, _ := config.GetString("docker:repository-namespace")
	parts = append(parts, repoNamespace, appName)
	return strings.Join(parts, "/")
}
<commit_msg>provision/docker: don't ignore errors on replication<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package docker

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/dotcloud/docker"
	dclient "github.com/fsouza/go-dockerclient"
	"github.com/globocom/config"
	"github.com/globocom/docker-cluster/cluster"
	"github.com/globocom/docker-cluster/storage"
	"github.com/globocom/tsuru/action"
	"github.com/globocom/tsuru/fs"
	"github.com/globocom/tsuru/log"
	"github.com/globocom/tsuru/provision"
	"io"
	"labix.org/v2/mgo/bson"
	"strings"
	"sync"
)

var (
	dCluster *cluster.Cluster
	cmutext  sync.Mutex
	fsystem  fs.Fs
)

const pushMaxTry = 5

func dockerCluster() *cluster.Cluster {
	cmutext.Lock()
	defer cmutext.Unlock()
	if dCluster == nil {
		servers, _ := config.GetList("docker:servers")
		if len(servers) < 1 {
			log.Fatal(`Tsuru is misconfigured. Setting "docker:servers" is mandatory`)
		}
		nodes := []cluster.Node{}
		for index, server := range servers {
			node := cluster.Node{
				ID:      fmt.Sprintf("server%d", index),
				Address: server,
			}
			nodes = append(nodes, node)
		}
		if segregate, _ := config.GetBool("docker:segregate"); segregate {
			var scheduler segregatedScheduler
			dCluster, _ = cluster.New(&scheduler, nodes...)
		} else {
			dCluster, _ = cluster.New(nil, nodes...)
		}
		if redisServer, err := config.GetString("docker:scheduler:redis-server"); err == nil {
			if password, err := config.GetString("docker:scheduler:redis-password"); err == nil {
				dCluster.SetStorage(storage.AuthenticatedRedis(redisServer, password))
			} else {
				dCluster.SetStorage(storage.Redis(redisServer))
			}
		}
	}
	return dCluster
}

func filesystem() fs.Fs {
	if fsystem == nil {
		fsystem = fs.OsFs{}
	}
	return fsystem
}

// runCmd executes commands and log the given stdout and stderror.
func runCmd(cmd string, args ...string) (string, error) {
	out := bytes.Buffer{}
	err := executor().Execute(cmd, args, nil, &out, &out)
	log.Printf("running the cmd: %s with the args: %s", cmd, args)
	if err != nil {
		return "", &cmdError{cmd: cmd, args: args, err: err, out: out.String()}
	}
	return out.String(), nil
}

func getPort() (string, error) {
	return config.GetString("docker:run-cmd:port")
}

type container struct {
	ID       string `bson:"_id"`
	AppName  string
	Type     string
	IP       string
	Port     string
	HostPort string
	Status   string
	Version  string
	Image    string
}

func (c *container) getAddress() string {
	hostAddr, err := config.Get("docker:host-address")
	if err != nil {
		log.Printf("Failed to obtain container address: %s", err.Error())
		return ""
	}
	return fmt.Sprintf("http://%s:%s", hostAddr, c.HostPort)
}

// newContainer creates a new container in Docker and stores it in the database.
func newContainer(app provision.App, imageId string, cmds []string) (container, error) {
	cont := container{
		AppName: app.GetName(),
		Type:    app.GetPlatform(),
	}
	port, err := getPort()
	if err != nil {
		log.Printf("error on getting port for container %s - %s", cont.AppName, port)
		return container{}, err
	}
	config := docker.Config{
		Image:        imageId,
		Cmd:          cmds,
		PortSpecs:    []string{port},
		AttachStdin:  false,
		AttachStdout: false,
		AttachStderr: false,
	}
	c, err := dockerCluster().CreateContainer(&config)
	if err != nil {
		log.Printf("error on creating container in docker %s - %s", cont.AppName, err.Error())
		return container{}, err
	}
	cont.ID = c.ID
	cont.Port = port
	return cont, nil
}

// hostPort returns the host port mapped for the container.
func (c *container) hostPort() (string, error) {
	if c.Port == "" {
		return "", errors.New("Container does not contain any mapped port")
	}
	dockerContainer, err := dockerCluster().InspectContainer(c.ID)
	if err != nil {
		return "", err
	}
	if dockerContainer.NetworkSettings != nil {
		mappedPorts := dockerContainer.NetworkSettings.PortMapping
		if port, ok := mappedPorts["Tcp"][c.Port]; ok {
			return port, nil
		}
	}
	return "", fmt.Errorf("Container port %s is not mapped to any host port", c.Port)
}

// ip returns the ip for the container.
func (c *container) ip() (string, error) {
	dockerContainer, err := dockerCluster().InspectContainer(c.ID)
	if err != nil {
		return "", err
	}
	if dockerContainer.NetworkSettings == nil {
		msg := "Error when getting container information. NetworkSettings is missing."
		log.Print(msg)
		return "", errors.New(msg)
	}
	instanceIP := dockerContainer.NetworkSettings.IPAddress
	if instanceIP == "" {
		msg := "error: Can't get ipaddress..."
		log.Print(msg)
		return "", errors.New(msg)
	}
	log.Printf("Instance IpAddress: %s", instanceIP)
	return instanceIP, nil
}

func (c *container) setStatus(status string) error {
	c.Status = status
	coll := collection()
	defer coll.Database.Session.Close()
	return coll.UpdateId(c.ID, c)
}

func (c *container) setImage(imageId string) error {
	c.Image = imageId
	coll := collection()
	defer coll.Database.Session.Close()
	return coll.UpdateId(c.ID, c)
}

func deploy(app provision.App, version string, w io.Writer) (string, error) {
	commands, err := deployCmds(app, version)
	if err != nil {
		return "", err
	}
	imageId := getImage(app)
	actions := []*action.Action{&createContainer, &startContainer, &insertContainer}
	pipeline := action.NewPipeline(actions...)
	err = pipeline.Execute(app, imageId, commands)
	if err != nil {
		log.Printf("error on execute deploy pipeline for app %s - %s", app.GetName(), err.Error())
		return "", err
	}
	c := pipeline.Result().(container)
	for {
		result, err := c.stopped()
		if err != nil {
			log.Printf("error on stopped for container %s - %s", c.ID, err.Error())
			return "", err
		}
		if result {
			break
		}
	}
	err = c.logs(w)
	if err != nil {
		log.Printf("error on get logs for container %s - %s", c.ID, err.Error())
		return "", err
	}
	imageId, err = c.commit()
	if err != nil {
		log.Printf("error on commit container %s - %s", c.ID, err.Error())
		return "", err
	}
	c.remove()
	return imageId, nil
}

func start(app provision.App, imageId string, w io.Writer) (*container, error) {
	commands, err := runCmds()
	if err != nil {
		return nil, err
	}
	actions := []*action.Action{&createContainer, &startContainer, &setIp, &setHostPort, &insertContainer, &addRoute}
	pipeline := action.NewPipeline(actions...)
	err = pipeline.Execute(app, imageId, commands)
	if err != nil {
		return nil, err
	}
	c := pipeline.Result().(container)
	err = c.setImage(imageId)
	if err != nil {
		return nil, err
	}
	err = c.setStatus("running")
	if err != nil {
		return nil, err
	}
	return &c, nil
}

// remove removes a docker container.
func (c *container) remove() error {
	address := c.getAddress()
	log.Printf("Removing container %s from docker", c.ID)
	err := dockerCluster().RemoveContainer(c.ID)
	if err != nil {
		log.Printf("Failed to remove container from docker: %s", err)
	}
	runCmd("ssh-keygen", "-R", c.IP)
	log.Printf("Removing container %s from database", c.ID)
	coll := collection()
	defer coll.Database.Session.Close()
	if err := coll.RemoveId(c.ID); err != nil {
		log.Printf("Failed to remove container from database: %s", err)
	}
	r, err := getRouter()
	if err != nil {
		log.Printf("Failed to obtain router: %s", err)
	}
	if err := r.RemoveRoute(c.AppName, address); err != nil {
		log.Printf("Failed to remove route: %s", err)
	}
	return nil
}

func (c *container) ssh(stdout, stderr io.Writer, cmd string, args ...string) error {
	stderr = &filter{w: stderr, content: []byte("unable to resolve host")}
	user, err := config.GetString("docker:ssh:user")
	if err != nil {
		return err
	}
	sshArgs := []string{c.IP, "-l", user, "-o", "StrictHostKeyChecking no"}
	if keyFile, err := config.GetString("docker:ssh:private-key"); err == nil {
		sshArgs = append(sshArgs, "-i", keyFile)
	}
	sshArgs = append(sshArgs, "--", cmd)
	sshArgs = append(sshArgs, args...)
	return executor().Execute("ssh", sshArgs, nil, stdout, stderr)
}

// commit commits an image in docker based in the container
// and returns the image repository.
func (c *container) commit() (string, error) {
	log.Printf("commiting container %s", c.ID)
	repository := buildImageName(c.AppName)
	opts := dclient.CommitContainerOptions{Container: c.ID, Repository: repository}
	image, err := dockerCluster().CommitContainer(opts)
	if err != nil {
		log.Printf("Could not commit docker image: %s", err.Error())
		return "", err
	}
	log.Printf("image %s generated from container %s", image.ID, c.ID)
	replicateImage(repository)
	return repository, nil
}

// stopped returns true if the container is stopped.
func (c *container) stopped() (bool, error) {
	dockerContainer, err := dockerCluster().InspectContainer(c.ID)
	if err != nil {
		log.Printf("error on get log for container %s: %s", c.ID, err)
		return false, err
	}
	return !dockerContainer.State.Running, nil
}

// stop stops the container.
func (c *container) stop() error {
	err := dockerCluster().StopContainer(c.ID, 10)
	if err != nil {
		log.Printf("error on stop container %s: %s", c.ID, err)
	}
	return err
}

// logs returns logs for the container.
func (c *container) logs(w io.Writer) error {
	opts := dclient.AttachToContainerOptions{
		Container:    c.ID,
		Logs:         true,
		Stdout:       true,
		OutputStream: w,
	}
	err := dockerCluster().AttachToContainer(opts)
	if err != nil {
		return err
	}
	opts = dclient.AttachToContainerOptions{
		Container:    c.ID,
		Logs:         true,
		Stderr:       true,
		OutputStream: w,
	}
	return dockerCluster().AttachToContainer(opts)
}

func getContainer(id string) (*container, error) {
	var c container
	coll := collection()
	defer coll.Database.Session.Close()
	err := coll.Find(bson.M{"_id": id}).One(&c)
	if err != nil {
		return nil, err
	}
	return &c, nil
}

func listAppContainers(appName string) ([]container, error) {
	var containers []container
	err := collection().Find(bson.M{"appname": appName}).All(&containers)
	return containers, err
}

// getImage returns the image name or id from an app.
func getImage(app provision.App) string {
	var c container
	collection().Find(bson.M{"appname": app.GetName()}).One(&c)
	if c.Image != "" {
		return c.Image
	}
	repoNamespace, err := config.GetString("docker:repository-namespace")
	if err != nil {
		return ""
	}
	return fmt.Sprintf("%s/%s", repoNamespace, app.GetPlatform())
}

// removeImage removes an image from docker registry
func removeImage(imageId string) error {
	return dockerCluster().RemoveImage(imageId)
}

type cmdError struct {
	cmd  string
	args []string
	err  error
	out  string
}

func (e *cmdError) Error() string {
	command := e.cmd + " " + strings.Join(e.args, " ")
	return fmt.Sprintf("Failed to run command %q (%s): %s.", command, e.err, e.out)
}

// replicateImage replicates the given image through all nodes in the cluster.
func replicateImage(name string) error {
	var buf bytes.Buffer
	if registry, err := config.GetString("docker:registry"); err == nil {
		if !strings.HasPrefix(name, registry) {
			name = registry + "/" + name
		}
		pushOpts := dclient.PushImageOptions{Name: name}
		for i := 0; i < pushMaxTry; i++ {
			err := dockerCluster().PushImage(pushOpts, &buf)
			if err == nil {
				buf.Reset()
				break
			}
			log.Printf("[docker] Failed to push image %q (%s): %s", name, err, buf.String())
			buf.Reset()
		}
		if err != nil {
			return err
		}
		pullOpts := dclient.PullImageOptions{Repository: name}
		err = dockerCluster().PullImage(pullOpts, &buf)
		if err != nil {
			log.Printf("[docker] Failed to replicate image %q through nodes (%s): %s", name, err, buf.String())
			return err
		}
	}
	return nil
}

func buildImageName(appName string) string {
	parts := make([]string, 0, 3)
	registry, _ := config.GetString("docker:registry")
	if registry != "" {
		parts = append(parts, registry)
	}
	repoNamespace, _ := config.GetString("docker:repository-namespace")
	parts = append(parts, repoNamespace, appName)
	return strings.Join(parts, "/")
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"regexp"
	"testing"
)

const testThis = "@k8s-bot test this"

// Make sure that our rerun commands match our triggers.
func TestJobTriggers(t *testing.T) {
	ja := &JobAgent{}
	if err := ja.load("../../jobs.yaml"); err != nil {
		t.Fatalf("Could not load job configs: %v", err)
	}
	if len(ja.jobs) == 0 {
		t.Fatalf("No jobs found in jobs.yaml.")
	}
	for _, jobs := range ja.jobs {
		for i, job := range jobs {
			if job.Name == "" {
				t.Errorf("Job %v needs a name.", job)
				continue
			}
			if job.Context == "" {
				t.Errorf("Job %s needs a context.", job.Name)
			}
			if job.RerunCommand == "" || job.Trigger == "" {
				t.Errorf("Job %s needs a trigger and a rerun command.", job.Name)
				continue
			}
			// Check that the merge bot will run AlwaysRun jobs, otherwise it
			// will attempt to rerun forever.
			if job.AlwaysRun && !job.re.MatchString(testThis) {
				t.Errorf("AlwaysRun job %s: \"%s\" does not match regex \"%v\".", job.Name, testThis, job.Trigger)
			}
			// Check that the rerun command actually runs the job.
			if !job.re.MatchString(job.RerunCommand) {
				t.Errorf("For job %s: RerunCommand \"%s\" does not match regex \"%v\".", job.Name, job.RerunCommand, job.Trigger)
			}
			// Next check that the rerun command doesn't run any other jobs.
			for j, job2 := range jobs {
				if i == j {
					continue
				}
				if job2.re.MatchString(job.RerunCommand) {
					t.Errorf("RerunCommand \"%s\" from job %s matches \"%v\" from job %s but shouldn't.", job.RerunCommand, job.Name, job2.Trigger, job2.Name)
				}
			}
		}
	}
}

func TestCommentBodyMatches(t *testing.T) {
	var testcases = []struct {
		repo         string
		body         string
		expectedJobs []string
	}{
		{
			"org/repo",
			"this is a random comment",
			[]string{},
		},
		{
			"org/repo",
			"ok to test",
			[]string{"gce", "unit"},
		},
		{
			"org/repo",
			"@k8s-bot test this",
			[]string{"gce", "unit", "gke"},
		},
		{
			"org/repo",
			"@k8s-bot unit test this",
			[]string{"unit"},
		},
		{
			"org/repo",
			"@k8s-bot federation test this",
			[]string{"federation"},
		},
		{
			"org/repo2",
			"@k8s-bot test this",
			[]string{"cadveapster"},
		},
		{
			"org/repo3",
			"@k8s-bot test this",
			[]string{},
		},
	}
	ja := &JobAgent{
		jobs: map[string][]JenkinsJob{
			"org/repo": {
				{
					Name:      "gce",
					re:        regexp.MustCompile(`@k8s-bot (gce )?test this`),
					AlwaysRun: true,
				},
				{
					Name:      "unit",
					re:        regexp.MustCompile(`@k8s-bot (unit )?test this`),
					AlwaysRun: true,
				},
				{
					Name:      "gke",
					re:        regexp.MustCompile(`@k8s-bot (gke )?test this`),
					AlwaysRun: false,
				},
				{
					Name:      "federation",
					re:        regexp.MustCompile(`@k8s-bot federation test this`),
					AlwaysRun: false,
				},
			},
			"org/repo2": {
				{
					Name:      "cadveapster",
					re:        regexp.MustCompile(`@k8s-bot test this`),
					AlwaysRun: true,
				},
			},
		},
	}
	for _, tc := range testcases {
		actualJobs := ja.MatchingJobs(tc.repo, tc.body)
		match := true
		if len(actualJobs) != len(tc.expectedJobs) {
			match = false
		} else {
			for _, actualJob := range actualJobs {
				found := false
				for _, expectedJob := range tc.expectedJobs {
					if expectedJob == actualJob.Name {
						found = true
						break
					}
				}
				if !found {
					match = false
					break
				}
			}
		}
		if !match {
			t.Errorf("Wrong jobs for body %s. Got %v, expected %v.", tc.body, actualJobs, tc.expectedJobs)
		}
	}
}
<commit_msg>Add unit tests for bootstrap prow jobs<commit_after>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"fmt"
	"os"
	"regexp"
	"strings"
	"testing"
)

const testThis = "@k8s-bot test this"

// Make sure that our rerun commands match our triggers.
func TestJobTriggers(t *testing.T) {
	ja := &JobAgent{}
	if err := ja.load("../../jobs.yaml"); err != nil {
		t.Fatalf("Could not load job configs: %v", err)
	}
	if len(ja.jobs) == 0 {
		t.Fatalf("No jobs found in jobs.yaml.")
	}
	for _, jobs := range ja.jobs {
		for i, job := range jobs {
			if job.Name == "" {
				t.Errorf("Job %v needs a name.", job)
				continue
			}
			if job.Context == "" {
				t.Errorf("Job %s needs a context.", job.Name)
			}
			if job.RerunCommand == "" || job.Trigger == "" {
				t.Errorf("Job %s needs a trigger and a rerun command.", job.Name)
				continue
			}
			// Check that the merge bot will run AlwaysRun jobs, otherwise it
			// will attempt to rerun forever.
			if job.AlwaysRun && !job.re.MatchString(testThis) {
				t.Errorf("AlwaysRun job %s: \"%s\" does not match regex \"%v\".", job.Name, testThis, job.Trigger)
			}
			// Check that the rerun command actually runs the job.
			if !job.re.MatchString(job.RerunCommand) {
				t.Errorf("For job %s: RerunCommand \"%s\" does not match regex \"%v\".", job.Name, job.RerunCommand, job.Trigger)
			}
			// Next check that the rerun command doesn't run any other jobs.
			for j, job2 := range jobs {
				if i == j {
					continue
				}
				if job2.re.MatchString(job.RerunCommand) {
					t.Errorf("RerunCommand \"%s\" from job %s matches \"%v\" from job %s but shouldn't.", job.RerunCommand, job.Name, job2.Trigger, job2.Name)
				}
			}
			// Ensure that bootstrap jobs have a shell script of the same name.
			if strings.HasPrefix(job.Name, "pull-") {
				if _, err := os.Stat(fmt.Sprintf("../../../jobs/%s.sh", job.Name)); err != nil {
					t.Errorf("Cannot find test-infra/jobs/%s.sh", job.Name)
				}
			}

		}
	}
}

func TestCommentBodyMatches(t *testing.T) {
	var testcases = []struct {
		repo         string
		body         string
		expectedJobs []string
	}{
		{
			"org/repo",
			"this is a random comment",
			[]string{},
		},
		{
			"org/repo",
			"ok to test",
			[]string{"gce", "unit"},
		},
		{
			"org/repo",
			"@k8s-bot test this",
			[]string{"gce", "unit", "gke"},
		},
		{
			"org/repo",
			"@k8s-bot unit test this",
			[]string{"unit"},
		},
		{
			"org/repo",
			"@k8s-bot federation test this",
			[]string{"federation"},
		},
		{
			"org/repo2",
			"@k8s-bot test this",
			[]string{"cadveapster"},
		},
		{
			"org/repo3",
			"@k8s-bot test this",
			[]string{},
		},
	}
	ja := &JobAgent{
		jobs: map[string][]JenkinsJob{
			"org/repo": {
				{
					Name:      "gce",
					re:        regexp.MustCompile(`@k8s-bot (gce )?test this`),
					AlwaysRun: true,
				},
				{
					Name:      "unit",
					re:        regexp.MustCompile(`@k8s-bot (unit )?test this`),
					AlwaysRun: true,
				},
				{
					Name:      "gke",
					re:        regexp.MustCompile(`@k8s-bot (gke )?test this`),
					AlwaysRun: false,
				},
				{
					Name:      "federation",
					re:        regexp.MustCompile(`@k8s-bot federation test this`),
					AlwaysRun: false,
				},
			},
			"org/repo2": {
				{
					Name:      "cadveapster",
					re:        regexp.MustCompile(`@k8s-bot test this`),
					AlwaysRun: true,
				},
			},
		},
	}
	for _, tc := range testcases {
		actualJobs := ja.MatchingJobs(tc.repo, tc.body)
		match := true
		if len(actualJobs) != len(tc.expectedJobs) {
			match = false
		} else {
			for _, actualJob := range actualJobs {
				found := false
				for _, expectedJob := range tc.expectedJobs {
					if expectedJob == actualJob.Name {
						found = true
						break
					}
				}
				if !found {
					match = false
					break
				}
			}
		}
		if !match {
			t.Errorf("Wrong jobs for body %s. Got %v, expected %v.", tc.body, actualJobs, tc.expectedJobs)
		}
	}
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"testing"

	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccDataSourceAwsRoute53Zone(t *testing.T) {
	rInt := acctest.RandInt()
	publicResourceName := "aws_route53_zon.test"
	publicDomain := fmt.Sprintf("terraformtestacchz-%d.com.", rInt)
	privateResourceName := "aws_route53_zone.test_private"
	privateDomain := fmt.Sprintf("test.acc-%d.", rInt)

	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config: testAccDataSourceAwsRoute53ZoneConfig(rInt),
				Check: resource.ComposeTestCheckFunc(
					testAccDataSourceAwsRoute53ZoneCheck(
						publicResourceName, "data.aws_route53_zone.by_zone_id", publicDomain),
					testAccDataSourceAwsRoute53ZoneCheck(
						publicResourceName, "data.aws_route53_zone.by_name", publicDomain),
					testAccDataSourceAwsRoute53ZoneCheck(
						privateResourceName, "data.aws_route53_zone.by_vpc", privateDomain),
					testAccDataSourceAwsRoute53ZoneCheck(
						privateResourceName, "data.aws_route53_zone.by_tag", privateDomain),
				),
			},
		},
	})
}

// rsName for the name of the created resource
// dsName for the name of the created data source
// zName for the name of the domain
func testAccDataSourceAwsRoute53ZoneCheck(rsName, dsName, zName string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[rsName]
		if !ok {
			return fmt.Errorf("root module has no resource called %s", rsName)
		}

		hostedZone, ok := s.RootModule().Resources[dsName]
		if !ok {
			return fmt.Errorf("can't find zone %q in state", dsName)
		}

		attr := rs.Primary.Attributes
		if attr["id"] != hostedZone.Primary.Attributes["id"] {
			return fmt.Errorf(
				"id is %s; want %s",
				attr["id"],
				hostedZone.Primary.Attributes["id"],
			)
		}

		if attr["name"] != zName {
			return fmt.Errorf("Route53 Zone name is %q; want %q", attr["name"], zName)
		}

		return nil
	}
}

func testAccDataSourceAwsRoute53ZoneConfig(rInt int) string {
	return fmt.Sprintf(`
	provider "aws" {
		region = "us-east-2"
	}

	resource "aws_vpc" "test" {
		cidr_block = "172.16.0.0/16"
	}

	resource "aws_route53_zone" "test_private" {
		name = "test.acc-%d."
		vpc_id = "${aws_vpc.test.id}"
		tags {
			Environment = "dev-%d"
		}
	}

	data "aws_route53_zone" "by_vpc" {
	 name = "${aws_route53_zone.test_private.name}"
	 vpc_id = "${aws_vpc.test.id}"
	}

	data "aws_route53_zone" "by_tag" {
	 name = "${aws_route53_zone.test_private.name}"
	 private_zone = true
	 tags {
		 Environment = "dev-%d"
	 }
	}

	resource "aws_route53_zone" "test" {
		name = "terraformtestacchz-%d.com."
	}

	data "aws_route53_zone" "by_zone_id" {
		zone_id = "${aws_route53_zone.test.zone_id}"
	}

	data "aws_route53_zone" "by_name" {
		name = "${data.aws_route53_zone.by_zone_id.name}"
	}`, rInt, rInt, rInt, rInt)
}
<commit_msg>Fixes route53 test<commit_after>package aws

import (
	"fmt"
	"testing"

	"github.com/hashicorp/terraform/helper/acctest"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccDataSourceAwsRoute53Zone(t *testing.T) {
	rInt := acctest.RandInt()
	publicResourceName := "aws_route53_zone.test"
	publicDomain := fmt.Sprintf("terraformtestacchz-%d.com.", rInt)
	privateResourceName := "aws_route53_zone.test_private"
	privateDomain := fmt.Sprintf("test.acc-%d.", rInt)

	resource.Test(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config: testAccDataSourceAwsRoute53ZoneConfig(rInt),
				Check: resource.ComposeTestCheckFunc(
					testAccDataSourceAwsRoute53ZoneCheck(
						publicResourceName, "data.aws_route53_zone.by_zone_id", publicDomain),
					testAccDataSourceAwsRoute53ZoneCheck(
						publicResourceName, "data.aws_route53_zone.by_name", publicDomain),
					testAccDataSourceAwsRoute53ZoneCheck(
						privateResourceName, "data.aws_route53_zone.by_vpc", privateDomain),
					testAccDataSourceAwsRoute53ZoneCheck(
						privateResourceName, "data.aws_route53_zone.by_tag", privateDomain),
				),
			},
		},
	})
}

// rsName for the name of the created resource
// dsName for the name of the created data source
// zName for the name of the domain
func testAccDataSourceAwsRoute53ZoneCheck(rsName, dsName, zName string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[rsName]
		if !ok {
			return fmt.Errorf("root module has no resource called %s", rsName)
		}

		hostedZone, ok := s.RootModule().Resources[dsName]
		if !ok {
			return fmt.Errorf("can't find zone %q in state", dsName)
		}

		attr := rs.Primary.Attributes
		if attr["id"] != hostedZone.Primary.Attributes["id"] {
			return fmt.Errorf(
				"id is %s; want %s",
				attr["id"],
				hostedZone.Primary.Attributes["id"],
			)
		}

		if attr["name"] != zName {
			return fmt.Errorf("Route53 Zone name is %q; want %q", attr["name"], zName)
		}

		return nil
	}
}

func testAccDataSourceAwsRoute53ZoneConfig(rInt int) string {
	return fmt.Sprintf(`
	provider "aws" {
		region = "us-east-2"
	}

	resource "aws_vpc" "test" {
		cidr_block = "172.16.0.0/16"
	}

	resource "aws_route53_zone" "test_private" {
		name = "test.acc-%d."
		vpc_id = "${aws_vpc.test.id}"
		tags {
			Environment = "dev-%d"
		}
	}

	data "aws_route53_zone" "by_vpc" {
	 name = "${aws_route53_zone.test_private.name}"
	 vpc_id = "${aws_vpc.test.id}"
	}

	data "aws_route53_zone" "by_tag" {
	 name = "${aws_route53_zone.test_private.name}"
	 private_zone = true
	 tags {
		 Environment = "dev-%d"
	 }
	}

	resource "aws_route53_zone" "test" {
		name = "terraformtestacchz-%d.com."
	}

	data "aws_route53_zone" "by_zone_id" {
		zone_id = "${aws_route53_zone.test.zone_id}"
	}

	data "aws_route53_zone" "by_name" {
		name = "${data.aws_route53_zone.by_zone_id.name}"
	}`, rInt, rInt, rInt, rInt)
}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/go-charset/charset"
        _ "code.google.com/p/go-charset/data"
	"code.google.com/p/go.net/html"
	"code.google.com/p/go.net/html/atom"
	"github.com/thoj/go-ircevent"
	"io"
	"log"
	"net/http"
	"net/url"
	"strings"
)

func logprivmsgs(event *irc.Event) {
	log.Print(event.Nick+": ", event.Arguments)
}

type URLTitleExtractor struct {
	ircobject *irc.Connection
}

func (t *URLTitleExtractor) WriteURLTitle(event *irc.Event) {
	var urls []string = FindURLs(event.Arguments[1])
	var err error
	var resp *http.Response
	var contentType string
	var foundcharset string
	var ureader io.Reader
	var htmlnode *html.Node

	for _, oneurl := range urls {
		// URL valid?
		_, err = url.Parse(oneurl)
		if err != nil {
			continue
		}
		resp, err = http.Head(oneurl)
		if err != nil {
			log.Print("Error getting Head: ", err)
			continue
		}

		// No HTML?
		contentType = resp.Header.Get("Content-Type")
		// Content type does not start with "text/html" or "application/xhtml+xml"?
		if !strings.HasPrefix(contentType, "text/html") && !strings.HasPrefix(contentType, "application/xhtml+xml") {
			log.Print("Wrong content type: ", contentType, " Expecting application/xhtml+xml or text/html")
			continue
		}
		// Get the charset
		foundcharset = ExtractCharset(contentType)

		// Get the Body
		resp, err = http.Get(oneurl)
		if err != nil {
			log.Print("Error during HTTP GET: ", err)
			continue
		}
		// Close later
		defer resp.Body.Close()

		if foundcharset != "" && strings.ToLower(foundcharset) != "utf-8" && strings.ToLower(foundcharset) != "utf8" {
			log.Print("Converting from ", foundcharset, " to UTF-8")
			ureader, err = charset.NewReader(foundcharset, resp.Body)
			if err != nil {
				log.Print("Error during utf-8 transformation: ", err)
				continue
			}
		} else {
			ureader = resp.Body
		}
		// Get the top HTML node
		htmlnode, err = html.Parse(ureader)
		if err != nil {
			log.Print("Error parsing HTML file: ", err)
			continue
		}
		var htmltag *html.Node = htmlnode.FirstChild // doctype, if well formed

		// Advance until we find the html tag or until no elements are left.
		for htmltag != nil && (htmltag.Type != html.ElementNode || htmltag.DataAtom != atom.Html) {
			htmltag = htmltag.NextSibling
		}
		// In case of broken HTML where everything is a top level element:
		if htmltag == nil {
			htmltag = htmlnode.FirstChild
		} else {
			htmlnode = htmltag // If head is missing we can continue from here
			htmltag = htmltag.FirstChild
		}
		for htmltag != nil && (htmltag.Type != html.ElementNode || htmltag.DataAtom != atom.Head) {
			htmltag = htmltag.NextSibling
		}
		// In case of even more broken HTML where even the Head is missing
		if htmltag == nil {
			htmltag = htmlnode.FirstChild
		} else {
			htmlnode = htmltag
			htmltag = htmltag.FirstChild // Go into head's first child
		}
		// Continue until finding title element or no elements are left
		for htmltag != nil && (htmltag.Type != html.ElementNode || htmltag.DataAtom != atom.Title) {
			htmltag = htmltag.NextSibling
		}
		if htmltag != nil && htmltag.FirstChild != nil && htmltag.FirstChild.Type == html.TextNode {
			log.Print(htmltag.FirstChild.Data)
                        t.ircobject.Privmsg(event.Arguments[0], "Title: "+htmltag.FirstChild.Data)
		}
	}
}
<commit_msg>Trim whitespace from title.<commit_after>package main

import (
	"code.google.com/p/go-charset/charset"
        _ "code.google.com/p/go-charset/data"
	"code.google.com/p/go.net/html"
	"code.google.com/p/go.net/html/atom"
	"github.com/thoj/go-ircevent"
	"io"
	"log"
	"net/http"
	"net/url"
	"strings"
)

func logprivmsgs(event *irc.Event) {
	log.Print(event.Nick+": ", event.Arguments)
}

type URLTitleExtractor struct {
	ircobject *irc.Connection
}

func (t *URLTitleExtractor) WriteURLTitle(event *irc.Event) {
	var urls []string = FindURLs(event.Arguments[1])
	var err error
	var resp *http.Response
	var contentType string
	var foundcharset string
	var ureader io.Reader
	var htmlnode *html.Node

	for _, oneurl := range urls {
		// URL valid?
		_, err = url.Parse(oneurl)
		if err != nil {
			continue
		}
		resp, err = http.Head(oneurl)
		if err != nil {
			log.Print("Error getting Head: ", err)
			continue
		}

		// No HTML?
		contentType = resp.Header.Get("Content-Type")
		// Content type does not start with "text/html" or "application/xhtml+xml"?
		if !strings.HasPrefix(contentType, "text/html") && !strings.HasPrefix(contentType, "application/xhtml+xml") {
			log.Print("Wrong content type: ", contentType, " Expecting application/xhtml+xml or text/html")
			continue
		}
		// Get the charset
		foundcharset = ExtractCharset(contentType)

		// Get the Body
		resp, err = http.Get(oneurl)
		if err != nil {
			log.Print("Error during HTTP GET: ", err)
			continue
		}
		// Close later
		defer resp.Body.Close()

		if foundcharset != "" && strings.ToLower(foundcharset) != "utf-8" && strings.ToLower(foundcharset) != "utf8" {
			log.Print("Converting from ", foundcharset, " to UTF-8")
			ureader, err = charset.NewReader(foundcharset, resp.Body)
			if err != nil {
				log.Print("Error during utf-8 transformation: ", err)
				continue
			}
		} else {
			ureader = resp.Body
		}
		// Get the top HTML node
		htmlnode, err = html.Parse(ureader)
		if err != nil {
			log.Print("Error parsing HTML file: ", err)
			continue
		}
		var htmltag *html.Node = htmlnode.FirstChild // doctype, if well formed

		// Advance until we find the html tag or until no elements are left.
		for htmltag != nil && (htmltag.Type != html.ElementNode || htmltag.DataAtom != atom.Html) {
			htmltag = htmltag.NextSibling
		}
		// In case of broken HTML where everything is a top level element:
		if htmltag == nil {
			htmltag = htmlnode.FirstChild
		} else {
			htmlnode = htmltag // If head is missing we can continue from here
			htmltag = htmltag.FirstChild
		}
		for htmltag != nil && (htmltag.Type != html.ElementNode || htmltag.DataAtom != atom.Head) {
			htmltag = htmltag.NextSibling
		}
		// In case of even more broken HTML where even the Head is missing
		if htmltag == nil {
			htmltag = htmlnode.FirstChild
		} else {
			htmlnode = htmltag
			htmltag = htmltag.FirstChild // Go into head's first child
		}
		// Continue until finding title element or no elements are left
		for htmltag != nil && (htmltag.Type != html.ElementNode || htmltag.DataAtom != atom.Title) {
			htmltag = htmltag.NextSibling
		}
		if htmltag != nil && htmltag.FirstChild != nil && htmltag.FirstChild.Type == html.TextNode {
			log.Print(htmltag.FirstChild.Data)
                        t.ircobject.Privmsg(event.Arguments[0], "Title: "+strings.TrimSpace(htmltag.FirstChild.Data))
		}
	}
}
<|endoftext|>


<commit_before>package alerts

import (
	"errors"
	"fmt"
	"sync"
	"time"

	"github.com/libopenstorage/openstorage/api"
	"github.com/portworx/kvdb"
	"go.pedge.io/dlog"
)

const (
	// AlertDeleteAction is an alerts watch action for delete
	AlertDeleteAction AlertAction = iota
	// AlertCreateAction is an alerts watch action for create
	AlertCreateAction
	// AlertUpdateAction is an alerts watch action for update
	AlertUpdateAction
)

const (
	//Unknown Resource
	Unknown Resource = iota
	// Volume Resource
	Volume
	// Node Resource
	Node
	// Cluster Resource
	Cluster
)

var (
	// ErrNotSupported implemenation of a specific function is not supported.
	ErrNotSupported = errors.New("implementation not supported")
	// ErrNotFound raised if Key is not found
	ErrNotFound = errors.New("Key not found")
	// ErrExist raised if key already exists
	ErrExist = errors.New("Key already exists")
	// ErrUnmarshal raised if Get fails to unmarshal value.
	ErrUnmarshal = errors.New("Failed to unmarshal value")
	// ErrIllegal raised if object is not valid.
	ErrIllegal = errors.New("Illegal operation")
	// ErrNotInitialized raised if alerts not initialized
	ErrNotInitialized = errors.New("Alerts not initialized")
	// ErrAlertsClientNotFound raised if no client implementation found
	ErrAlertsClientNotFound = errors.New("Alerts client not found")
	// ErrResourceNotFound raised if ResourceType is not found
	ErrResourceNotFound = errors.New("Resource not found in Alerts")

	instances = make(map[string]AlertsClient)
	drivers   = make(map[string]InitFunc)

	lock sync.RWMutex
)

// AlertAction used to indicate the action performed on a KV pair
type AlertAction int

// Resource is equaivalent to api.ResourceType and is used in the alerts instance
// so that callers of the instance don't have to worry about api.*
type Resource int

// InitFunc initialization function for alerts
type InitFunc func(string, string, []string, string) (AlertsClient, error)

// AlertsWatcherFunc is a function type used as a callback for KV WatchTree
type AlertsWatcherFunc func(*api.Alerts, AlertAction, string, string) error

// AlertsClient interface for Alerts API
type AlertsClient interface {
	fmt.Stringer

	// Shutdown
	Shutdown()

	// GetKvdbInstance
	GetKvdbInstance() kvdb.Kvdb

	// Raise raises an Alerts
	Raise(alert api.Alerts) (api.Alerts, error)

	// Retrieve retrieves specific  Alerts
	Retrieve(resourceType api.ResourceType, id int64) (api.Alerts, error)

	// Enumerate enumerates Alerts
	Enumerate(filter api.Alerts) ([]*api.Alerts, error)

	// EnumerateWithinTimeRange enumerates Alertss between timeStart and timeEnd
	EnumerateWithinTimeRange(timeStart time.Time, timeEnd time.Time, resourceType api.ResourceType) ([]*api.Alerts, error)

	// Erase erases an Alerts
	Erase(resourceType api.ResourceType, alertID int64) error

	// Clear an Alerts
	Clear(resourceType api.ResourceType, alertID int64) error

	// Watch on all Alerts
	Watch(clusterId string, alertsWatcher AlertsWatcherFunc) error
}

type AlertsInstance interface {
	// Clear clears an alert
	Clear(resource Resource, resourceId string, alertID int64)

	// Alarm raises an alert with severity : ALARM
	Alarm(name string, msg string, resource Resource, resourceId string) (int64, error)

	// Notify raises an alert with severity : NOTIFY
	Notify(name string, msg string, resource Resource, resourceId string) (int64, error)

	// Warn raises an alert with severity : WARNING
	Warn(name string, msg string, resource Resource, resourceId string) (int64, error)

	// Alert :  Keeping this function for backward compatibility
	// until we remove all calls to this function
	Alert(name string, msg string) error
}

// Shutdown the alerts instance
func Shutdown() {
	lock.Lock()
	defer lock.Unlock()
	for _, v := range instances {
		v.Shutdown()
	}
}

// Get an alerts instance
func Get(name string) (AlertsClient, error) {
	lock.RLock()
	defer lock.RUnlock()

	if v, ok := instances[name]; ok {
		return v, nil
	}
	return nil, ErrAlertsClientNotFound
}

// New returns a new alerts instance
func New(name string, kvdbName string, kvdbBase string, kvdbMachines []string, clusterId string) (AlertsClient, error) {
	lock.Lock()
	defer lock.Unlock()

	if _, ok := instances[name]; ok {
		return nil, ErrExist
	}
	if initFunc, exists := drivers[name]; exists {
		driver, err := initFunc(kvdbName, kvdbBase, kvdbMachines, clusterId)
		if err != nil {
			return nil, err
		}
		instances[name] = driver
		return driver, err
	}
	return nil, ErrNotSupported
}

// NewAlertsInstance creates a new singleton istance of AlertsInstance
func NewAlertsInstance(version, nodeId, clusterId, kvdbName, kvdbBase string, kvdbMachines []string) {
	kva, err := Get(Name)
	if err != nil {
		kva, err = New(Name, kvdbName, kvdbBase, kvdbMachines, clusterId)
		if err != nil {
			dlog.Errorf("Failed to initialize an AlertsInstance ")
		}
	}
	newAlertsInstance(nodeId, clusterId, version, kva)
}

// Instance returns the singleton AlertsInstance
func Instance() AlertsInstance {
	return instance()
}

// Register an alerts interface
func Register(name string, initFunc InitFunc) error {
	lock.Lock()
	defer lock.Unlock()
	if _, exists := drivers[name]; exists {
		return ErrExist
	}
	drivers[name] = initFunc
	return nil
}
<commit_msg>add periods in godoc for alerts<commit_after>package alerts

import (
	"errors"
	"fmt"
	"sync"
	"time"

	"github.com/libopenstorage/openstorage/api"
	"github.com/portworx/kvdb"
	"go.pedge.io/dlog"
)

const (
	// AlertDeleteAction is an alerts watch action for delete.
	AlertDeleteAction AlertAction = iota
	// AlertCreateAction is an alerts watch action for create.
	AlertCreateAction
	// AlertUpdateAction is an alerts watch action for update.
	AlertUpdateAction
)

const (
	//Unknown Resource.
	Unknown Resource = iota
	// Volume Resource.
	Volume
	// Node Resource.
	Node
	// Cluster Resource.
	Cluster
)

var (
	// ErrNotSupported implemenation of a specific function is not supported.
	ErrNotSupported = errors.New("implementation not supported")
	// ErrNotFound raised if Key is not found.
	ErrNotFound = errors.New("Key not found")
	// ErrExist raised if key already exists.
	ErrExist = errors.New("Key already exists")
	// ErrUnmarshal raised if Get fails to unmarshal value.
	ErrUnmarshal = errors.New("Failed to unmarshal value")
	// ErrIllegal raised if object is not valid.
	ErrIllegal = errors.New("Illegal operation")
	// ErrNotInitialized raised if alerts not initialized.
	ErrNotInitialized = errors.New("Alerts not initialized")
	// ErrAlertsClientNotFound raised if no client implementation found.
	ErrAlertsClientNotFound = errors.New("Alerts client not found")
	// ErrResourceNotFound raised if ResourceType is not found>
	ErrResourceNotFound = errors.New("Resource not found in Alerts")

	instances = make(map[string]AlertsClient)
	drivers   = make(map[string]InitFunc)

	lock sync.RWMutex
)

// AlertAction used to indicate the action performed on a KV pair.
type AlertAction int

// Resource is equaivalent to api.ResourceType and is used in the alerts instance
// so that callers of the instance don't have to worry about api.*
type Resource int

// InitFunc initialization function for alerts.
type InitFunc func(string, string, []string, string) (AlertsClient, error)

// AlertsWatcherFunc is a function type used as a callback for KV WatchTree.
type AlertsWatcherFunc func(*api.Alerts, AlertAction, string, string) error

// AlertsClient interface for Alerts API.
type AlertsClient interface {
	fmt.Stringer

	// Shutdown.
	Shutdown()

	// GetKvdbInstance.
	GetKvdbInstance() kvdb.Kvdb

	// Raise raises an Alerts.
	Raise(alert api.Alerts) (api.Alerts, error)

	// Retrieve retrieves specific Alerts.
	Retrieve(resourceType api.ResourceType, id int64) (api.Alerts, error)

	// Enumerate enumerates Alerts.
	Enumerate(filter api.Alerts) ([]*api.Alerts, error)

	// EnumerateWithinTimeRange enumerates Alertss between timeStart and timeEnd.
	EnumerateWithinTimeRange(timeStart time.Time, timeEnd time.Time, resourceType api.ResourceType) ([]*api.Alerts, error)

	// Erase erases an Alerts.
	Erase(resourceType api.ResourceType, alertID int64) error

	// Clear an Alerts.
	Clear(resourceType api.ResourceType, alertID int64) error

	// Watch on all Alerts>
	Watch(clusterId string, alertsWatcher AlertsWatcherFunc) error
}

type AlertsInstance interface {
	// Clear clears an alert.
	Clear(resource Resource, resourceId string, alertID int64)

	// Alarm raises an alert with severity : ALARM.
	Alarm(name string, msg string, resource Resource, resourceId string) (int64, error)

	// Notify raises an alert with severity : NOTIFY.
	Notify(name string, msg string, resource Resource, resourceId string) (int64, error)

	// Warn raises an alert with severity : WARNING.
	Warn(name string, msg string, resource Resource, resourceId string) (int64, error)

	// Alert :  Keeping this function for backward compatibility
	// until we remove all calls to this function.
	Alert(name string, msg string) error
}

// Shutdown the alerts instance.
func Shutdown() {
	lock.Lock()
	defer lock.Unlock()
	for _, v := range instances {
		v.Shutdown()
	}
}

// Get an alerts instance.
func Get(name string) (AlertsClient, error) {
	lock.RLock()
	defer lock.RUnlock()

	if v, ok := instances[name]; ok {
		return v, nil
	}
	return nil, ErrAlertsClientNotFound
}

// New returns a new alerts instance.
func New(name string, kvdbName string, kvdbBase string, kvdbMachines []string, clusterId string) (AlertsClient, error) {
	lock.Lock()
	defer lock.Unlock()

	if _, ok := instances[name]; ok {
		return nil, ErrExist
	}
	if initFunc, exists := drivers[name]; exists {
		driver, err := initFunc(kvdbName, kvdbBase, kvdbMachines, clusterId)
		if err != nil {
			return nil, err
		}
		instances[name] = driver
		return driver, err
	}
	return nil, ErrNotSupported
}

// NewAlertsInstance creates a new singleton istance of AlertsInstance.
func NewAlertsInstance(version, nodeId, clusterId, kvdbName, kvdbBase string, kvdbMachines []string) {
	kva, err := Get(Name)
	if err != nil {
		kva, err = New(Name, kvdbName, kvdbBase, kvdbMachines, clusterId)
		if err != nil {
			dlog.Errorf("Failed to initialize an AlertsInstance ")
		}
	}
	newAlertsInstance(nodeId, clusterId, version, kva)
}

// Instance returns the singleton AlertsInstance.
func Instance() AlertsInstance {
	return instance()
}

// Register an alerts interface.
func Register(name string, initFunc InitFunc) error {
	lock.Lock()
	defer lock.Unlock()
	if _, exists := drivers[name]; exists {
		return ErrExist
	}
	drivers[name] = initFunc
	return nil
}
<|endoftext|>


<commit_before>package apps

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gexec"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	"github.com/cloudfoundry-incubator/cf-test-helpers/helpers"
	"github.com/cloudfoundry-incubator/cf-test-helpers/runner"
	"github.com/cloudfoundry/cf-acceptance-tests/helpers/app_helpers"
	"github.com/cloudfoundry/cf-acceptance-tests/helpers/assets"
)

var _ = Describe("Wildcard Routes", func() {
	var appNameDora string
	var appNameSimple string
	var domainName string
	var orgName string
	var spaceName string

	curlRoute := func(hostName string, path string) string {
		uri := config.Protocol() + hostName + "." + domainName + path
		curlCmd := runner.CurlSkipSSL(true, uri)

		runner.NewCmdRunner(curlCmd, DEFAULT_TIMEOUT).Run()
		Expect(string(curlCmd.Err.Contents())).To(HaveLen(0))
		return string(curlCmd.Out.Contents())
	}

	BeforeEach(func() {
		orgName = context.RegularUserContext().Org
		spaceName = context.RegularUserContext().Space

		domainName = generator.RandomName() + "." + helpers.LoadConfig().AppsDomain
		cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
			Expect(cf.Cf("create-shared-domain", domainName).Wait(CF_PUSH_TIMEOUT)).To(Exit(0))
		})

		appNameDora = generator.PrefixedRandomName("CATS-APP-")
		Expect(cf.Cf("push", appNameDora, "--no-start", "-b", config.RubyBuildpackName, "-m", DEFAULT_MEMORY_LIMIT, "-p", assets.NewAssets().Dora, "-d", config.AppsDomain).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		app_helpers.SetBackend(appNameDora)
		Expect(cf.Cf("start", appNameDora).Wait(CF_PUSH_TIMEOUT)).To(Exit(0))

		appNameSimple = generator.PrefixedRandomName("CATS-APP-")
		Expect(cf.Cf("push", appNameSimple, "--no-start", "-b", config.RubyBuildpackName, "-m", DEFAULT_MEMORY_LIMIT, "-p", assets.NewAssets().HelloWorld, "-d", config.AppsDomain).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		app_helpers.SetBackend(appNameSimple)
		Expect(cf.Cf("start", appNameSimple).Wait(CF_PUSH_TIMEOUT)).To(Exit(0))
	})

	AfterEach(func() {
		app_helpers.AppReport(appNameDora, DEFAULT_TIMEOUT)
		app_helpers.AppReport(appNameSimple, DEFAULT_TIMEOUT)

		cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
			Expect(cf.Cf("target", "-o", orgName).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
			Expect(cf.Cf("delete-shared-domain", domainName, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		})

		Expect(cf.Cf("delete", appNameDora, "-f", "-r").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		Expect(cf.Cf("delete", appNameSimple, "-f", "-r").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
	})

	Describe("Adding a wildcard route to a domain", func() {
		It("completes successfully", func() {
			wildCardRoute := "*"
			regularRoute := "bar"

			cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
				Expect(cf.Cf("target", "-o", orgName).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
				Expect(cf.Cf("create-route", spaceName, domainName, "-n", wildCardRoute).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
			})
			Expect(cf.Cf("create-route", spaceName, domainName, "-n", regularRoute).Wait(DEFAULT_TIMEOUT)).To(Exit(0))

			Expect(cf.Cf("map-route", appNameDora, domainName, "-n", wildCardRoute).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
			Expect(cf.Cf("map-route", appNameSimple, domainName, "-n", regularRoute).Wait(DEFAULT_TIMEOUT)).To(Exit(0))

			Eventually(func() string {
				return curlRoute(regularRoute, "/")
			}, DEFAULT_TIMEOUT).Should(ContainSubstring("Hello"))

			Eventually(func() string {
				return curlRoute("foo", "/")
			}, DEFAULT_TIMEOUT).Should(ContainSubstring("Hi, I'm Dora!"))

			Eventually(func() string {
				return curlRoute("foo.baz", "/")
			}, DEFAULT_TIMEOUT).Should(ContainSubstring("Hi, I'm Dora!"))
		})
	})
})
<commit_msg>Use CF_PUSH_TIMEOUT when pushing app in wildcard routes test.<commit_after>package apps

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gexec"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	"github.com/cloudfoundry-incubator/cf-test-helpers/helpers"
	"github.com/cloudfoundry-incubator/cf-test-helpers/runner"
	"github.com/cloudfoundry/cf-acceptance-tests/helpers/app_helpers"
	"github.com/cloudfoundry/cf-acceptance-tests/helpers/assets"
)

var _ = Describe("Wildcard Routes", func() {
	var appNameDora string
	var appNameSimple string
	var domainName string
	var orgName string
	var spaceName string

	curlRoute := func(hostName string, path string) string {
		uri := config.Protocol() + hostName + "." + domainName + path
		curlCmd := runner.CurlSkipSSL(true, uri)

		runner.NewCmdRunner(curlCmd, DEFAULT_TIMEOUT).Run()
		Expect(string(curlCmd.Err.Contents())).To(HaveLen(0))
		return string(curlCmd.Out.Contents())
	}

	BeforeEach(func() {
		orgName = context.RegularUserContext().Org
		spaceName = context.RegularUserContext().Space

		domainName = generator.RandomName() + "." + helpers.LoadConfig().AppsDomain
		cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
			Expect(cf.Cf("create-shared-domain", domainName).Wait(CF_PUSH_TIMEOUT)).To(Exit(0))
		})

		appNameDora = generator.PrefixedRandomName("CATS-APP-")
		appNameSimple = generator.PrefixedRandomName("CATS-APP-")

		Expect(cf.Cf(
			"push", appNameDora,
			"--no-start",
			"-b", config.RubyBuildpackName,
			"-m", DEFAULT_MEMORY_LIMIT,
			"-p", assets.NewAssets().Dora,
			"-d", config.AppsDomain,
		).Wait(CF_PUSH_TIMEOUT)).To(Exit(0))

		app_helpers.SetBackend(appNameDora)
		Expect(cf.Cf("start", appNameDora).Wait(CF_PUSH_TIMEOUT)).To(Exit(0))

		Expect(cf.Cf(
			"push", appNameSimple,
			"--no-start",
			"-b", config.RubyBuildpackName,
			"-m", DEFAULT_MEMORY_LIMIT,
			"-p", assets.NewAssets().HelloWorld,
			"-d", config.AppsDomain,
		).Wait(CF_PUSH_TIMEOUT)).To(Exit(0))

		app_helpers.SetBackend(appNameSimple)
		Expect(cf.Cf("start", appNameSimple).Wait(CF_PUSH_TIMEOUT)).To(Exit(0))
	})

	AfterEach(func() {
		app_helpers.AppReport(appNameDora, DEFAULT_TIMEOUT)
		app_helpers.AppReport(appNameSimple, DEFAULT_TIMEOUT)

		cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
			Expect(cf.Cf("target", "-o", orgName).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
			Expect(cf.Cf("delete-shared-domain", domainName, "-f").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		})

		Expect(cf.Cf("delete", appNameDora, "-f", "-r").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		Expect(cf.Cf("delete", appNameSimple, "-f", "-r").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
	})

	Describe("Adding a wildcard route to a domain", func() {
		It("completes successfully", func() {
			wildCardRoute := "*"
			regularRoute := "bar"

			cf.AsUser(context.AdminUserContext(), DEFAULT_TIMEOUT, func() {
				Expect(cf.Cf("target", "-o", orgName).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
				Expect(cf.Cf("create-route", spaceName, domainName, "-n", wildCardRoute).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
			})
			Expect(cf.Cf("create-route", spaceName, domainName, "-n", regularRoute).Wait(DEFAULT_TIMEOUT)).To(Exit(0))

			Expect(cf.Cf("map-route", appNameDora, domainName, "-n", wildCardRoute).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
			Expect(cf.Cf("map-route", appNameSimple, domainName, "-n", regularRoute).Wait(DEFAULT_TIMEOUT)).To(Exit(0))

			Eventually(func() string {
				return curlRoute(regularRoute, "/")
			}, DEFAULT_TIMEOUT).Should(ContainSubstring("Hello"))

			Eventually(func() string {
				return curlRoute("foo", "/")
			}, DEFAULT_TIMEOUT).Should(ContainSubstring("Hi, I'm Dora!"))

			Eventually(func() string {
				return curlRoute("foo.baz", "/")
			}, DEFAULT_TIMEOUT).Should(ContainSubstring("Hi, I'm Dora!"))
		})
	})
})
<|endoftext|>


<commit_before>package cloudcontroller

import (
	"crypto/tls"
	"crypto/x509"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"

	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
)

// CloudControllerConnection represents a connection to the Cloud Controller
// server.
type CloudControllerConnection struct {
	HTTPClient *http.Client
	UserAgent  string
}

// Config is for configuring a CloudControllerConnection.
type Config struct {
	DialTimeout       time.Duration
	SkipSSLValidation bool
}

// NewConnection returns a new CloudControllerConnection with provided
// configuration.
func NewConnection(config Config) *CloudControllerConnection {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: config.SkipSSLValidation,
		},
		Proxy: http.ProxyFromEnvironment,
		DialContext: (&net.Dialer{
			KeepAlive: 30 * time.Second,
			Timeout:   config.DialTimeout,
		}).DialContext,
	}

	return &CloudControllerConnection{
		HTTPClient: &http.Client{Transport: tr},
	}
}

// Make performs the request and parses the response.
func (connection *CloudControllerConnection) Make(request *Request, passedResponse *Response) error {
	// In case this function is called from a retry, passedResponse may already
	// be populated with a previous response. We reset in case there's an HTTP
	// error and we don't repopulate it in populateResponse.
	passedResponse.reset()

	response, err := connection.HTTPClient.Do(request.Request)
	if err != nil {
		return connection.processRequestErrors(request.Request, err)
	}

	return connection.populateResponse(response, passedResponse)
}

func (*CloudControllerConnection) processRequestErrors(request *http.Request, err error) error {
	switch e := err.(type) {
	case *url.Error:
		switch urlErr := e.Err.(type) {
		case x509.UnknownAuthorityError:
			return ccerror.UnverifiedServerError{
				URL: request.URL.String(),
			}
		case x509.HostnameError:
			return ccerror.SSLValidationHostnameError{
				Message: urlErr.Error(),
			}
		default:
			return ccerror.RequestError{Err: e}
		}
	default:
		return err
	}
}

func (connection *CloudControllerConnection) populateResponse(response *http.Response, passedResponse *Response) error {
	passedResponse.HTTPResponse = response

	warnings, err := connection.handleWarnings(response)
	if err != nil {
		return err
	}
	passedResponse.Warnings = warnings

	if resourceLocationURL := response.Header.Get("Location"); resourceLocationURL != "" {
		passedResponse.ResourceLocationURL = resourceLocationURL
	}

	err = connection.handleStatusCodes(response, passedResponse)
	if err != nil {
		return err
	}

	// TODO: only unmarshal on 'application/json', skip otherwise - Fixing this
	// todo will require changing ALL the API tests to include the content-type
	// in their tests.
	if passedResponse.Result != nil {
		err = DecodeJSON(passedResponse.RawResponse, passedResponse.Result)
		if err != nil {
			return err
		}
	}

	return nil
}

// handleWarnings looks for the "X-Cf-Warnings" header in the cloud controller
// response and URI decodes them. The value can contain multiple warnings that
// are comma separated.
func (*CloudControllerConnection) handleWarnings(response *http.Response) ([]string, error) {
	rawWarnings := response.Header.Get("X-Cf-Warnings")
	rawWarnings, err := url.QueryUnescape(rawWarnings)
	if err != nil {
		return nil, err
	}

	var warnings []string
	if rawWarnings != "" {
		for _, warning := range strings.Split(rawWarnings, ",") {
			warningTrimmed := strings.Trim(warning, " ")
			warnings = append(warnings, warningTrimmed)
		}
	}

	return warnings, nil
}

func (*CloudControllerConnection) handleStatusCodes(response *http.Response, passedResponse *Response) error {
	if response.StatusCode == http.StatusNoContent {
		passedResponse.RawResponse = []byte("{}")
	} else {
		rawBytes, err := ioutil.ReadAll(response.Body)
		defer response.Body.Close()
		if err != nil {
			return err
		}

		passedResponse.RawResponse = rawBytes
	}

	if response.StatusCode >= 400 {
		return ccerror.RawHTTPStatusError{
			StatusCode:  response.StatusCode,
			RawResponse: passedResponse.RawResponse,
			RequestIDs:  response.Header["X-Vcap-Request-Id"],
		}
	}

	return nil
}
<commit_msg>reorganizing based on style rules<commit_after>package cloudcontroller

import (
	"crypto/tls"
	"crypto/x509"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"

	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
)

// Config is for configuring a CloudControllerConnection.
type Config struct {
	DialTimeout       time.Duration
	SkipSSLValidation bool
}

// CloudControllerConnection represents a connection to the Cloud Controller
// server.
type CloudControllerConnection struct {
	HTTPClient *http.Client
	UserAgent  string
}

// NewConnection returns a new CloudControllerConnection with provided
// configuration.
func NewConnection(config Config) *CloudControllerConnection {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: config.SkipSSLValidation,
		},
		Proxy: http.ProxyFromEnvironment,
		DialContext: (&net.Dialer{
			KeepAlive: 30 * time.Second,
			Timeout:   config.DialTimeout,
		}).DialContext,
	}

	return &CloudControllerConnection{
		HTTPClient: &http.Client{Transport: tr},
	}
}

// Make performs the request and parses the response.
func (connection *CloudControllerConnection) Make(request *Request, passedResponse *Response) error {
	// In case this function is called from a retry, passedResponse may already
	// be populated with a previous response. We reset in case there's an HTTP
	// error and we don't repopulate it in populateResponse.
	passedResponse.reset()

	response, err := connection.HTTPClient.Do(request.Request)
	if err != nil {
		return connection.processRequestErrors(request.Request, err)
	}

	return connection.populateResponse(response, passedResponse)
}

func (*CloudControllerConnection) handleStatusCodes(response *http.Response, passedResponse *Response) error {
	if response.StatusCode == http.StatusNoContent {
		passedResponse.RawResponse = []byte("{}")
	} else {
		rawBytes, err := ioutil.ReadAll(response.Body)
		defer response.Body.Close()
		if err != nil {
			return err
		}

		passedResponse.RawResponse = rawBytes
	}

	if response.StatusCode >= 400 {
		return ccerror.RawHTTPStatusError{
			StatusCode:  response.StatusCode,
			RawResponse: passedResponse.RawResponse,
			RequestIDs:  response.Header["X-Vcap-Request-Id"],
		}
	}

	return nil
}

// handleWarnings looks for the "X-Cf-Warnings" header in the cloud controller
// response and URI decodes them. The value can contain multiple warnings that
// are comma separated.
func (*CloudControllerConnection) handleWarnings(response *http.Response) ([]string, error) {
	rawWarnings := response.Header.Get("X-Cf-Warnings")
	rawWarnings, err := url.QueryUnescape(rawWarnings)
	if err != nil {
		return nil, err
	}

	var warnings []string
	if rawWarnings != "" {
		for _, warning := range strings.Split(rawWarnings, ",") {
			warningTrimmed := strings.Trim(warning, " ")
			warnings = append(warnings, warningTrimmed)
		}
	}

	return warnings, nil
}

func (connection *CloudControllerConnection) populateResponse(response *http.Response, passedResponse *Response) error {
	passedResponse.HTTPResponse = response

	warnings, err := connection.handleWarnings(response)
	if err != nil {
		return err
	}
	passedResponse.Warnings = warnings

	if resourceLocationURL := response.Header.Get("Location"); resourceLocationURL != "" {
		passedResponse.ResourceLocationURL = resourceLocationURL
	}

	err = connection.handleStatusCodes(response, passedResponse)
	if err != nil {
		return err
	}

	// TODO: only unmarshal on 'application/json', skip otherwise - Fixing this
	// todo will require changing ALL the API tests to include the content-type
	// in their tests.
	if passedResponse.Result != nil {
		err = DecodeJSON(passedResponse.RawResponse, passedResponse.Result)
		if err != nil {
			return err
		}
	}

	return nil
}

func (*CloudControllerConnection) processRequestErrors(request *http.Request, err error) error {
	switch e := err.(type) {
	case *url.Error:
		switch urlErr := e.Err.(type) {
		case x509.UnknownAuthorityError:
			return ccerror.UnverifiedServerError{
				URL: request.URL.String(),
			}
		case x509.HostnameError:
			return ccerror.SSLValidationHostnameError{
				Message: urlErr.Error(),
			}
		default:
			return ccerror.RequestError{Err: e}
		}
	default:
		return err
	}
}
<|endoftext|>