<commit_before>// Package syntaxhighlight provides syntax highlighting for code. It currently
// uses a language-independent lexer and performs decently on JavaScript, Java,
// Ruby, Python, Go, and C.
package syntaxhighlight

import (
	"bufio"
	"bytes"
	"github.com/sourcegraph/annotate"
	"io"
	"text/template"
	"unicode"
)

const (
	WHITESPACE = iota
	STRING
	KEYWORD
	COMMENT
	TYPE
	LITERAL
	PUNCTUATION
	PLAINTEXT
	TAG
	HTMLTAG
	HTMLATTRNAME
	HTMLATTRVALUE
	DECIMAL
)

type Printer interface {
	Print(w io.Writer, tok []byte, kind int) error
}

type HTMLConfig struct {
	String        string
	Keyword       string
	Comment       string
	Type          string
	Literal       string
	Punctuation   string
	Plaintext     string
	Tag           string
	HTMLTag       string
	HTMLAttrName  string
	HTMLAttrValue string
	Decimal       string
}

type HTMLPrinter HTMLConfig

func (c HTMLConfig) class(kind int) string {
	switch kind {
	case STRING:
		return c.String
	case KEYWORD:
		return c.Keyword
	case COMMENT:
		return c.Comment
	case TYPE:
		return c.Type
	case LITERAL:
		return c.Literal
	case PUNCTUATION:
		return c.Punctuation
	case PLAINTEXT:
		return c.Plaintext
	case TAG:
		return c.Tag
	case HTMLTAG:
		return c.HTMLTag
	case HTMLATTRNAME:
		return c.HTMLAttrName
	case HTMLATTRVALUE:
		return c.HTMLAttrValue
	case DECIMAL:
		return c.Decimal
	}
	return ""
}

func (p HTMLPrinter) Print(w io.Writer, tok []byte, kind int) error {
	class := ((HTMLConfig)(p)).class(kind)
	if class != "" {
		_, err := w.Write([]byte(`<span class="`))
		if err != nil {
			return err
		}
		_, err = io.WriteString(w, class)
		if err != nil {
			return err
		}
		_, err = w.Write([]byte(`">`))
		if err != nil {
			return err
		}
	}
	template.HTMLEscape(w, tok)
	if class != "" {
		_, err := w.Write([]byte(`</span>`))
		if err != nil {
			return err
		}
	}
	return nil
}

type Annotator interface {
	Annotate(start int, tok []byte, kind int) (*annotate.Annotation, error)
}

type HTMLAnnotator HTMLConfig

func (a HTMLAnnotator) Annotate(start int, tok []byte, kind int) (*annotate.Annotation, error) {
	class := ((HTMLConfig)(a)).class(kind)
	if class != "" {
		left := []byte(`<span class="`)
		left = append(left, []byte(class)...)
		left = append(left, []byte(`">`)...)
		return &annotate.Annotation{
			Start: start, End: start + len([]rune(string(tok))),
			Left: left, Right: []byte(""),
		}, nil
	}
	return nil, nil
}

// DefaultHTMLConfig's class names match those of
// [google-code-prettify](https://code.google.com/p/google-code-prettify/).
var DefaultHTMLConfig = HTMLConfig{
	String:        "str",
	Keyword:       "kwd",
	Comment:       "com",
	Type:          "typ",
	Literal:       "lit",
	Punctuation:   "pun",
	Plaintext:     "pln",
	Tag:           "tag",
	HTMLTag:       "htm",
	HTMLAttrName:  "atn",
	HTMLAttrValue: "atv",
	Decimal:       "dec",
}

func Print(s *Scanner, w io.Writer, p Printer) error {
	for s.Scan() {
		tok, kind := s.Token()
		err := p.Print(w, tok, kind)
		if err != nil {
			return err
		}
	}

	if err := s.Err(); err != nil {
		return err
	}

	return nil
}

func Annotate(src []byte, a Annotator) ([]*annotate.Annotation, error) {
	s := NewScanner(src)

	var anns []*annotate.Annotation
	read := 0
	for s.Scan() {
		tok, kind := s.Token()
		ann, err := a.Annotate(read, tok, kind)
		if err != nil {
			return nil, err
		}
		read += len([]rune(string(tok)))
		if ann != nil {
			anns = append(anns, ann)
		}
	}

	if err := s.Err(); err != nil {
		return nil, err
	}

	return anns, nil
}

func AsHTML(src []byte) ([]byte, error) {
	var buf bytes.Buffer
	err := Print(NewScanner(src), &buf, HTMLPrinter(DefaultHTMLConfig))
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

type Scanner struct {
	*bufio.Scanner
	kind int
	typ  bool
	name bool
}

func NewScanner(src []byte) *Scanner {
	r := bytes.NewReader(src)
	s := &Scanner{Scanner: bufio.NewScanner(r)}
	s.Split(func(byteData []byte, atEOF bool) (advance int, token []byte, err error) {
		data := []rune(string(byteData))
		if atEOF && len(byteData) == 0 {
			return 0, nil, nil
		}

		//		r, _ := utf8.DecodeRune(data)
		r := data[0]

		retRunes := func(data []rune) (int, []byte, error) {
			seg := []byte(string(data))
			return len(seg), seg, nil
		}

		retBytes := func() (int, []byte, error) {
			return len(byteData), byteData, nil
		}

		isQuot := func(r rune) bool {
			return r == '`' || r == '\'' || r == '"'
		}

		if isQuot(r) {
			s.kind = STRING
			for j := 1; j < len(data); j++ {
				if data[j] == '\\' {
					j++
				} else if data[j] == r {
					return retRunes(data[0 : j+1])
				} else if atEOF {
					return retBytes()
				}
			}
			return 0, nil, nil
		}

		alpha := func(r rune) bool {
			return byte(r) == '_' || unicode.IsLetter(r)
		}
		alnum := func(r rune) bool {
			return alpha(r) || unicode.IsDigit(r)
		}

		if unicode.IsUpper(r) {
			s.typ = true
			s.kind = TYPE
		} else if alpha(r) {
			s.name = true
			s.kind = PLAINTEXT
		}
		if s.typ || s.name {
			i := lastContiguousIndexFunc([]byte(string(data)), alnum)
			if i >= 0 {
				s.typ, s.name = false, false
				if _, isKwd := Keywords[string(data[0:i+1])]; isKwd {
					s.kind = KEYWORD
				}
				return retRunes(data[0 : i+1])
			}
			return 0, nil, nil
		}

		if unicode.IsDigit(r) {
			s.kind = DECIMAL
			i := lastContiguousIndexFunc([]byte(string(data)), unicode.IsDigit)
			if i >= 0 {
				return retRunes(data[:i+1])
			}
			return 0, nil, nil
		}

		if unicode.IsSpace(r) {
			s.kind = WHITESPACE
			i := lastContiguousIndexFunc([]byte(string(data)), unicode.IsSpace)
			if i >= 0 {
				if i+1 <= len(data) {
					return retRunes(data[:i+1])
				} else {
					return retRunes(data)
				}
			}
			if atEOF {
				return retBytes()
			}
			return 0, nil, nil
		}

		lineComments := []string{"//", "#"}
		for _, lc := range lineComments {
			if i := indexRunes(data, string(lc)); i == 0 {
				s.kind = COMMENT
				if i := indexRune(data, '\n'); i >= 0 {
					return retRunes(data[0 : i+1])
				}
				if atEOF {
					return retBytes()
				}
				return 0, nil, nil
			}
		}

		if i := indexRunes(data, "/*"); i == 0 {
			s.kind = COMMENT
			if i := indexRunes(data, "*/"); i >= 0 {
				return retRunes(data[0 : i+2])
			}
			if atEOF {
				return retBytes()
			}
			return 0, nil, nil
		}

		if i := bytes.IndexFunc([]byte(string(data)), func(r rune) bool { return !alnum(r) && !unicode.IsSpace(r) && !isQuot(r) }); i >= 0 {
			s.kind = PUNCTUATION
			return retRunes(data[0 : i+1])
		}

		if atEOF {
			return retBytes()
		}

		return 0, nil, nil
	})
	return s
}

func lastContiguousIndexFunc(s []byte, f func(r rune) bool) int {
	i := bytes.IndexFunc(s, func(r rune) bool {
		return !f(r)
	})
	if i == -1 {
		i = len(s)
	}
	return i - 1
}

func (s *Scanner) Token() ([]byte, int) {
	return s.Bytes(), s.kind
}

func indexRune(src []rune, c rune) int {
	for i, r := range src {
		if r == c {
			return i
		}
	}
	return -1
}

func indexRunes(src []rune, c string) int {
	l := len(src)
	w := len([]rune(c))
	for i := 0; i < l-w; i++ {
		if string(src[i:i+w]) == c {
			return i
		}
	}
	return -1
}
<commit_msg>Revert "fix index out of bound"<commit_after>// Package syntaxhighlight provides syntax highlighting for code. It currently
// uses a language-independent lexer and performs decently on JavaScript, Java,
// Ruby, Python, Go, and C.
package syntaxhighlight

import (
	"bufio"
	"bytes"
	"github.com/sourcegraph/annotate"
	"io"
	"text/template"
	"unicode"
)

const (
	WHITESPACE = iota
	STRING
	KEYWORD
	COMMENT
	TYPE
	LITERAL
	PUNCTUATION
	PLAINTEXT
	TAG
	HTMLTAG
	HTMLATTRNAME
	HTMLATTRVALUE
	DECIMAL
)

type Printer interface {
	Print(w io.Writer, tok []byte, kind int) error
}

type HTMLConfig struct {
	String        string
	Keyword       string
	Comment       string
	Type          string
	Literal       string
	Punctuation   string
	Plaintext     string
	Tag           string
	HTMLTag       string
	HTMLAttrName  string
	HTMLAttrValue string
	Decimal       string
}

type HTMLPrinter HTMLConfig

func (c HTMLConfig) class(kind int) string {
	switch kind {
	case STRING:
		return c.String
	case KEYWORD:
		return c.Keyword
	case COMMENT:
		return c.Comment
	case TYPE:
		return c.Type
	case LITERAL:
		return c.Literal
	case PUNCTUATION:
		return c.Punctuation
	case PLAINTEXT:
		return c.Plaintext
	case TAG:
		return c.Tag
	case HTMLTAG:
		return c.HTMLTag
	case HTMLATTRNAME:
		return c.HTMLAttrName
	case HTMLATTRVALUE:
		return c.HTMLAttrValue
	case DECIMAL:
		return c.Decimal
	}
	return ""
}

func (p HTMLPrinter) Print(w io.Writer, tok []byte, kind int) error {
	class := ((HTMLConfig)(p)).class(kind)
	if class != "" {
		_, err := w.Write([]byte(`<span class="`))
		if err != nil {
			return err
		}
		_, err = io.WriteString(w, class)
		if err != nil {
			return err
		}
		_, err = w.Write([]byte(`">`))
		if err != nil {
			return err
		}
	}
	template.HTMLEscape(w, tok)
	if class != "" {
		_, err := w.Write([]byte(`</span>`))
		if err != nil {
			return err
		}
	}
	return nil
}

type Annotator interface {
	Annotate(start int, tok []byte, kind int) (*annotate.Annotation, error)
}

type HTMLAnnotator HTMLConfig

func (a HTMLAnnotator) Annotate(start int, tok []byte, kind int) (*annotate.Annotation, error) {
	class := ((HTMLConfig)(a)).class(kind)
	if class != "" {
		left := []byte(`<span class="`)
		left = append(left, []byte(class)...)
		left = append(left, []byte(`">`)...)
		return &annotate.Annotation{
			Start: start, End: start + len([]rune(string(tok))),
			Left: left, Right: []byte(""),
		}, nil
	}
	return nil, nil
}

// DefaultHTMLConfig's class names match those of
// [google-code-prettify](https://code.google.com/p/google-code-prettify/).
var DefaultHTMLConfig = HTMLConfig{
	String:        "str",
	Keyword:       "kwd",
	Comment:       "com",
	Type:          "typ",
	Literal:       "lit",
	Punctuation:   "pun",
	Plaintext:     "pln",
	Tag:           "tag",
	HTMLTag:       "htm",
	HTMLAttrName:  "atn",
	HTMLAttrValue: "atv",
	Decimal:       "dec",
}

func Print(s *Scanner, w io.Writer, p Printer) error {
	for s.Scan() {
		tok, kind := s.Token()
		err := p.Print(w, tok, kind)
		if err != nil {
			return err
		}
	}

	if err := s.Err(); err != nil {
		return err
	}

	return nil
}

func Annotate(src []byte, a Annotator) ([]*annotate.Annotation, error) {
	s := NewScanner(src)

	var anns []*annotate.Annotation
	read := 0
	for s.Scan() {
		tok, kind := s.Token()
		ann, err := a.Annotate(read, tok, kind)
		if err != nil {
			return nil, err
		}
		read += len([]rune(string(tok)))
		if ann != nil {
			anns = append(anns, ann)
		}
	}

	if err := s.Err(); err != nil {
		return nil, err
	}

	return anns, nil
}

func AsHTML(src []byte) ([]byte, error) {
	var buf bytes.Buffer
	err := Print(NewScanner(src), &buf, HTMLPrinter(DefaultHTMLConfig))
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

type Scanner struct {
	*bufio.Scanner
	kind int
	typ  bool
	name bool
}

func NewScanner(src []byte) *Scanner {
	r := bytes.NewReader(src)
	s := &Scanner{Scanner: bufio.NewScanner(r)}
	s.Split(func(byteData []byte, atEOF bool) (advance int, token []byte, err error) {
		data := []rune(string(byteData))
		if atEOF && len(byteData) == 0 {
			return 0, nil, nil
		}

		//		r, _ := utf8.DecodeRune(data)
		r := data[0]

		retRunes := func(data []rune) (int, []byte, error) {
			seg := []byte(string(data))
			return len(seg), seg, nil
		}

		retBytes := func() (int, []byte, error) {
			return len(byteData), byteData, nil
		}

		isQuot := func(r rune) bool {
			return r == '`' || r == '\'' || r == '"'
		}

		if isQuot(r) {
			s.kind = STRING
			for j := 1; j < len(data); j++ {
				if data[j] == '\\' {
					j++
				} else if data[j] == r {
					return retRunes(data[0 : j+1])
				} else if atEOF {
					return retBytes()
				}
			}
			return 0, nil, nil
		}

		alpha := func(r rune) bool {
			return byte(r) == '_' || unicode.IsLetter(r)
		}
		alnum := func(r rune) bool {
			return alpha(r) || unicode.IsDigit(r)
		}

		if unicode.IsUpper(r) {
			s.typ = true
			s.kind = TYPE
		} else if alpha(r) {
			s.name = true
			s.kind = PLAINTEXT
		}
		if s.typ || s.name {
			i := lastContiguousIndexFunc([]byte(string(data)), alnum)
			if i >= 0 {
				s.typ, s.name = false, false
				if _, isKwd := Keywords[string(data[0:i+1])]; isKwd {
					s.kind = KEYWORD
				}
				return retRunes(data[0 : i+1])
			}
			return 0, nil, nil
		}

		if unicode.IsDigit(r) {
			s.kind = DECIMAL
			i := lastContiguousIndexFunc([]byte(string(data)), unicode.IsDigit)
			if i >= 0 {
				return retRunes(data[:i+1])
			}
			return 0, nil, nil
		}

		if unicode.IsSpace(r) {
			s.kind = WHITESPACE
			i := lastContiguousIndexFunc([]byte(string(data)), unicode.IsSpace)
			if i >= 0 {
				return retRunes(data[:i+1])
			}
			if atEOF {
				return retBytes()
			}
			return 0, nil, nil
		}

		lineComments := []string{"//", "#"}
		for _, lc := range lineComments {
			if i := indexRunes(data, string(lc)); i == 0 {
				s.kind = COMMENT
				if i := indexRune(data, '\n'); i >= 0 {
					return retRunes(data[0 : i+1])
				}
				if atEOF {
					return retBytes()
				}
				return 0, nil, nil
			}
		}

		if i := indexRunes(data, "/*"); i == 0 {
			s.kind = COMMENT
			if i := indexRunes(data, "*/"); i >= 0 {
				return retRunes(data[0 : i+2])
			}
			if atEOF {
				return retBytes()
			}
			return 0, nil, nil
		}

		if i := bytes.IndexFunc([]byte(string(data)), func(r rune) bool { return !alnum(r) && !unicode.IsSpace(r) && !isQuot(r) }); i >= 0 {
			s.kind = PUNCTUATION
			return retRunes(data[0 : i+1])
		}

		if atEOF {
			return retBytes()
		}

		return 0, nil, nil
	})
	return s
}

func lastContiguousIndexFunc(s []byte, f func(r rune) bool) int {
	i := bytes.IndexFunc(s, func(r rune) bool {
		return !f(r)
	})
	if i == -1 {
		i = len(s)
	}
	return i - 1
}

func (s *Scanner) Token() ([]byte, int) {
	return s.Bytes(), s.kind
}

func indexRune(src []rune, c rune) int {
	for i, r := range src {
		if r == c {
			return i
		}
	}
	return -1
}

func indexRunes(src []rune, c string) int {
	l := len(src)
	w := len([]rune(c))
	for i := 0; i < l-w; i++ {
		if string(src[i:i+w]) == c {
			return i
		}
	}
	return -1
}
<|endoftext|>


<commit_before>package dnsclient

import (
	"errors"
	"fmt"
	"path"
	"strings"

	"koding/kites/kloud/api/amazon"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/service/route53"
	"github.com/dchest/validator"
	"github.com/koding/logging"
)

var ErrNoRecord = errors.New("no records available")

type Route53 struct {
	*route53.Route53
	hostedZone string
	ZoneId     string
	Log        logging.Logger
}

// NewRoute53Client initializes a new DNSClient interface instance based on AWS Route53
func NewRoute53Client(c *credentials.Credentials, hostedZone string) *Route53 {
	opts := &amazon.ClientOptions{
		Credentials: c,
		Region:      "us-east-1", // our route53 is based on this region, so we use it
		Log:         logging.NewLogger("kloud-dns"),
	}
	dns := route53.New(amazon.NewSession(opts))
	params := &route53.ListHostedZonesInput{
		MaxItems: aws.String("100"),
	}
	hostedZones, err := dns.ListHostedZones(params)
	if err != nil {
		panic(err)
	}

	var zoneId string
	var dnsName = hostedZone + "." // DNS name ends with a ".", e.g. "dev.koding.io."
	for _, h := range hostedZones.HostedZones {
		if aws.StringValue(h.Name) == dnsName {
			// The h.Id looks like "/hostedzone/Z2T644TMIB2JZM", we're interested
			// only in the last part - "Z2T644TMIB2JZM".
			if s := aws.StringValue(h.Id); s != "" {
				zoneId = path.Base(s)
			}
		}
	}

	if zoneId == "" {
		panic(fmt.Sprintf("Hosted zone with the name '%s' doesn't exist", hostedZone))
	}

	return &Route53{
		Route53:    dns,
		hostedZone: hostedZone,
		ZoneId:     zoneId,
		Log:        opts.Log,
	}
}

// Upsert creates or updates a the domain record with the given ip address. If
// the record already exists, the record is updated with the new IP.
func (r *Route53) Upsert(domain string, newIP string) error {
	r.Log.Debug("upserting domain name: %s to be associated with following ip: %v", domain, newIP)
	params := &route53.ChangeResourceRecordSetsInput{
		HostedZoneId: aws.String(r.ZoneId),
		ChangeBatch: &route53.ChangeBatch{
			Comment: aws.String("Upserting domain"),
			Changes: []*route53.Change{{
				Action: aws.String("UPSERT"),
				ResourceRecordSet: &route53.ResourceRecordSet{
					Name: aws.String(domain),
					Type: aws.String("A"),
					TTL:  aws.Int64(30),
					ResourceRecords: []*route53.ResourceRecord{{
						Value: aws.String(newIP),
					}},
				},
			}},
		},
	}
	_, err := r.ChangeResourceRecordSets(params)
	if err != nil {
		return r.errorf("could not upsert domain %q: %v", domain, err)
	}
	return nil
}

// Domain retrieves the record set for the given domain name
func (r *Route53) Get(domain string) (*Record, error) {
	r.Log.Debug("fetching domain record for domain: %s", domain)
	resp, err := r.get(domain)
	if err != nil {
		return nil, r.error(err)
	}

	var dnsName = domain + "." // DNS name ends with a ".", e.g. "dev.koding.io."
	for _, r := range resp {
		if aws.StringValue(r.Name) == dnsName {
			return &Record{
				Name: aws.StringValue(r.Name),
				IP:   aws.StringValue(r.ResourceRecords[0].Value),
				TTL:  int(aws.Int64Value(r.TTL)),
			}, nil
		}
	}

	return nil, r.error(ErrNoRecord)
}

// GetAll retrieves all records from the hostedzone. Because of the limitation
// of Route53 it only returns up to 100 records. Subsequent calls retrieve the
// first 100.
func (r *Route53) GetAll(name string) ([]*Record, error) {
	r.Log.Debug("fetching domain records for name: %s", name)
	resp, err := r.get(name)
	if err != nil {
		return nil, r.error(err)
	}

	records := make([]*Record, len(resp))

	for i, r := range resp {
		records[i] = &Record{
			Name: aws.StringValue(r.Name),
			IP:   aws.StringValue(r.ResourceRecords[0].Value),
			TTL:  int(aws.Int64Value(r.TTL)),
		}
	}

	return records, nil
}

func (r *Route53) get(name string) ([]*route53.ResourceRecordSet, error) {
	params := &route53.ListResourceRecordSetsInput{
		HostedZoneId: aws.String(r.ZoneId),
	}
	if name != "" {
		params.StartRecordName = aws.String(name)
	}
	resp, err := r.ListResourceRecordSets(params)
	if err != nil {
		return nil, fmt.Errorf("could not fetch records for name %q: %s", name, err)
	}
	if len(resp.ResourceRecordSets) == 0 {
		return nil, ErrNoRecord
	}
	return resp.ResourceRecordSets, nil
}

// Rename changes the domain from oldDomain to newDomain in a single transaction
func (r *Route53) Rename(oldDomain, newDomain string) error {
	record, err := r.Get(oldDomain)
	if err != nil {
		return err
	}
	r.Log.Debug("updating domain name of IP %s from %q to %q", record.IP, oldDomain, newDomain)
	params := &route53.ChangeResourceRecordSetsInput{
		HostedZoneId: aws.String(r.ZoneId),
		ChangeBatch: &route53.ChangeBatch{
			Comment: aws.String("Renaming domain"),
			Changes: []*route53.Change{{
				Action: aws.String("DELETE"),
				ResourceRecordSet: &route53.ResourceRecordSet{
					Name: aws.String(oldDomain),
					Type: aws.String("A"),
					TTL:  aws.Int64(int64(record.TTL)),
					ResourceRecords: []*route53.ResourceRecord{{
						Value: aws.String(record.IP),
					}},
				},
			}, {
				Action: aws.String("UPSERT"),
				ResourceRecordSet: &route53.ResourceRecordSet{
					Name: aws.String(newDomain),
					Type: aws.String("A"),
					TTL:  aws.Int64(int64(record.TTL)),
					ResourceRecords: []*route53.ResourceRecord{{
						Value: aws.String(record.IP),
					}},
				},
			}},
		},
	}
	if _, err = r.ChangeResourceRecordSets(params); err != nil {
		return r.errorf("could not rename domain %q to %q: %s", oldDomain, newDomain, err)
	}
	return nil
}

// DeleteDomain deletes a domain record for the given domain
func (r *Route53) Delete(domain string) error {
	// fetch correct TTL value, instead of relying on a hardcoded value for TTL
	// and IP
	record, err := r.Get(domain)
	if err != nil {
		return err
	}
	r.Log.Debug("deleting domain name: %s which was associated to following ip: %s", domain, record.IP)
	params := &route53.ChangeResourceRecordSetsInput{
		HostedZoneId: aws.String(r.ZoneId),
		ChangeBatch: &route53.ChangeBatch{
			Comment: aws.String("Renaming domain"),
			Changes: []*route53.Change{{
				Action: aws.String("DELETE"),
				ResourceRecordSet: &route53.ResourceRecordSet{
					Name: aws.String(domain),
					Type: aws.String("A"),
					TTL:  aws.Int64(int64(record.TTL)),
					ResourceRecords: []*route53.ResourceRecord{{
						Value: aws.String(record.IP),
					}},
				},
			}},
		},
	}
	if _, err = r.ChangeResourceRecordSets(params); err != nil {
		return r.errorf("could not delete domain %q: %s", domain, err)
	}
	return nil
}

func (r *Route53) HostedZone() string {
	return r.hostedZone
}

func (r *Route53) Validate(domain, username string) error {
	hostedZone := r.hostedZone

	if domain == "" {
		return r.errorf("Domain name argument is empty")
	}

	if domain == hostedZone {
		return r.errorf("Domain '%s' can't be the same as top-level domain '%s'", domain, hostedZone)
	}

	if !strings.Contains(domain, hostedZone) {
		return r.errorf("Domain doesn't contain hostedzone '%s'", hostedZone)
	}

	rest := strings.TrimSuffix(domain, "."+hostedZone)
	if rest == domain {
		return r.errorf("Domain is invalid (1) '%s'", domain)
	}

	if split := strings.Split(rest, "."); split[len(split)-1] != username {
		return r.errorf("Domain doesn't contain username '%s'", username)
	}

	if !validator.IsValidDomain(domain) {
		return r.errorf("Domain is invalid (2) '%s'", domain)
	}

	return nil
}

func (r *Route53) errorf(format string, v ...interface{}) error {
	err := fmt.Errorf(format, v...)
	r.Log.Error(err.Error())
	return err
}

func (r *Route53) error(err error) error {
	r.Log.Error(err.Error())
	return err
}
<commit_msg>kloud: fix log for nonexisting records<commit_after>package dnsclient

import (
	"errors"
	"fmt"
	"path"
	"strings"

	"koding/kites/kloud/api/amazon"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/service/route53"
	"github.com/dchest/validator"
	"github.com/koding/logging"
)

var ErrNoRecord = errors.New("no records available")

type Route53 struct {
	*route53.Route53
	hostedZone string
	ZoneId     string
	Log        logging.Logger
}

// NewRoute53Client initializes a new DNSClient interface instance based on AWS Route53
func NewRoute53Client(c *credentials.Credentials, hostedZone string) *Route53 {
	opts := &amazon.ClientOptions{
		Credentials: c,
		Region:      "us-east-1", // our route53 is based on this region, so we use it
		Log:         logging.NewLogger("kloud-dns"),
	}
	dns := route53.New(amazon.NewSession(opts))
	params := &route53.ListHostedZonesInput{
		MaxItems: aws.String("100"),
	}
	hostedZones, err := dns.ListHostedZones(params)
	if err != nil {
		panic(err)
	}

	var zoneId string
	var dnsName = hostedZone + "." // DNS name ends with a ".", e.g. "dev.koding.io."
	for _, h := range hostedZones.HostedZones {
		if aws.StringValue(h.Name) == dnsName {
			// The h.Id looks like "/hostedzone/Z2T644TMIB2JZM", we're interested
			// only in the last part - "Z2T644TMIB2JZM".
			if s := aws.StringValue(h.Id); s != "" {
				zoneId = path.Base(s)
			}
		}
	}

	if zoneId == "" {
		panic(fmt.Sprintf("Hosted zone with the name '%s' doesn't exist", hostedZone))
	}

	return &Route53{
		Route53:    dns,
		hostedZone: hostedZone,
		ZoneId:     zoneId,
		Log:        opts.Log,
	}
}

// Upsert creates or updates a the domain record with the given ip address. If
// the record already exists, the record is updated with the new IP.
func (r *Route53) Upsert(domain string, newIP string) error {
	r.Log.Debug("upserting domain name: %s to be associated with following ip: %v", domain, newIP)
	params := &route53.ChangeResourceRecordSetsInput{
		HostedZoneId: aws.String(r.ZoneId),
		ChangeBatch: &route53.ChangeBatch{
			Comment: aws.String("Upserting domain"),
			Changes: []*route53.Change{{
				Action: aws.String("UPSERT"),
				ResourceRecordSet: &route53.ResourceRecordSet{
					Name: aws.String(domain),
					Type: aws.String("A"),
					TTL:  aws.Int64(30),
					ResourceRecords: []*route53.ResourceRecord{{
						Value: aws.String(newIP),
					}},
				},
			}},
		},
	}
	_, err := r.ChangeResourceRecordSets(params)
	if err != nil {
		return r.errorf("could not upsert domain %q: %v", domain, err)
	}
	return nil
}

// Domain retrieves the record set for the given domain name
func (r *Route53) Get(domain string) (*Record, error) {
	r.Log.Debug("fetching domain record for domain: %s", domain)
	resp, err := r.get(domain)
	if err != nil {
		return nil, r.error(err)
	}

	var dnsName = domain + "." // DNS name ends with a ".", e.g. "dev.koding.io."
	for _, r := range resp {
		if aws.StringValue(r.Name) == dnsName {
			return &Record{
				Name: aws.StringValue(r.Name),
				IP:   aws.StringValue(r.ResourceRecords[0].Value),
				TTL:  int(aws.Int64Value(r.TTL)),
			}, nil
		}
	}

	return nil, r.error(ErrNoRecord)
}

// GetAll retrieves all records from the hostedzone. Because of the limitation
// of Route53 it only returns up to 100 records. Subsequent calls retrieve the
// first 100.
func (r *Route53) GetAll(name string) ([]*Record, error) {
	r.Log.Debug("fetching domain records for name: %s", name)
	resp, err := r.get(name)
	if err != nil {
		return nil, r.error(err)
	}

	records := make([]*Record, len(resp))

	for i, r := range resp {
		records[i] = &Record{
			Name: aws.StringValue(r.Name),
			IP:   aws.StringValue(r.ResourceRecords[0].Value),
			TTL:  int(aws.Int64Value(r.TTL)),
		}
	}

	return records, nil
}

func (r *Route53) get(name string) ([]*route53.ResourceRecordSet, error) {
	params := &route53.ListResourceRecordSetsInput{
		HostedZoneId: aws.String(r.ZoneId),
	}
	if name != "" {
		params.StartRecordName = aws.String(name)
	}
	resp, err := r.ListResourceRecordSets(params)
	if err != nil {
		return nil, fmt.Errorf("could not fetch records for name %q: %s", name, err)
	}
	if len(resp.ResourceRecordSets) == 0 {
		return nil, ErrNoRecord
	}
	return resp.ResourceRecordSets, nil
}

// Rename changes the domain from oldDomain to newDomain in a single transaction
func (r *Route53) Rename(oldDomain, newDomain string) error {
	record, err := r.Get(oldDomain)
	if err != nil {
		return err
	}
	r.Log.Debug("updating domain name of IP %s from %q to %q", record.IP, oldDomain, newDomain)
	params := &route53.ChangeResourceRecordSetsInput{
		HostedZoneId: aws.String(r.ZoneId),
		ChangeBatch: &route53.ChangeBatch{
			Comment: aws.String("Renaming domain"),
			Changes: []*route53.Change{{
				Action: aws.String("DELETE"),
				ResourceRecordSet: &route53.ResourceRecordSet{
					Name: aws.String(oldDomain),
					Type: aws.String("A"),
					TTL:  aws.Int64(int64(record.TTL)),
					ResourceRecords: []*route53.ResourceRecord{{
						Value: aws.String(record.IP),
					}},
				},
			}, {
				Action: aws.String("UPSERT"),
				ResourceRecordSet: &route53.ResourceRecordSet{
					Name: aws.String(newDomain),
					Type: aws.String("A"),
					TTL:  aws.Int64(int64(record.TTL)),
					ResourceRecords: []*route53.ResourceRecord{{
						Value: aws.String(record.IP),
					}},
				},
			}},
		},
	}
	if _, err = r.ChangeResourceRecordSets(params); err != nil {
		return r.errorf("could not rename domain %q to %q: %s", oldDomain, newDomain, err)
	}
	return nil
}

// DeleteDomain deletes a domain record for the given domain
func (r *Route53) Delete(domain string) error {
	// fetch correct TTL value, instead of relying on a hardcoded value for TTL
	// and IP
	record, err := r.Get(domain)
	if err != nil {
		// domains can be removed via other bussiness logics, so this can
		// happen
		if err == ErrNoRecord {
			return nil
		}
		return err
	}
	r.Log.Debug("deleting domain name: %s which was associated to following ip: %s", domain, record.IP)
	params := &route53.ChangeResourceRecordSetsInput{
		HostedZoneId: aws.String(r.ZoneId),
		ChangeBatch: &route53.ChangeBatch{
			Comment: aws.String("Renaming domain"),
			Changes: []*route53.Change{{
				Action: aws.String("DELETE"),
				ResourceRecordSet: &route53.ResourceRecordSet{
					Name: aws.String(domain),
					Type: aws.String("A"),
					TTL:  aws.Int64(int64(record.TTL)),
					ResourceRecords: []*route53.ResourceRecord{{
						Value: aws.String(record.IP),
					}},
				},
			}},
		},
	}
	if _, err = r.ChangeResourceRecordSets(params); err != nil {
		return r.errorf("could not delete domain %q: %s", domain, err)
	}
	return nil
}

func (r *Route53) HostedZone() string {
	return r.hostedZone
}

func (r *Route53) Validate(domain, username string) error {
	hostedZone := r.hostedZone

	if domain == "" {
		return r.errorf("Domain name argument is empty")
	}

	if domain == hostedZone {
		return r.errorf("Domain '%s' can't be the same as top-level domain '%s'", domain, hostedZone)
	}

	if !strings.Contains(domain, hostedZone) {
		return r.errorf("Domain doesn't contain hostedzone '%s'", hostedZone)
	}

	rest := strings.TrimSuffix(domain, "."+hostedZone)
	if rest == domain {
		return r.errorf("Domain is invalid (1) '%s'", domain)
	}

	if split := strings.Split(rest, "."); split[len(split)-1] != username {
		return r.errorf("Domain doesn't contain username '%s'", username)
	}

	if !validator.IsValidDomain(domain) {
		return r.errorf("Domain is invalid (2) '%s'", domain)
	}

	return nil
}

func (r *Route53) errorf(format string, v ...interface{}) error {
	err := fmt.Errorf(format, v...)
	r.Log.Error(err.Error())
	return err
}

func (r *Route53) error(err error) error {
	r.Log.Error(err.Error())
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/flynn/flynn/Godeps/_workspace/src/github.com/flynn/go-docopt"
	"github.com/flynn/flynn/Godeps/_workspace/src/github.com/technoweenie/grohl"
	"github.com/flynn/flynn/bootstrap/discovery"
	"github.com/flynn/flynn/host/cli"
	"github.com/flynn/flynn/host/config"
	"github.com/flynn/flynn/host/logmux"
	"github.com/flynn/flynn/host/volume"
	"github.com/flynn/flynn/host/volume/manager"
	zfsVolume "github.com/flynn/flynn/host/volume/zfs"
	"github.com/flynn/flynn/pkg/cluster"
	"github.com/flynn/flynn/pkg/shutdown"
	"github.com/flynn/flynn/pkg/version"
)

const configFile = "/etc/flynn/host.json"

func init() {
	log.SetFlags(log.Lshortfile | log.Lmicroseconds)

	cli.Register("daemon", runDaemon, `
usage: flynn-host daemon [options]

options:
  --external-ip=IP       external IP of host
  --state=PATH           path to state file [default: /var/lib/flynn/host-state.bolt]
  --id=ID                host id
  --force                kill all containers booted by flynn-host before starting
  --volpath=PATH         directory to create volumes in [default: /var/lib/flynn/volumes]
  --backend=BACKEND      runner backend [default: libvirt-lxc]
  --flynn-init=PATH      path to flynn-init binary [default: /usr/local/bin/flynn-init]
  --nsumount=PATH        path to flynn-nsumount binary [default: /usr/local/bin/flynn-nsumount]
  --log-dir=DIR          directory to store job logs [default: /var/log/flynn]
  --discovery=TOKEN      join cluster with discovery token
  --peer-ips=IPLIST      join existing cluster using IPs
	`)
}

func main() {
	defer shutdown.Exit()

	usage := `usage: flynn-host [-h|--help] [--version] <command> [<args>...]

Options:
  -h, --help                 Show this message
  --version                  Show current version

Commands:
  help                       Show usage for a specific command
  init                       Create cluster configuration for daemon
  daemon                     Start the daemon
  update                     Update Flynn components
  download                   Download container images
  bootstrap                  Bootstrap layer 1
  inspect                    Get low-level information about a job
  log                        Get the logs of a job
  ps                         List jobs
  stop                       Stop running jobs
  destroy-volumes            Destroys the local volume database
  collect-debug-info         Collect debug information into an anonymous gist or tarball
  version                    Show current version

See 'flynn-host help <command>' for more information on a specific command.
`

	args, _ := docopt.Parse(usage, nil, true, version.String(), true)
	cmd := args.String["<command>"]
	cmdArgs := args.All["<args>"].([]string)

	if cmd == "help" {
		if len(cmdArgs) == 0 { // `flynn help`
			fmt.Println(usage)
			return
		} else { // `flynn help <command>`
			cmd = cmdArgs[0]
			cmdArgs = []string{"--help"}
		}
	}

	if cmd == "daemon" {
		// merge in args and env from config file, if available
		var c *config.Config
		if n := os.Getenv("FLYNN_HOST_CONFIG"); n != "" {
			var err error
			c, err = config.Open(n)
			if err != nil {
				log.Fatalf("error opening config file %s: %s", n, err)
			}
		} else {
			var err error
			c, err = config.Open(configFile)
			if err != nil && !os.IsNotExist(err) {
				log.Fatalf("error opening config file %s: %s", configFile, err)
			}
			if c == nil {
				c = &config.Config{}
			}
		}
		cmdArgs = append(cmdArgs, c.Args...)
		for k, v := range c.Env {
			os.Setenv(k, v)
		}
	}

	if err := cli.Run(cmd, cmdArgs); err != nil {
		if err == cli.ErrInvalidCommand {
			fmt.Printf("ERROR: %q is not a valid command\n\n", cmd)
			fmt.Println(usage)
			shutdown.ExitWithCode(1)
		}
		shutdown.Fatal(err)
	}
}

func runDaemon(args *docopt.Args) {
	hostname, _ := os.Hostname()
	externalIP := args.String["--external-ip"]
	stateFile := args.String["--state"]
	hostID := args.String["--id"]
	force := args.Bool["--force"]
	volPath := args.String["--volpath"]
	backendName := args.String["--backend"]
	flynnInit := args.String["--flynn-init"]
	nsumount := args.String["--nsumount"]
	logDir := args.String["--log-dir"]
	discoveryToken := args.String["--discovery"]
	peerIPs := strings.Split(args.String["--peer-ips"], ",")

	grohl.AddContext("app", "host")
	grohl.Log(grohl.Data{"at": "start"})
	g := grohl.NewContext(grohl.Data{"fn": "main"})

	if hostID == "" {
		hostID = strings.Replace(hostname, "-", "", -1)
	}
	if strings.Contains(hostID, "-") {
		shutdown.Fatal("host id must not contain dashes")
	}
	if externalIP == "" {
		var err error
		externalIP, err = config.DefaultExternalIP()
		if err != nil {
			shutdown.Fatal(err)
		}
	}

	publishAddr := externalIP + ":1113"
	if discoveryToken != "" {
		// TODO: retry
		discoveryID, err := discovery.RegisterInstance(discovery.Info{
			ClusterURL:  discoveryToken,
			InstanceURL: "http://" + publishAddr,
			Name:        hostID,
		})
		if err != nil {
			g.Log(grohl.Data{"at": "register_discovery", "status": "error", "err": err.Error()})
			shutdown.Fatal(err)
		}
		g.Log(grohl.Data{"at": "register_discovery", "id": discoveryID})
	}

	state := NewState(hostID, stateFile)
	var backend Backend
	var err error

	// create volume manager
	vman, err := volumemanager.New(
		filepath.Join(volPath, "volumes.bolt"),
		func() (volume.Provider, error) {
			// use a zpool backing file size of either 70% of the device on which
			// volumes will reside, or 100GB if that can't be determined.
			var size int64
			var dev syscall.Statfs_t
			if err := syscall.Statfs(volPath, &dev); err == nil {
				size = (dev.Bsize * int64(dev.Blocks) * 7) / 10
			} else {
				size = 100000000000
			}
			g.Log(grohl.Data{"at": "zpool_size", "size": size})

			return zfsVolume.NewProvider(&zfsVolume.ProviderConfig{
				DatasetName: "flynn-default",
				Make: &zfsVolume.MakeDev{
					BackingFilename: filepath.Join(volPath, "zfs/vdev/flynn-default-zpool.vdev"),
					Size:            size,
				},
				WorkingDir: filepath.Join(volPath, "zfs"),
			})
		},
	)
	if err != nil {
		shutdown.Fatal(err)
	}

	mux := logmux.New(1000)
	shutdown.BeforeExit(func() { mux.Close() })

	switch backendName {
	case "libvirt-lxc":
		backend, err = NewLibvirtLXCBackend(state, vman, logDir, flynnInit, nsumount, mux)
	default:
		log.Fatalf("unknown backend %q", backendName)
	}
	if err != nil {
		shutdown.Fatal(err)
	}
	backend.SetDefaultEnv("EXTERNAL_IP", externalIP)

	resurrect, err := state.Restore(backend)
	if err != nil {
		shutdown.Fatal(err)
	}
	shutdown.BeforeExit(func() { backend.Cleanup() })
	shutdown.BeforeExit(func() {
		if err := state.MarkForResurrection(); err != nil {
			log.Print("error marking for resurrection", err)
		}
	})

	discoverdManager := NewDiscoverdManager(backend, mux, hostID, publishAddr)
	if err := serveHTTP(
		&Host{
			id:      hostID,
			url:     "http://" + publishAddr,
			state:   state,
			backend: backend,
		},
		&attachHandler{state: state, backend: backend},
		cluster.NewClient(),
		vman,
		discoverdManager.ConnectLocal,
	); err != nil {
		shutdown.Fatal(err)
	}

	if force {
		if err := backend.Cleanup(); err != nil {
			shutdown.Fatal(err)
		}
	}

	if discoveryToken != "" {
		instances, err := discovery.GetCluster(discoveryToken)
		if err != nil {
			// TODO(titanous): retry?
			shutdown.Fatal(err)
		}
		peerIPs = make([]string, 0, len(instances))
		for _, inst := range instances {
			u, err := url.Parse(inst.URL)
			if err != nil {
				continue
			}
			ip, _, err := net.SplitHostPort(u.Host)
			if err != nil || ip == externalIP {
				continue
			}
			peerIPs = append(peerIPs, ip)
		}
	}
	if err := discoverdManager.ConnectPeer(peerIPs); err != nil {
		// No peers have working discoverd, so resurrect any available jobs
		resurrect()
	}

	<-make(chan struct{})
}
<commit_msg>host: Use net.JoinHostPort<commit_after>package main

import (
	"fmt"
	"log"
	"net"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/flynn/flynn/Godeps/_workspace/src/github.com/flynn/go-docopt"
	"github.com/flynn/flynn/Godeps/_workspace/src/github.com/technoweenie/grohl"
	"github.com/flynn/flynn/bootstrap/discovery"
	"github.com/flynn/flynn/host/cli"
	"github.com/flynn/flynn/host/config"
	"github.com/flynn/flynn/host/logmux"
	"github.com/flynn/flynn/host/volume"
	"github.com/flynn/flynn/host/volume/manager"
	zfsVolume "github.com/flynn/flynn/host/volume/zfs"
	"github.com/flynn/flynn/pkg/cluster"
	"github.com/flynn/flynn/pkg/shutdown"
	"github.com/flynn/flynn/pkg/version"
)

const configFile = "/etc/flynn/host.json"

func init() {
	log.SetFlags(log.Lshortfile | log.Lmicroseconds)

	cli.Register("daemon", runDaemon, `
usage: flynn-host daemon [options]

options:
  --external-ip=IP       external IP of host
  --state=PATH           path to state file [default: /var/lib/flynn/host-state.bolt]
  --id=ID                host id
  --force                kill all containers booted by flynn-host before starting
  --volpath=PATH         directory to create volumes in [default: /var/lib/flynn/volumes]
  --backend=BACKEND      runner backend [default: libvirt-lxc]
  --flynn-init=PATH      path to flynn-init binary [default: /usr/local/bin/flynn-init]
  --nsumount=PATH        path to flynn-nsumount binary [default: /usr/local/bin/flynn-nsumount]
  --log-dir=DIR          directory to store job logs [default: /var/log/flynn]
  --discovery=TOKEN      join cluster with discovery token
  --peer-ips=IPLIST      join existing cluster using IPs
	`)
}

func main() {
	defer shutdown.Exit()

	usage := `usage: flynn-host [-h|--help] [--version] <command> [<args>...]

Options:
  -h, --help                 Show this message
  --version                  Show current version

Commands:
  help                       Show usage for a specific command
  init                       Create cluster configuration for daemon
  daemon                     Start the daemon
  update                     Update Flynn components
  download                   Download container images
  bootstrap                  Bootstrap layer 1
  inspect                    Get low-level information about a job
  log                        Get the logs of a job
  ps                         List jobs
  stop                       Stop running jobs
  destroy-volumes            Destroys the local volume database
  collect-debug-info         Collect debug information into an anonymous gist or tarball
  version                    Show current version

See 'flynn-host help <command>' for more information on a specific command.
`

	args, _ := docopt.Parse(usage, nil, true, version.String(), true)
	cmd := args.String["<command>"]
	cmdArgs := args.All["<args>"].([]string)

	if cmd == "help" {
		if len(cmdArgs) == 0 { // `flynn help`
			fmt.Println(usage)
			return
		} else { // `flynn help <command>`
			cmd = cmdArgs[0]
			cmdArgs = []string{"--help"}
		}
	}

	if cmd == "daemon" {
		// merge in args and env from config file, if available
		var c *config.Config
		if n := os.Getenv("FLYNN_HOST_CONFIG"); n != "" {
			var err error
			c, err = config.Open(n)
			if err != nil {
				log.Fatalf("error opening config file %s: %s", n, err)
			}
		} else {
			var err error
			c, err = config.Open(configFile)
			if err != nil && !os.IsNotExist(err) {
				log.Fatalf("error opening config file %s: %s", configFile, err)
			}
			if c == nil {
				c = &config.Config{}
			}
		}
		cmdArgs = append(cmdArgs, c.Args...)
		for k, v := range c.Env {
			os.Setenv(k, v)
		}
	}

	if err := cli.Run(cmd, cmdArgs); err != nil {
		if err == cli.ErrInvalidCommand {
			fmt.Printf("ERROR: %q is not a valid command\n\n", cmd)
			fmt.Println(usage)
			shutdown.ExitWithCode(1)
		}
		shutdown.Fatal(err)
	}
}

func runDaemon(args *docopt.Args) {
	hostname, _ := os.Hostname()
	externalIP := args.String["--external-ip"]
	stateFile := args.String["--state"]
	hostID := args.String["--id"]
	force := args.Bool["--force"]
	volPath := args.String["--volpath"]
	backendName := args.String["--backend"]
	flynnInit := args.String["--flynn-init"]
	nsumount := args.String["--nsumount"]
	logDir := args.String["--log-dir"]
	discoveryToken := args.String["--discovery"]
	peerIPs := strings.Split(args.String["--peer-ips"], ",")

	grohl.AddContext("app", "host")
	grohl.Log(grohl.Data{"at": "start"})
	g := grohl.NewContext(grohl.Data{"fn": "main"})

	if hostID == "" {
		hostID = strings.Replace(hostname, "-", "", -1)
	}
	if strings.Contains(hostID, "-") {
		shutdown.Fatal("host id must not contain dashes")
	}
	if externalIP == "" {
		var err error
		externalIP, err = config.DefaultExternalIP()
		if err != nil {
			shutdown.Fatal(err)
		}
	}

	publishAddr := net.JoinHostPort(externalIP, "1113")
	if discoveryToken != "" {
		// TODO: retry
		discoveryID, err := discovery.RegisterInstance(discovery.Info{
			ClusterURL:  discoveryToken,
			InstanceURL: "http://" + publishAddr,
			Name:        hostID,
		})
		if err != nil {
			g.Log(grohl.Data{"at": "register_discovery", "status": "error", "err": err.Error()})
			shutdown.Fatal(err)
		}
		g.Log(grohl.Data{"at": "register_discovery", "id": discoveryID})
	}

	state := NewState(hostID, stateFile)
	var backend Backend
	var err error

	// create volume manager
	vman, err := volumemanager.New(
		filepath.Join(volPath, "volumes.bolt"),
		func() (volume.Provider, error) {
			// use a zpool backing file size of either 70% of the device on which
			// volumes will reside, or 100GB if that can't be determined.
			var size int64
			var dev syscall.Statfs_t
			if err := syscall.Statfs(volPath, &dev); err == nil {
				size = (dev.Bsize * int64(dev.Blocks) * 7) / 10
			} else {
				size = 100000000000
			}
			g.Log(grohl.Data{"at": "zpool_size", "size": size})

			return zfsVolume.NewProvider(&zfsVolume.ProviderConfig{
				DatasetName: "flynn-default",
				Make: &zfsVolume.MakeDev{
					BackingFilename: filepath.Join(volPath, "zfs/vdev/flynn-default-zpool.vdev"),
					Size:            size,
				},
				WorkingDir: filepath.Join(volPath, "zfs"),
			})
		},
	)
	if err != nil {
		shutdown.Fatal(err)
	}

	mux := logmux.New(1000)
	shutdown.BeforeExit(func() { mux.Close() })

	switch backendName {
	case "libvirt-lxc":
		backend, err = NewLibvirtLXCBackend(state, vman, logDir, flynnInit, nsumount, mux)
	default:
		log.Fatalf("unknown backend %q", backendName)
	}
	if err != nil {
		shutdown.Fatal(err)
	}
	backend.SetDefaultEnv("EXTERNAL_IP", externalIP)

	resurrect, err := state.Restore(backend)
	if err != nil {
		shutdown.Fatal(err)
	}
	shutdown.BeforeExit(func() { backend.Cleanup() })
	shutdown.BeforeExit(func() {
		if err := state.MarkForResurrection(); err != nil {
			log.Print("error marking for resurrection", err)
		}
	})

	discoverdManager := NewDiscoverdManager(backend, mux, hostID, publishAddr)
	if err := serveHTTP(
		&Host{
			id:      hostID,
			url:     "http://" + publishAddr,
			state:   state,
			backend: backend,
		},
		&attachHandler{state: state, backend: backend},
		cluster.NewClient(),
		vman,
		discoverdManager.ConnectLocal,
	); err != nil {
		shutdown.Fatal(err)
	}

	if force {
		if err := backend.Cleanup(); err != nil {
			shutdown.Fatal(err)
		}
	}

	if discoveryToken != "" {
		instances, err := discovery.GetCluster(discoveryToken)
		if err != nil {
			// TODO(titanous): retry?
			shutdown.Fatal(err)
		}
		peerIPs = make([]string, 0, len(instances))
		for _, inst := range instances {
			u, err := url.Parse(inst.URL)
			if err != nil {
				continue
			}
			ip, _, err := net.SplitHostPort(u.Host)
			if err != nil || ip == externalIP {
				continue
			}
			peerIPs = append(peerIPs, ip)
		}
	}
	if err := discoverdManager.ConnectPeer(peerIPs); err != nil {
		// No peers have working discoverd, so resurrect any available jobs
		resurrect()
	}

	<-make(chan struct{})
}
<|endoftext|>


<commit_before>// Borrowed from https://github.com/acmacalister/helm

package lambda

import (
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"
)

const (
	get     = "GET"
	head    = "HEAD"
	post    = "POST"
	put     = "PUT"
	patch   = "PATCH"
	deleteh = "DELETE"
	options = "OPTIONS"
)

// RouteHandler is similar to "net/http" Handlers, except there is no response writer.
// Instead the *ProxyResponse is manipulated and returned directly.
type RouteHandler func(*Context, *Event, *ProxyResponse, url.Values)

// Middleware is just like the RouteHandler type, but has a boolean return. True
// means to keep processing the rest of the middleware chain, false means end.
type Middleware func(*Context, *Event, *ProxyResponse, url.Values) bool

// Router name says it all.
type Router struct {
	tree           *node
	rootHandler    RouteHandler
	middleware     []Middleware
	l              *log.Logger
	LoggingEnabled bool
	URIVersion     string
	GatewayPort    string
}

// NewRouter creates a new router. Take the root/fall through route
// like how the default mux works. Only difference is in this case,
// you have to specific one.
func NewRouter(rootHandler RouteHandler) *Router {
	node := node{component: "/", isNamedParam: false, methods: make(map[string]*route)}
	return &Router{tree: &node, rootHandler: rootHandler, URIVersion: ""}
}

// Handle takes an http handler, method and pattern for a route.
func (r *Router) Handle(method, path string, handler RouteHandler, middleware ...Middleware) {
	if path[0] != '/' {
		panic("Path has to start with a /.")
	}
	r.tree.addNode(method, r.URIVersion+path, handler, middleware...)
}

// GET same as Handle only the method is already implied.
func (r *Router) GET(path string, handler RouteHandler, middleware ...Middleware) {
	r.Handle(get, path, handler, middleware...)
}

// HEAD same as Handle only the method is already implied.
func (r *Router) HEAD(path string, handler RouteHandler, middleware ...Middleware) {
	r.Handle(head, path, handler, middleware...)
}

// OPTIONS same as Handle only the method is already implied.
func (r *Router) OPTIONS(path string, handler RouteHandler, middleware ...Middleware) {
	r.Handle(options, path, handler, middleware...)
}

// POST same as Handle only the method is already implied.
func (r *Router) POST(path string, handler RouteHandler, middleware ...Middleware) {
	r.Handle(post, path, handler, middleware...)
}

// PUT same as Handle only the method is already implied.
func (r *Router) PUT(path string, handler RouteHandler, middleware ...Middleware) {
	r.Handle(put, path, handler, middleware...)
}

// PATCH same as Handle only the method is already implied.
func (r *Router) PATCH(path string, handler RouteHandler, middleware ...Middleware) {
	r.Handle(patch, path, handler, middleware...)
}

// DELETE same as Handle only the method is already implied.
func (r *Router) DELETE(path string, handler RouteHandler, middleware ...Middleware) {
	r.Handle(deleteh, path, handler, middleware...)
}

// runMiddleware loops over the slice of middleware and call to each of the middleware handlers.
func runMiddleware(ctx *Context, evt *Event, res *ProxyResponse, params url.Values, middleware ...Middleware) bool {
	for _, m := range middleware {
		if !m(ctx, evt, res, params) {
			return false // the middleware returned false, so end processing the chain.
		}
	}
	return true
}

// Listen will start the internal router and listen for Lambda events to forward to registered routes.
func (r *Router) Listen() {
	RunStream(func(ctx *Context, evt *Event) *ProxyResponse {
		// url.Values are typically used for qureystring parameters.
		// However, this router uses them for path params.
		// Querystring parameters can be picked up from the *Event though.
		params := url.Values{}
		// New empty response with a 200 status code since nothing has gone wrong yet, it's just empty.
		res := NewProxyResponse(200, map[string]string{}, "", nil)

		// use the Path and HTTPMethod from the event to figure out the route
		node, _ := r.tree.traverse(strings.Split(evt.Path, "/")[1:], params)
		if handler := node.methods[evt.HTTPMethod]; handler != nil {
			// Middleware must return true in order to continue.
			// If it returns false, it will catch and halt everything.
			if !runMiddleware(ctx, evt, res, params, handler.middleware...) {
				// TODO: Figure out what to do here. I'm not sure what makes sense.
				// Should it return the response in its current state?
				return res
				// Or should it return an error?
				// Typically it leaves the request hanging if it returns false.
				// The middleware would need to write something back to the client.
				// return NewProxyResponse(500, map[string]string{}, "", nil)
			}
			handler.handler(ctx, evt, res, params)
		} else {
			r.rootHandler(ctx, evt, res, params)
		}

		return res
	}, os.Stdin, os.Stdout)
}

// gatewayHandler is a Router that implements an http.Handler interface
type gatewayHandler Router

// ServerHTTP will build an Event using an HTTP Request, run the appropriate handler from the Lambda code and then return an HTTP Response.
// Normally AWS API Gateway handles this for us, but locally, we'll need to do these transforms.
func (h gatewayHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// --> Build the request by converting HTTP request to Lambda Event
	ctx, evt := h.requestToEvent(r)

	// -<>- Normal handling of Lambda Event with Aegis Router.
	// It looks just like the closure given to RunStream with Listen(), except that we aren't going
	// to deal with stdio. Instead, we're taking the results and passing back through an HTTP Response.
	// TODO: refactor this to make a new handler that also works with a router. There's a tiny bit of repetition with this and what's in Listen()
	params := url.Values{}
	// New empty response with a 200 status code since nothing has gone wrong yet, it's just empty.
	res := NewProxyResponse(200, map[string]string{}, "", nil)
	// use the Path and HTTPMethod from the event to figure out the route
	node, _ := h.tree.traverse(strings.Split(evt.Path, "/")[1:], params)
	if handler := node.methods[evt.HTTPMethod]; handler != nil {
		// Middleware must return true in order to continue.
		// If it returns false, it will catch and halt everything.
		if !runMiddleware(ctx, evt, res, params, handler.middleware...) {
			// <-- Send the response
			h.proxyResponseToHTTPResponse(res, w)
			return
		}
		handler.handler(ctx, evt, res, params)
	} else {
		h.rootHandler(ctx, evt, res, params)
	}

	// <-- Send the response
	h.proxyResponseToHTTPResponse(res, w)
}

// requestToEvent will take an HTTP Request and transform it into a faux AWS Lambda Event.
// It will be missing some data like AWS Cognito information, API stage information, and more.
// However, it will be enough to handle request/response and will mimic Lambda locally.
// AWS does this for us automatically, but when running a local HTTP server, we'll need to do it.
func (h gatewayHandler) requestToEvent(r *http.Request) (*Context, *Event) {
	ctx := Context{}
	evt := Event{
		Path:       r.URL.Path,
		HTTPMethod: r.Method,
		RequestContext: RequestContext{
			HTTPMethod: r.Method,
		},
		HandlerStartTimeMs: time.Now().Unix(),
		HandlerStartTime:   time.Now().UnixNano(),
	}
	// transfer the headers over to the event
	evt.Headers = map[string]string{}
	for k, v := range r.Header {
		evt.Headers[k] = strings.Join(v, "; ")
	}

	// Querystring params
	params := r.URL.Query()
	paramsMap := map[string]string{}
	for k, _ := range params {
		paramsMap[k] = params.Get(k)
	}
	evt.QueryStringParameters = paramsMap

	// Path params (just the proxy+ path ... but it does not have the preceding slash)
	evt.PathParameters = map[string]string{
		"proxy": r.URL.Path[1:len(r.URL.Path)],
	}
	evt.Resource = "/{proxy+}"
	evt.RequestContext.ResourcePath = "/{proxy+}"

	// Identity info: user agent, IP, etc.
	evt.RequestContext.Identity.UserAgent = r.Header.Get("User-Agent")
	evt.RequestContext.Identity.SourceIP = r.Header.Get("X-Forwarded-For")
	if evt.RequestContext.Identity.SourceIP == "" {
		ip, _, err := net.SplitHostPort(r.RemoteAddr)
		if err == nil {
			evt.RequestContext.Identity.SourceIP = net.ParseIP(ip).String()
		}
	}

	// Stage will be "local" for now? I'm not sure what makes sense here. Local gateway. Local. Debug. ¯\_(ツ)_/¯
	evt.RequestContext.Stage = "local"
	// TODO: Stage variables would need to be pulled from the aegis.yaml ...
	// so now the config file has to be next to the app... otherwise some defaults will be set like "local"
	// and no stage variables i suppose.
	// evt.StageVariables =

	// The request id will simply be a timestamp to help keep it unique, but also allowing it to be easily sorted
	evt.RequestContext.RequestID = strconv.FormatInt(time.Now().UnixNano(), 10)

	// pass along the body
	bodyData, err := ioutil.ReadAll(r.Body)
	if err == nil {
		evt.Body = string(bodyData)
	}

	return &ctx, &evt
}

// proxyResponseToHTTPResponse will take the typical Lambda Proxy response and transform it into an HTTP response.
// AWS does this for us automatically, but when running a local HTTP server, we'll need to do it.
func (h gatewayHandler) proxyResponseToHTTPResponse(res *ProxyResponse, w http.ResponseWriter) {
	// transfer the headers into the HTTP Response
	for k, v := range res.Headers {
		w.Header().Set(k, v)
	}

	// The handler and middleware should have set everything on res
	code, _ := strconv.ParseInt(res.StatusCode, 10, 32)
	w.WriteHeader(int(code))

	// and of course the body
	fmt.Fprintf(w, res.Body)
}

// Gateway will start a local web server to listen for events. Useful for testing locally.
func (r *Router) Gateway() {
	if r.GatewayPort == "" {
		r.GatewayPort = ":9999"
	}
	fmt.Printf("Starting local gateway: http://localhost%v \n", r.GatewayPort)
	err := http.ListenAndServe(r.GatewayPort, gatewayHandler(*r))
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>ensure base64 is decoded and binary returned for local gateway, mimic api gateway<commit_after>// Borrowed from https://github.com/acmacalister/helm

package lambda

import (
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"
)

const (
	get     = "GET"
	head    = "HEAD"
	post    = "POST"
	put     = "PUT"
	patch   = "PATCH"
	deleteh = "DELETE"
	options = "OPTIONS"
)

// RouteHandler is similar to "net/http" Handlers, except there is no response writer.
// Instead the *ProxyResponse is manipulated and returned directly.
type RouteHandler func(*Context, *Event, *ProxyResponse, url.Values)

// Middleware is just like the RouteHandler type, but has a boolean return. True
// means to keep processing the rest of the middleware chain, false means end.
type Middleware func(*Context, *Event, *ProxyResponse, url.Values) bool

// Router name says it all.
type Router struct {
	tree           *node
	rootHandler    RouteHandler
	middleware     []Middleware
	l              *log.Logger
	LoggingEnabled bool
	URIVersion     string
	GatewayPort    string
}

// NewRouter creates a new router. Take the root/fall through route
// like how the default mux works. Only difference is in this case,
// you have to specific one.
func NewRouter(rootHandler RouteHandler) *Router {
	node := node{component: "/", isNamedParam: false, methods: make(map[string]*route)}
	return &Router{tree: &node, rootHandler: rootHandler, URIVersion: ""}
}

// Handle takes an http handler, method and pattern for a route.
func (r *Router) Handle(method, path string, handler RouteHandler, middleware ...Middleware) {
	if path[0] != '/' {
		panic("Path has to start with a /.")
	}
	r.tree.addNode(method, r.URIVersion+path, handler, middleware...)
}

// GET same as Handle only the method is already implied.
func (r *Router) GET(path string, handler RouteHandler, middleware ...Middleware) {
	r.Handle(get, path, handler, middleware...)
}

// HEAD same as Handle only the method is already implied.
func (r *Router) HEAD(path string, handler RouteHandler, middleware ...Middleware) {
	r.Handle(head, path, handler, middleware...)
}

// OPTIONS same as Handle only the method is already implied.
func (r *Router) OPTIONS(path string, handler RouteHandler, middleware ...Middleware) {
	r.Handle(options, path, handler, middleware...)
}

// POST same as Handle only the method is already implied.
func (r *Router) POST(path string, handler RouteHandler, middleware ...Middleware) {
	r.Handle(post, path, handler, middleware...)
}

// PUT same as Handle only the method is already implied.
func (r *Router) PUT(path string, handler RouteHandler, middleware ...Middleware) {
	r.Handle(put, path, handler, middleware...)
}

// PATCH same as Handle only the method is already implied.
func (r *Router) PATCH(path string, handler RouteHandler, middleware ...Middleware) {
	r.Handle(patch, path, handler, middleware...)
}

// DELETE same as Handle only the method is already implied.
func (r *Router) DELETE(path string, handler RouteHandler, middleware ...Middleware) {
	r.Handle(deleteh, path, handler, middleware...)
}

// runMiddleware loops over the slice of middleware and call to each of the middleware handlers.
func runMiddleware(ctx *Context, evt *Event, res *ProxyResponse, params url.Values, middleware ...Middleware) bool {
	for _, m := range middleware {
		if !m(ctx, evt, res, params) {
			return false // the middleware returned false, so end processing the chain.
		}
	}
	return true
}

// Listen will start the internal router and listen for Lambda events to forward to registered routes.
func (r *Router) Listen() {
	RunStream(func(ctx *Context, evt *Event) *ProxyResponse {
		// url.Values are typically used for qureystring parameters.
		// However, this router uses them for path params.
		// Querystring parameters can be picked up from the *Event though.
		params := url.Values{}
		// New empty response with a 200 status code since nothing has gone wrong yet, it's just empty.
		res := NewProxyResponse(200, map[string]string{}, "", nil)

		// use the Path and HTTPMethod from the event to figure out the route
		node, _ := r.tree.traverse(strings.Split(evt.Path, "/")[1:], params)
		if handler := node.methods[evt.HTTPMethod]; handler != nil {
			// Middleware must return true in order to continue.
			// If it returns false, it will catch and halt everything.
			if !runMiddleware(ctx, evt, res, params, handler.middleware...) {
				// TODO: Figure out what to do here. I'm not sure what makes sense.
				// Should it return the response in its current state?
				return res
				// Or should it return an error?
				// Typically it leaves the request hanging if it returns false.
				// The middleware would need to write something back to the client.
				// return NewProxyResponse(500, map[string]string{}, "", nil)
			}
			handler.handler(ctx, evt, res, params)
		} else {
			r.rootHandler(ctx, evt, res, params)
		}

		return res
	}, os.Stdin, os.Stdout)
}

// gatewayHandler is a Router that implements an http.Handler interface
type gatewayHandler Router

// ServerHTTP will build an Event using an HTTP Request, run the appropriate handler from the Lambda code and then return an HTTP Response.
// Normally AWS API Gateway handles this for us, but locally, we'll need to do these transforms.
func (h gatewayHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// --> Build the request by converting HTTP request to Lambda Event
	ctx, evt := h.requestToEvent(r)

	// -<>- Normal handling of Lambda Event with Aegis Router.
	// It looks just like the closure given to RunStream with Listen(), except that we aren't going
	// to deal with stdio. Instead, we're taking the results and passing back through an HTTP Response.
	// TODO: refactor this to make a new handler that also works with a router. There's a tiny bit of repetition with this and what's in Listen()
	params := url.Values{}
	// New empty response with a 200 status code since nothing has gone wrong yet, it's just empty.
	res := NewProxyResponse(200, map[string]string{}, "", nil)
	// use the Path and HTTPMethod from the event to figure out the route
	node, _ := h.tree.traverse(strings.Split(evt.Path, "/")[1:], params)
	if handler := node.methods[evt.HTTPMethod]; handler != nil {
		// Middleware must return true in order to continue.
		// If it returns false, it will catch and halt everything.
		if !runMiddleware(ctx, evt, res, params, handler.middleware...) {
			// <-- Send the response
			h.proxyResponseToHTTPResponse(res, w)
			return
		}
		handler.handler(ctx, evt, res, params)
	} else {
		h.rootHandler(ctx, evt, res, params)
	}

	// <-- Send the response
	h.proxyResponseToHTTPResponse(res, w)
}

// requestToEvent will take an HTTP Request and transform it into a faux AWS Lambda Event.
// It will be missing some data like AWS Cognito information, API stage information, and more.
// However, it will be enough to handle request/response and will mimic Lambda locally.
// AWS does this for us automatically, but when running a local HTTP server, we'll need to do it.
func (h gatewayHandler) requestToEvent(r *http.Request) (*Context, *Event) {
	ctx := Context{}
	evt := Event{
		Path:       r.URL.Path,
		HTTPMethod: r.Method,
		RequestContext: RequestContext{
			HTTPMethod: r.Method,
		},
		HandlerStartTimeMs: time.Now().Unix(),
		HandlerStartTime:   time.Now().UnixNano(),
	}
	// transfer the headers over to the event
	evt.Headers = map[string]string{}
	for k, v := range r.Header {
		evt.Headers[k] = strings.Join(v, "; ")
	}

	// Querystring params
	params := r.URL.Query()
	paramsMap := map[string]string{}
	for k, _ := range params {
		paramsMap[k] = params.Get(k)
	}
	evt.QueryStringParameters = paramsMap

	// Path params (just the proxy+ path ... but it does not have the preceding slash)
	evt.PathParameters = map[string]string{
		"proxy": r.URL.Path[1:len(r.URL.Path)],
	}
	evt.Resource = "/{proxy+}"
	evt.RequestContext.ResourcePath = "/{proxy+}"

	// Identity info: user agent, IP, etc.
	evt.RequestContext.Identity.UserAgent = r.Header.Get("User-Agent")
	evt.RequestContext.Identity.SourceIP = r.Header.Get("X-Forwarded-For")
	if evt.RequestContext.Identity.SourceIP == "" {
		ip, _, err := net.SplitHostPort(r.RemoteAddr)
		if err == nil {
			evt.RequestContext.Identity.SourceIP = net.ParseIP(ip).String()
		}
	}

	// Stage will be "local" for now? I'm not sure what makes sense here. Local gateway. Local. Debug. ¯\_(ツ)_/¯
	evt.RequestContext.Stage = "local"
	// TODO: Stage variables would need to be pulled from the aegis.yaml ...
	// so now the config file has to be next to the app... otherwise some defaults will be set like "local"
	// and no stage variables i suppose.
	// evt.StageVariables =

	// The request id will simply be a timestamp to help keep it unique, but also allowing it to be easily sorted
	evt.RequestContext.RequestID = strconv.FormatInt(time.Now().UnixNano(), 10)

	// pass along the body
	bodyData, err := ioutil.ReadAll(r.Body)
	if err == nil {
		evt.Body = string(bodyData)
	}

	return &ctx, &evt
}

// proxyResponseToHTTPResponse will take the typical Lambda Proxy response and transform it into an HTTP response.
// AWS does this for us automatically, but when running a local HTTP server, we'll need to do it.
func (h gatewayHandler) proxyResponseToHTTPResponse(res *ProxyResponse, w http.ResponseWriter) {
	// transfer the headers into the HTTP Response
	for k, v := range res.Headers {
		w.Header().Set(k, v)
	}

	// The handler and middleware should have set everything on res
	code, _ := strconv.ParseInt(res.StatusCode, 10, 32)
	w.WriteHeader(int(code))

	// If this is true, then API Gateway will decode the base64 string to bytes. Mimic that behavior here.
	if res.IsBase64Encoded {
		decodedBody, err := base64.StdEncoding.DecodeString(res.Body)
		if err == nil {
			w.Header().Set("Content-Length", strconv.Itoa(len(decodedBody)))
			fmt.Fprintf(w, "%s", decodedBody)
		} else {
			res.Body = err.Error()
			fmt.Fprintf(w, res.Body)
		}
	} else {
		// if not base64, write res.Body
		fmt.Fprintf(w, res.Body)
	}
}

// Gateway will start a local web server to listen for events. Useful for testing locally.
func (r *Router) Gateway() {
	if r.GatewayPort == "" {
		r.GatewayPort = ":9999"
	}
	fmt.Printf("Starting local gateway: http://localhost%v \n", r.GatewayPort)
	err := http.ListenAndServe(r.GatewayPort, gatewayHandler(*r))
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package controllers

import (
	"github.com/ernestio/api-gateway/controllers/policies"
	h "github.com/ernestio/api-gateway/helpers"
	"github.com/labstack/echo"
)

// GetPoliciesHandler : responds to GET /policies/ with a list of all
// policies
func GetPoliciesHandler(c echo.Context) (err error) {
	return genericList(c, "policy", policies.List)
}

// GetPolicyHandler : responds to GET /policies/:id:/ with the specified
// user details
func GetPolicyHandler(c echo.Context) error {
	return genericGet(c, "policy", policies.Get)
}

// CreatePolicyHandler : responds to POST /policies/ by creating a policy
// on the data store
func CreatePolicyHandler(c echo.Context) (err error) {
	return genericCreate(c, "policy", policies.Create)
}

// DeletePolicyHandler : responds to DELETE /policies/:id: by deleting an
// existing policy
func DeletePolicyHandler(c echo.Context) (err error) {
	return genericDelete(c, "policy", policies.Delete)
}

// UpdatePolicyHandler : ...
func UpdatePolicyHandler(c echo.Context) (err error) {
	return genericUpdate(c, "policy", policies.Update)
}

// GetPoliciesHandler : responds to GET /policies/ with a list of all
// policies
func GetPolicyDocumentsHandler(c echo.Context) (err error) {
	au := AuthenticatedUser(c)
	name := c.Param("policy")

	st, b := h.IsAuthorized(&au, "policys/list")
	if st == 200 {
		st, b = policies.ListDocuments(au, name)
	}

	return h.Respond(c, st, b)
}

// GetPolicyDocumentHandler : responds to GET /policies/:id:/revisions/:rev:
func GetPolicyDocumentHandler(c echo.Context) error {
	au := AuthenticatedUser(c)
	name := c.Param("policy")
	revision := c.Param("revision")

	st, b := h.IsAuthorized(&au, "policys/get")
	if st == 200 {
		st, b = policies.GetDocument(au, name, revision)
	}

	return h.Respond(c, st, b)
}

// CreatePolicyDocumentHandler : responds to POST /policies/ by creating a policy
// on the data store
func CreatePolicyDocumentHandler(c echo.Context) (err error) {
	au := AuthenticatedUser(c)
	name := c.Param("policy")

	st, b := h.IsAuthorized(&au, "policys/create")
	if st != 200 {
		return h.Respond(c, st, b)
	}

	st = 500
	b = []byte("Invalid input")
	body, err := h.GetRequestBody(c)
	if err == nil {
		st, b = policies.CreateDocument(au, name, body)
	}

	return h.Respond(c, st, b)
}
<commit_msg>allowing all users to view and list policy documents<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package controllers

import (
	"github.com/ernestio/api-gateway/controllers/policies"
	h "github.com/ernestio/api-gateway/helpers"
	"github.com/labstack/echo"
)

// GetPoliciesHandler : responds to GET /policies/ with a list of all
// policies
func GetPoliciesHandler(c echo.Context) (err error) {
	au := AuthenticatedUser(c)

	st, b := policies.List(au)

	return h.Respond(c, st, b)
}

// GetPolicyHandler : responds to GET /policies/:id:/ with the specified
// user details
func GetPolicyHandler(c echo.Context) error {
	au := AuthenticatedUser(c)
	name := c.Param("policy")

	st, b := policies.Get(au, name)

	return h.Respond(c, st, b)
}

// CreatePolicyHandler : responds to POST /policies/ by creating a policy
// on the data store
func CreatePolicyHandler(c echo.Context) (err error) {
	return genericCreate(c, "policy", policies.Create)
}

// DeletePolicyHandler : responds to DELETE /policies/:id: by deleting an
// existing policy
func DeletePolicyHandler(c echo.Context) (err error) {
	return genericDelete(c, "policy", policies.Delete)
}

// UpdatePolicyHandler : ...
func UpdatePolicyHandler(c echo.Context) (err error) {
	return genericUpdate(c, "policy", policies.Update)
}

// GetPolicyDocumentsHandler : responds to GET /policies/ with a list of all
// policies
func GetPolicyDocumentsHandler(c echo.Context) (err error) {
	au := AuthenticatedUser(c)
	name := c.Param("policy")

	st, b := policies.ListDocuments(au, name)

	return h.Respond(c, st, b)
}

// GetPolicyDocumentHandler : responds to GET /policies/:id:/revisions/:rev:
func GetPolicyDocumentHandler(c echo.Context) error {
	au := AuthenticatedUser(c)
	name := c.Param("policy")
	revision := c.Param("revision")

	st, b := policies.GetDocument(au, name, revision)

	return h.Respond(c, st, b)
}

// CreatePolicyDocumentHandler : responds to POST /policies/ by creating a policy
// on the data store
func CreatePolicyDocumentHandler(c echo.Context) (err error) {
	au := AuthenticatedUser(c)
	name := c.Param("policy")

	st, b := h.IsAuthorized(&au, "policys/create")
	if st != 200 {
		return h.Respond(c, st, b)
	}

	st = 500
	b = []byte("Invalid input")
	body, err := h.GetRequestBody(c)
	if err == nil {
		st, b = policies.CreateDocument(au, name, body)
	}

	return h.Respond(c, st, b)
}
<|endoftext|>


<commit_before>// Copyright The OpenTelemetry 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.

// nolint:gocritic
package awsprometheusremotewriteexporter

import (
	"context"
	"testing"

	"github.com/stretchr/testify/assert"
	"go.opentelemetry.io/collector/component"
	"go.opentelemetry.io/collector/component/componenttest"
	"go.opentelemetry.io/collector/config"
	"go.opentelemetry.io/collector/config/confighttp"
	"go.opentelemetry.io/collector/config/configtest"
	"go.opentelemetry.io/collector/config/configtls"
)

func TestType(t *testing.T) {
	af := NewFactory()
	assert.Equal(t, af.Type(), config.Type(typeStr))
}

//Tests whether or not the default Exporter factory can instantiate a properly interfaced Exporter with default conditions
func TestCreateDefaultConfig(t *testing.T) {
	af := NewFactory()
	cfg := af.CreateDefaultConfig()
	assert.NotNil(t, cfg, "failed to create default config")
	assert.NoError(t, configtest.CheckConfigStruct(cfg))
}

//Tests whether or not a correct Metrics Exporter from the default Config parameters
func TestCreateMetricsExporter(t *testing.T) {
	af := NewFactory()
	validConfigWithAuth := af.CreateDefaultConfig().(*Config)
	validConfigWithAuth.AuthConfig = AuthConfig{Region: "region", Service: "service"}

	// Some form of AWS credentials chain required to test valid auth case
	// This is a set of mock credentials strictly for testing purposes. Users
	// should not set their credentials like this in production.
	t.Setenv("AWS_ACCESS_KEY", "mock_value")
	t.Setenv("AWS_SECRET_ACCESS_KEY", "mock_value2")

	invalidConfigWithAuth := af.CreateDefaultConfig().(*Config)
	invalidConfigWithAuth.AuthConfig = AuthConfig{Region: "", Service: "service"}

	invalidConfig := af.CreateDefaultConfig().(*Config)
	invalidConfig.HTTPClientSettings = confighttp.HTTPClientSettings{}

	invalidTLSConfig := af.CreateDefaultConfig().(*Config)
	invalidTLSConfig.HTTPClientSettings.TLSSetting = configtls.TLSClientSetting{
		TLSSetting: configtls.TLSSetting{
			CAFile:   "non-existent file",
			CertFile: "",
			KeyFile:  "",
		},
		Insecure:   false,
		ServerName: "",
	}

	tests := []struct {
		name                string
		cfg                 config.Exporter
		params              component.ExporterCreateSettings
		returnErrorOnCreate bool
		returnErrorOnStart  bool
	}{
		{
			name:                "success_case_with_auth",
			cfg:                 validConfigWithAuth,
			params:              componenttest.NewNopExporterCreateSettings(),
			returnErrorOnCreate: false,
		},
		{
			name:                "invalid_config_case",
			cfg:                 invalidConfig,
			params:              componenttest.NewNopExporterCreateSettings(),
			returnErrorOnCreate: true,
		},
		{
			name:               "invalid_tls_config_case",
			cfg:                invalidTLSConfig,
			params:             componenttest.NewNopExporterCreateSettings(),
			returnErrorOnStart: true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			exp, err := af.CreateMetricsExporter(context.Background(), tt.params, tt.cfg)
			if tt.returnErrorOnCreate {
				assert.Error(t, err)
				return
			}
			assert.NoError(t, err)
			assert.NotNil(t, exp)
			err = exp.Start(context.Background(), componenttest.NewNopHost())
			if tt.returnErrorOnStart {
				assert.Error(t, err)
				return
			}
			assert.NoError(t, err)
			assert.NoError(t, exp.Shutdown(context.Background()))
		})
	}
}
<commit_msg>[exporter/awsprometheusremotewriteexporter] enable gocritic (#11437)<commit_after>// Copyright The OpenTelemetry 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 awsprometheusremotewriteexporter

import (
	"context"
	"testing"

	"github.com/stretchr/testify/assert"
	"go.opentelemetry.io/collector/component"
	"go.opentelemetry.io/collector/component/componenttest"
	"go.opentelemetry.io/collector/config"
	"go.opentelemetry.io/collector/config/confighttp"
	"go.opentelemetry.io/collector/config/configtest"
	"go.opentelemetry.io/collector/config/configtls"
)

func TestType(t *testing.T) {
	af := NewFactory()
	assert.Equal(t, af.Type(), config.Type(typeStr))
}

// Tests whether the default Exporter factory can instantiate a properly interfaced Exporter with default conditions
func TestCreateDefaultConfig(t *testing.T) {
	af := NewFactory()
	cfg := af.CreateDefaultConfig()
	assert.NotNil(t, cfg, "failed to create default config")
	assert.NoError(t, configtest.CheckConfigStruct(cfg))
}

// Tests whether a correct Metrics Exporter from the default Config parameters
func TestCreateMetricsExporter(t *testing.T) {
	af := NewFactory()
	validConfigWithAuth := af.CreateDefaultConfig().(*Config)
	validConfigWithAuth.AuthConfig = AuthConfig{Region: "region", Service: "service"}

	// Some form of AWS credentials chain required to test valid auth case
	// This is a set of mock credentials strictly for testing purposes. Users
	// should not set their credentials like this in production.
	t.Setenv("AWS_ACCESS_KEY", "mock_value")
	t.Setenv("AWS_SECRET_ACCESS_KEY", "mock_value2")

	invalidConfigWithAuth := af.CreateDefaultConfig().(*Config)
	invalidConfigWithAuth.AuthConfig = AuthConfig{Region: "", Service: "service"}

	invalidConfig := af.CreateDefaultConfig().(*Config)
	invalidConfig.HTTPClientSettings = confighttp.HTTPClientSettings{}

	invalidTLSConfig := af.CreateDefaultConfig().(*Config)
	invalidTLSConfig.HTTPClientSettings.TLSSetting = configtls.TLSClientSetting{
		TLSSetting: configtls.TLSSetting{
			CAFile:   "non-existent file",
			CertFile: "",
			KeyFile:  "",
		},
		Insecure:   false,
		ServerName: "",
	}

	tests := []struct {
		name                string
		cfg                 config.Exporter
		params              component.ExporterCreateSettings
		returnErrorOnCreate bool
		returnErrorOnStart  bool
	}{
		{
			name:                "success_case_with_auth",
			cfg:                 validConfigWithAuth,
			params:              componenttest.NewNopExporterCreateSettings(),
			returnErrorOnCreate: false,
		},
		{
			name:                "invalid_config_case",
			cfg:                 invalidConfig,
			params:              componenttest.NewNopExporterCreateSettings(),
			returnErrorOnCreate: true,
		},
		{
			name:               "invalid_tls_config_case",
			cfg:                invalidTLSConfig,
			params:             componenttest.NewNopExporterCreateSettings(),
			returnErrorOnStart: true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			exp, err := af.CreateMetricsExporter(context.Background(), tt.params, tt.cfg)
			if tt.returnErrorOnCreate {
				assert.Error(t, err)
				return
			}
			assert.NoError(t, err)
			assert.NotNil(t, exp)
			err = exp.Start(context.Background(), componenttest.NewNopHost())
			if tt.returnErrorOnStart {
				assert.Error(t, err)
				return
			}
			assert.NoError(t, err)
			assert.NoError(t, exp.Shutdown(context.Background()))
		})
	}
}
<|endoftext|>


<commit_before>package trollmode

import (
	"encoding/json"
	"errors"
	"socialapi/models"
	"socialapi/request"
	"socialapi/workers/common/manager"

	"github.com/koding/logging"
	"github.com/koding/worker"
	"github.com/streadway/amqp"
)

const (
	MarkedAsTroll   = "api.account_marked_as_troll"
	UnMarkedAsTroll = "api.account_unmarked_as_troll"
)

func NewManager(controller worker.ErrHandler) *manager.Manager {
	m := manager.New()
	m.Controller(controller)
	m.HandleFunc(MarkedAsTroll, (*Controller).MarkedAsTroll)
	m.HandleFunc(UnMarkedAsTroll, (*Controller).UnMarkedAsTroll)
	return m
}

type Controller struct {
	log logging.Logger
}

func NewController(log logging.Logger) *Controller {
	return &Controller{
		log: log,
	}
}

func (t *Controller) DefaultErrHandler(delivery amqp.Delivery, err error) bool {
	if delivery.Redelivered {
		t.log.Error("Redelivered message gave error again, putting to maintenance queue", err)
		delivery.Ack(false)
		return true
	}

	t.log.Error("an error occured putting message back to queue", err)
	delivery.Nack(false, true)
	return false
}

func (t *Controller) MarkedAsTroll(account *models.Account) error {
	if err := t.validateRequest(account); err != nil {
		t.log.Error("Validation failed for marking troll; skipping, err: %s ", err.Error())
		return nil
	}

	return t.processsAllMessagesAsTroll(account.Id)
}

func (t *Controller) validateRequest(account *models.Account) error {
	if account == nil {
		return errors.New("account is not set (nil)")
	}

	if account.Id == 0 {
		return errors.New("account id is not set")
	}

	return nil
}

func (t *Controller) processsAllMessagesAsTroll(accountId int64) error {
	query := &request.Query{
		Type:      models.ChannelMessage_TYPE_POST,
		AccountId: accountId,
	}

func (c *Controller) markParticipations(account *models.Account) error {
	var processCount = 100
	var skip = 0
	var erroredChannelParticipants []models.ChannelParticipant

	cp := models.NewChannelParticipant()
	q := &bongo.Query{
		Selector: map[string]interface{}{
			"account_id": account.Id,
			// 0 means safe
			"meta_bits": models.Safe,
		},
		Pagination: *bongo.NewPagination(processCount, 0),
	}

	for {

		// set skip everytime here
		q.Pagination.Skip = skip
		var channelParticipants []models.ChannelParticipant
		if err := cp.Some(&channelParticipants, q); err != nil {
			return err
		}

		// we processed all channel participants
		if len(channelParticipants) <= 0 {
			break
		}

		for i, channelParticipant := range channelParticipants {
			channelParticipant.MetaBits.MarkTroll()
			if err := channelParticipant.Update(); err != nil {
				c.log.Error(err.Error())
				erroredChannelParticipants = append(erroredChannelParticipants, channelParticipants[i])
			}
		}

		// increment skip count
		skip = processCount + skip
	}

	if len(erroredChannelParticipants) != 0 {
		err := errors.New(fmt.Sprintf("some errors: %v", erroredChannelParticipants))
		c.log.Error(err.Error())
		return err
	}

	return nil
}
	cm := models.NewChannelMessage()
	totalMessageCount, err := cm.FetchTotalMessageCount(query)
	if err != nil {
		return err
	}

	// no need to continue if user doesnt have any channel message
	if totalMessageCount == 0 {
		t.log.Notice("Account %d doesnt have any post messages", accountId)
		return nil
	}

	processCount := 100

	for i := 0; totalMessageCount <= 0; {
		query.Limit = processCount
		query.Skip = processCount * i

		messageIds, err := cm.FetchMessageIds(query)
		if err != nil {
			return err
		}

		if len(messageIds) == 0 {
			return nil
		}

		err = t.markMessagesAsTroll(cm, messageIds)
		if err != nil {
			return err
		}

		totalMessageCount = totalMessageCount - processCount
		i++
	}

	return nil

}

func (t *Controller) markMessagesAsTroll(cm *models.ChannelMessage, messageIds []int64) error {
	if len(messageIds) == 0 {
		return nil
	}

	for _, messageId := range messageIds {
		err := cm.UpdateMulti(
			map[string]interface{}{"id": messageId},
			map[string]interface{}{"meta_bits": 1},
		)
		if err != nil {
			return err
		}
	}

	return nil
}

func (t *Controller) UnMarkedAsTroll(account *models.Account) error {
	t.log.Critical("un marked as troll ehehe %v", account)
	return nil
}

func mapMessage(data []byte) (*models.Account, error) {
	cm := models.NewAccount()
	if err := json.Unmarshal(data, cm); err != nil {
		return nil, err
	}

	return cm, nil
}
<commit_msg>Social: markChannels as exempt<commit_after>package trollmode

import (
	"encoding/json"
	"errors"
	"socialapi/models"
	"socialapi/request"
	"socialapi/workers/common/manager"

	"github.com/koding/logging"
	"github.com/koding/worker"
	"github.com/streadway/amqp"
)

const (
	MarkedAsTroll   = "api.account_marked_as_troll"
	UnMarkedAsTroll = "api.account_unmarked_as_troll"
)

func NewManager(controller worker.ErrHandler) *manager.Manager {
	m := manager.New()
	m.Controller(controller)
	m.HandleFunc(MarkedAsTroll, (*Controller).MarkedAsTroll)
	m.HandleFunc(UnMarkedAsTroll, (*Controller).UnMarkedAsTroll)
	return m
}

type Controller struct {
	log logging.Logger
}

func NewController(log logging.Logger) *Controller {
	return &Controller{
		log: log,
	}
}

func (t *Controller) DefaultErrHandler(delivery amqp.Delivery, err error) bool {
	if delivery.Redelivered {
		t.log.Error("Redelivered message gave error again, putting to maintenance queue", err)
		delivery.Ack(false)
		return true
	}

	t.log.Error("an error occured putting message back to queue", err)
	delivery.Nack(false, true)
	return false
}

func (t *Controller) MarkedAsTroll(account *models.Account) error {
	if err := t.validateRequest(account); err != nil {
		t.log.Error("Validation failed for marking troll; skipping, err: %s ", err.Error())
		return nil
	}

	return t.processsAllMessagesAsTroll(account.Id)
}

func (t *Controller) validateRequest(account *models.Account) error {
	if account == nil {
		return errors.New("account is not set (nil)")
	}

	if account.Id == 0 {
		return errors.New("account id is not set")
	}

	return nil
}

func (t *Controller) processsAllMessagesAsTroll(accountId int64) error {
	query := &request.Query{
		Type:      models.ChannelMessage_TYPE_POST,
		AccountId: accountId,
func (c *Controller) markChannels(account *models.Account) error {
	var processCount = 100
	var skip = 0
	var erroredChannels []models.Channel

	ch := models.NewChannel()
	q := &bongo.Query{
		Selector: map[string]interface{}{
			"creator_id":    account.Id,
			"type_constant": models.Channel_TYPE_PRIVATE_MESSAGE,
			// 0 means safe
			"meta_bits": models.Safe,
		},
		Pagination: *bongo.NewPagination(processCount, 0),
	}

	for {
		// set skip everytime here
		q.Pagination.Skip = skip
		var channels []models.Channel
		if err := ch.Some(&channels, q); err != nil {
			return err
		}

		// we processed all messages
		if len(channels) <= 0 {
			break
		}

		for i, channel := range channels {
			channel.MetaBits.MarkTroll()
			if err := channel.Update(); err != nil {
				c.log.Error(err.Error())
				erroredChannels = append(erroredChannels, channels[i])
			}
		}

		// increment skip count
		skip = processCount + skip
	}

	if len(erroredChannels) != 0 {
		err := errors.New(fmt.Sprintf("some errors: %v", erroredChannels))
		c.log.Error(err.Error())
		return err
	}

	return nil
}

func (c *Controller) markParticipations(account *models.Account) error {
	var processCount = 100
	var skip = 0
	var erroredChannelParticipants []models.ChannelParticipant

	cp := models.NewChannelParticipant()
	q := &bongo.Query{
		Selector: map[string]interface{}{
			"account_id": account.Id,
			// 0 means safe
			"meta_bits": models.Safe,
		},
		Pagination: *bongo.NewPagination(processCount, 0),
	}

	for {

		// set skip everytime here
		q.Pagination.Skip = skip
		var channelParticipants []models.ChannelParticipant
		if err := cp.Some(&channelParticipants, q); err != nil {
			return err
		}

		// we processed all channel participants
		if len(channelParticipants) <= 0 {
			break
		}

		for i, channelParticipant := range channelParticipants {
			channelParticipant.MetaBits.MarkTroll()
			if err := channelParticipant.Update(); err != nil {
				c.log.Error(err.Error())
				erroredChannelParticipants = append(erroredChannelParticipants, channelParticipants[i])
			}
		}

		// increment skip count
		skip = processCount + skip
	}

	if len(erroredChannelParticipants) != 0 {
		err := errors.New(fmt.Sprintf("some errors: %v", erroredChannelParticipants))
		c.log.Error(err.Error())
		return err
	}

	return nil
}
	cm := models.NewChannelMessage()
	totalMessageCount, err := cm.FetchTotalMessageCount(query)
	if err != nil {
		return err
	}

	// no need to continue if user doesnt have any channel message
	if totalMessageCount == 0 {
		t.log.Notice("Account %d doesnt have any post messages", accountId)
		return nil
	}

	processCount := 100

	for i := 0; totalMessageCount <= 0; {
		query.Limit = processCount
		query.Skip = processCount * i

		messageIds, err := cm.FetchMessageIds(query)
		if err != nil {
			return err
		}

		if len(messageIds) == 0 {
			return nil
		}

		err = t.markMessagesAsTroll(cm, messageIds)
		if err != nil {
			return err
		}

		totalMessageCount = totalMessageCount - processCount
		i++
	}

	return nil

}

func (t *Controller) markMessagesAsTroll(cm *models.ChannelMessage, messageIds []int64) error {
	if len(messageIds) == 0 {
		return nil
	}

	for _, messageId := range messageIds {
		err := cm.UpdateMulti(
			map[string]interface{}{"id": messageId},
			map[string]interface{}{"meta_bits": 1},
		)
		if err != nil {
			return err
		}
	}

	return nil
}

func (t *Controller) UnMarkedAsTroll(account *models.Account) error {
	t.log.Critical("un marked as troll ehehe %v", account)
	return nil
}

func mapMessage(data []byte) (*models.Account, error) {
	cm := models.NewAccount()
	if err := json.Unmarshal(data, cm); err != nil {
		return nil, err
	}

	return cm, nil
}
<|endoftext|>


<commit_before>package isolated

import (
	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("enable-org-isolation command", func() {
	var isolationSegmentName string
	var organizationName string

	BeforeEach(func() {
		isolationSegmentName = helpers.IsolationSegmentName()
		organizationName = helpers.NewOrgName()
	})

	Describe("help", func() {
		Context("when --help flag is set", func() {
			It("Displays command usage to output", func() {
				session := helpers.CF("enable-org-isolation", "--help")
				Eventually(session).Should(Say("NAME:"))
				Eventually(session).Should(Say("enable-org-isolation - Entitle an organization to an isolation segment"))
				Eventually(session).Should(Say("USAGE:"))
				Eventually(session).Should(Say("cf enable-org-isolation ORG_NAME SEGMENT_NAME"))
				Eventually(session).Should(Say("SEE ALSO:"))
				Eventually(session).Should(Say("create-isolation-segment, isolation-segments"))
				Eventually(session).Should(Exit(0))
			})
		})
	})

	Context("when the environment is not setup correctly", func() {
		Context("when no API endpoint is set", func() {
			BeforeEach(func() {
				helpers.UnsetAPI()
			})

			It("fails with no API endpoint set message", func() {
				session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No API endpoint set. Use 'cf login' or 'cf api' to target an endpoint."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when not logged in", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
			})

			It("fails with not logged in message", func() {
				session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("Not logged in. Use 'cf login' to log in."))
				Eventually(session).Should(Exit(1))
			})
		})
	})

	Context("when the environment is set up correctly", func() {
		var userName string

		BeforeEach(func() {
			helpers.LoginCF()
			userName, _ = helpers.GetCredentials()
		})

		Context("when the isolation segment does not exist", func() {
			It("fails with isolation segment not found message", func() {
				session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
				Eventually(session).Should(Say("Enabling isolation segment %s for org %s as %s…", isolationSegmentName, organizationName, userName))
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("Isolation segment '%s' not found.", isolationSegmentName))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when the isolation segment exists", func() {
			BeforeEach(func() {
				Eventually(helpers.CF("create-isolation-segment", isolationSegmentName)).Should(Exit(0))
			})

			// TODO: Delete this and add it to cleanup script after #138303919
			AfterEach(func() {
				Eventually(helpers.CF("delete-isolation-segment", "-f", isolationSegmentName)).Should(Exit(0))
			})

			Context("when the organization does not exist", func() {
				It("fails with organization not found message", func() {
					session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
					Eventually(session).Should(Say("Enabling isolation segment %s for org %s as %s…", isolationSegmentName, organizationName, userName))
					Eventually(session).Should(Say("FAILED"))
					Eventually(session.Err).Should(Say("Organization '%s' not found.", organizationName))
					Eventually(session).Should(Exit(1))
				})
			})

			Context("when the organization exists", func() {
				BeforeEach(func() {
					helpers.CreateOrg(organizationName)
					helpers.TargetOrg(organizationName)
				})

				It("displays OK", func() {
					session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
					Eventually(session).Should(Say("Enabling isolation segment %s for org %s as %s…", isolationSegmentName, organizationName, userName))
					Eventually(session).Should(Say("OK"))
					Eventually(session).Should(Exit(0))
				})

				Context("when the isolation is already enabled", func() {
					BeforeEach(func() {
						Eventually(helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)).Should(Exit(0))
					})

					It("displays OK", func() {
						session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
						Eventually(session).Should(Say("Enabling isolation segment %s for org %s as %s…", isolationSegmentName, organizationName, userName))
						Eventually(session).Should(Say("OK"))
						Eventually(session).Should(Exit(0))
					})
				})
			})
		})
	})
})
<commit_msg>fixed integration<commit_after>package isolated

import (
	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("enable-org-isolation command", func() {
	var isolationSegmentName string
	var organizationName string

	BeforeEach(func() {
		isolationSegmentName = helpers.IsolationSegmentName()
		organizationName = helpers.NewOrgName()
	})

	Describe("help", func() {
		Context("when --help flag is set", func() {
			It("Displays command usage to output", func() {
				session := helpers.CF("enable-org-isolation", "--help")
				Eventually(session).Should(Say("NAME:"))
				Eventually(session).Should(Say("enable-org-isolation - Entitle an organization to an isolation segment"))
				Eventually(session).Should(Say("USAGE:"))
				Eventually(session).Should(Say("cf enable-org-isolation ORG_NAME SEGMENT_NAME"))
				Eventually(session).Should(Say("SEE ALSO:"))
				Eventually(session).Should(Say("create-isolation-segment, isolation-segments"))
				Eventually(session).Should(Exit(0))
			})
		})
	})

	Context("when the environment is not setup correctly", func() {
		Context("when no API endpoint is set", func() {
			BeforeEach(func() {
				helpers.UnsetAPI()
			})

			It("fails with no API endpoint set message", func() {
				session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No API endpoint set. Use 'cf login' or 'cf api' to target an endpoint."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when not logged in", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
			})

			It("fails with not logged in message", func() {
				session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("Not logged in. Use 'cf login' to log in."))
				Eventually(session).Should(Exit(1))
			})
		})
	})

	Context("when the environment is set up correctly", func() {
		var userName string

		BeforeEach(func() {
			helpers.LoginCF()
			userName, _ = helpers.GetCredentials()
		})

		Context("when the isolation segment does not exist", func() {
			It("fails with isolation segment not found message", func() {
				session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
				Eventually(session).Should(Say("Enabling isolation segment %s for org %s as %s…", isolationSegmentName, organizationName, userName))
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("Isolation segment '%s' not found.", isolationSegmentName))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when the isolation segment exists", func() {
			BeforeEach(func() {
				Eventually(helpers.CF("create-isolation-segment", isolationSegmentName)).Should(Exit(0))
			})

			// TODO: Delete this and add it to cleanup script after #138303919
			AfterEach(func() {
				Eventually(helpers.CF("delete-org", "-f", organizationName)).Should(Exit(0))
				Eventually(helpers.CF("delete-isolation-segment", "-f", isolationSegmentName)).Should(Exit(0))
			})

			Context("when the organization does not exist", func() {
				It("fails with organization not found message", func() {
					session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
					Eventually(session).Should(Say("Enabling isolation segment %s for org %s as %s…", isolationSegmentName, organizationName, userName))
					Eventually(session).Should(Say("FAILED"))
					Eventually(session.Err).Should(Say("Organization '%s' not found.", organizationName))
					Eventually(session).Should(Exit(1))
				})
			})

			Context("when the organization exists", func() {
				BeforeEach(func() {
					helpers.CreateOrg(organizationName)
					helpers.TargetOrg(organizationName)
				})

				It("displays OK", func() {
					session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
					Eventually(session).Should(Say("Enabling isolation segment %s for org %s as %s…", isolationSegmentName, organizationName, userName))
					Eventually(session).Should(Say("OK"))
					Eventually(session).Should(Exit(0))
				})

				Context("when the isolation is already enabled", func() {
					BeforeEach(func() {
						Eventually(helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)).Should(Exit(0))
					})

					It("displays OK", func() {
						session := helpers.CF("enable-org-isolation", isolationSegmentName, organizationName)
						Eventually(session).Should(Say("Enabling isolation segment %s for org %s as %s…", isolationSegmentName, organizationName, userName))
						Eventually(session).Should(Say("OK"))
						Eventually(session).Should(Exit(0))
					})
				})
			})
		})
	})
})
<|endoftext|>