<commit_before>package q

import "github.com/oov/q/qutil"

// Interval represents intervals in SQL statements.
type Interval interface {
	Value() int
	Unit() qutil.IntervalUnit
}

type (
	years   int
	months  int
	days    int
	hours   int
	minutes int
	seconds int
)

func (i years) Value() int   { return int(i) }
func (i months) Value() int  { return int(i) }
func (i days) Value() int    { return int(i) }
func (i hours) Value() int   { return int(i) }
func (i minutes) Value() int { return int(i) }
func (i seconds) Value() int { return int(i) }

func (i years) Unit() qutil.IntervalUnit   { return qutil.Year }
func (i months) Unit() qutil.IntervalUnit  { return qutil.Month }
func (i days) Unit() qutil.IntervalUnit    { return qutil.Day }
func (i hours) Unit() qutil.IntervalUnit   { return qutil.Hour }
func (i minutes) Unit() qutil.IntervalUnit { return qutil.Minute }
func (i seconds) Unit() qutil.IntervalUnit { return qutil.Second }

// Years creates Interval such as "INTERVAL n YEAR".
func Years(n int) Interval { return years(n) }

// Months creates Interval such as "INTERVAL n MONTH".
func Months(n int) Interval { return months(n) }

// Days creates Interval such as "INTERVAL n DAY".
func Days(n int) Interval { return days(n) }

// Hours creates Interval such as "INTERVAL n HOUR".
func Hours(n int) Interval { return hours(n) }

// Minutes creates Interval such as "INTERVAL n MINUTE".
func Minutes(n int) Interval { return minutes(n) }

// Seconds creates Interval such as "INTERVAL n SECOND".
func Seconds(n int) Interval { return seconds(n) }

type addIntervalFunc struct {
	V         interface{}
	Intervals []qutil.Interval
}

func (f *addIntervalFunc) String() string               { return expressionToString(f) }
func (f *addIntervalFunc) C(aliasName ...string) Column { return columnExpr(f, aliasName...) }
func (f *addIntervalFunc) WriteExpression(ctx *qutil.Context, buf []byte) []byte {
	return ctx.Dialect.AddInterval(ctx, buf, f.V, f.Intervals...)
}

// AddInterval creates Function such as "v + INTERVAL intervals[n] YEAR + ...".
func AddInterval(v interface{}, intervals ...Interval) Function {
	r := &addIntervalFunc{V: interfaceToExpression(v), Intervals: make([]qutil.Interval, len(intervals))}
	for i, v := range intervals {
		r.Intervals[i] = v
	}
	return r
}
<commit_msg>avoid unnecessary memory allocation<commit_after>package q

import "github.com/oov/q/qutil"

// Interval represents intervals in SQL statements.
type Interval interface {
	Value() int
	Unit() qutil.IntervalUnit
}

type (
	years   int
	months  int
	days    int
	hours   int
	minutes int
	seconds int
)

func (i years) Value() int   { return int(i) }
func (i months) Value() int  { return int(i) }
func (i days) Value() int    { return int(i) }
func (i hours) Value() int   { return int(i) }
func (i minutes) Value() int { return int(i) }
func (i seconds) Value() int { return int(i) }

func (i years) Unit() qutil.IntervalUnit   { return qutil.Year }
func (i months) Unit() qutil.IntervalUnit  { return qutil.Month }
func (i days) Unit() qutil.IntervalUnit    { return qutil.Day }
func (i hours) Unit() qutil.IntervalUnit   { return qutil.Hour }
func (i minutes) Unit() qutil.IntervalUnit { return qutil.Minute }
func (i seconds) Unit() qutil.IntervalUnit { return qutil.Second }

// Years creates Interval such as "INTERVAL n YEAR".
func Years(n int) Interval { return years(n) }

// Months creates Interval such as "INTERVAL n MONTH".
func Months(n int) Interval { return months(n) }

// Days creates Interval such as "INTERVAL n DAY".
func Days(n int) Interval { return days(n) }

// Hours creates Interval such as "INTERVAL n HOUR".
func Hours(n int) Interval { return hours(n) }

// Minutes creates Interval such as "INTERVAL n MINUTE".
func Minutes(n int) Interval { return minutes(n) }

// Seconds creates Interval such as "INTERVAL n SECOND".
func Seconds(n int) Interval { return seconds(n) }

type addIntervalFunc struct {
	V         interface{}
	Intervals []qutil.Interval
}

func (f *addIntervalFunc) String() string               { return expressionToString(f) }
func (f *addIntervalFunc) C(aliasName ...string) Column { return columnExpr(f, aliasName...) }
func (f *addIntervalFunc) WriteExpression(ctx *qutil.Context, buf []byte) []byte {
	return ctx.Dialect.AddInterval(ctx, buf, f.V, f.Intervals...)
}

// AddInterval creates Function such as "v + INTERVAL intervals[n] YEAR + ...".
func AddInterval(v interface{}, intervals ...Interval) Function {
	ivs := make([]qutil.Interval, len(intervals))
	for i, v := range intervals {
		ivs[i] = v
	}
	return &addIntervalFunc{V: v, Intervals: ivs}
}
<|endoftext|>


<commit_before>/*                          _       _
 *__      _____  __ ___   ___  __ _| |_ ___
 *\ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
 * \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
 *  \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
 *
 * Copyright © 2016 - 2019 Weaviate. All rights reserved.
 * LICENSE: https://github.com/creativesoftwarefdn/weaviate/blob/develop/LICENSE.md
 * DESIGN & CONCEPT: Bob van Luijt (@bobvanluijt)
 * CONTACT: hello@creativesoftwarefdn.org
 */
package etcd

import (
	"context"
	"fmt"

	"github.com/creativesoftwarefdn/weaviate/contextionary"
	"github.com/creativesoftwarefdn/weaviate/database/schema"
	"github.com/creativesoftwarefdn/weaviate/database/schema/kind"
	"github.com/creativesoftwarefdn/weaviate/models"
	"github.com/go-openapi/strfmt"
)

func (l *etcdSchemaManager) GetSchema() schema.Schema {
	return schema.Schema{
		Actions: l.schemaState.ActionSchema,
		Things:  l.schemaState.ThingSchema,
	}
}

func (l *etcdSchemaManager) UpdateMeta(ctx context.Context, kind kind.Kind,
	atContext strfmt.URI, maintainer strfmt.Email, name string) error {
	semanticSchema := l.schemaState.SchemaFor(kind)
	semanticSchema.AtContext = atContext
	semanticSchema.Maintainer = maintainer
	semanticSchema.Name = name

	return l.saveSchema(ctx)
}

func (l *etcdSchemaManager) SetContextionary(context contextionary.Contextionary) {
	l.contextionary = context
}

func (l *etcdSchemaManager) AddClass(ctx context.Context, kind kind.Kind, class *models.SemanticSchemaClass) error {
	err := l.validateCanAddClass(kind, class)
	if err != nil {
		return err
	} else {
		semanticSchema := l.schemaState.SchemaFor(kind)
		semanticSchema.Classes = append(semanticSchema.Classes, class)
		err := l.saveSchema(ctx)
		if err != nil {
			return err
		}

		return l.connectorMigrator.AddClass(ctx, kind, class)
	}
}

func (l *etcdSchemaManager) DropClass(ctx context.Context, kind kind.Kind, className string) error {
	semanticSchema := l.schemaState.SchemaFor(kind)

	var classIdx int = -1
	for idx, class := range semanticSchema.Classes {
		if class.Class == className {
			classIdx = idx
			break
		}
	}

	if classIdx == -1 {
		return fmt.Errorf("Could not find class '%s'", className)
	}

	semanticSchema.Classes[classIdx] = semanticSchema.Classes[len(semanticSchema.Classes)-1]
	semanticSchema.Classes[len(semanticSchema.Classes)-1] = nil // to prevent leaking this pointer.
	semanticSchema.Classes = semanticSchema.Classes[:len(semanticSchema.Classes)-1]

	err := l.saveSchema(ctx)
	if err != nil {
		return err
	}

	return l.connectorMigrator.DropClass(ctx, kind, className)
}

func (l *etcdSchemaManager) UpdateClass(ctx context.Context, kind kind.Kind, className string, newClassName *string, newKeywords *models.SemanticSchemaKeywords) error {
	semanticSchema := l.schemaState.SchemaFor(kind)

	class, err := schema.GetClassByName(semanticSchema, className)
	if err != nil {
		return err
	}

	classNameAfterUpdate := className
	keywordsAfterUpdate := class.Keywords

	// First validate the request
	if newClassName != nil {
		err = l.validateClassNameUniqueness(*newClassName)
		classNameAfterUpdate = *newClassName
		if err != nil {
			return err
		}
	}

	if newKeywords != nil {
		keywordsAfterUpdate = *newKeywords
	}

	// Validate name / keywords in contextionary
	l.validateClassNameOrKeywordsCorrect(kind, classNameAfterUpdate, keywordsAfterUpdate)

	// Validated! Now apply the changes.
	class.Class = classNameAfterUpdate
	class.Keywords = keywordsAfterUpdate

	err = l.saveSchema(ctx)

	if err != nil {
		return nil
	}

	return l.connectorMigrator.UpdateClass(ctx, kind, className, newClassName, newKeywords)
}

func (l *etcdSchemaManager) AddProperty(ctx context.Context, kind kind.Kind, className string, prop *models.SemanticSchemaClassProperty) error {
	semanticSchema := l.schemaState.SchemaFor(kind)
	class, err := schema.GetClassByName(semanticSchema, className)
	if err != nil {
		return err
	}

	err = l.validateCanAddProperty(prop, class)
	if err != nil {
		return err
	}

	class.Properties = append(class.Properties, prop)

	err = l.saveSchema(ctx)

	if err != nil {
		return nil
	}

	return l.connectorMigrator.AddProperty(ctx, kind, className, prop)
}

func (l *etcdSchemaManager) UpdateProperty(ctx context.Context, kind kind.Kind, className string, propName string, newName *string, newKeywords *models.SemanticSchemaKeywords) error {
	semanticSchema := l.schemaState.SchemaFor(kind)
	class, err := schema.GetClassByName(semanticSchema, className)
	if err != nil {
		return err
	}

	prop, err := schema.GetPropertyByName(class, propName)
	if err != nil {
		return err
	}

	propNameAfterUpdate := propName
	keywordsAfterUpdate := prop.Keywords

	if newName != nil {
		// verify uniqueness
		err = validatePropertyNameUniqueness(*newName, class)
		propNameAfterUpdate = *newName
		if err != nil {
			return err
		}
	}

	if newKeywords != nil {
		keywordsAfterUpdate = *newKeywords
	}

	// Validate name / keywords in contextionary
	l.validatePropertyNameOrKeywordsCorrect(className, propNameAfterUpdate, keywordsAfterUpdate)

	// Validated! Now apply the changes.
	prop.Name = propNameAfterUpdate
	prop.Keywords = keywordsAfterUpdate

	err = l.saveSchema(ctx)

	if err != nil {
		return nil
	}

	return l.connectorMigrator.UpdateProperty(ctx, kind, className, propName, newName, newKeywords)
}

func (l *etcdSchemaManager) UpdatePropertyAddDataType(ctx context.Context, kind kind.Kind, className string, propName string, newDataType string) error {
	semanticSchema := l.schemaState.SchemaFor(kind)
	class, err := schema.GetClassByName(semanticSchema, className)
	if err != nil {
		return err
	}

	prop, err := schema.GetPropertyByName(class, propName)
	if err != nil {
		return err
	}

	if dataTypeAlreadyContained(prop.AtDataType, newDataType) {
		return nil
	}

	prop.AtDataType = append(prop.AtDataType, newDataType)
	err = l.saveSchema(ctx)

	if err != nil {
		return nil
	}

	return l.connectorMigrator.UpdatePropertyAddDataType(ctx, kind, className, propName, newDataType)
}

func dataTypeAlreadyContained(haystack []string, needle string) bool {
	for _, hay := range haystack {
		if hay == needle {
			return true
		}
	}
	return false
}

func (l *etcdSchemaManager) DropProperty(ctx context.Context, kind kind.Kind, className string, propName string) error {
	semanticSchema := l.schemaState.SchemaFor(kind)
	class, err := schema.GetClassByName(semanticSchema, className)
	if err != nil {
		return err
	}

	var propIdx int = -1
	for idx, prop := range class.Properties {
		if prop.Name == propName {
			propIdx = idx
			break
		}
	}

	if propIdx == -1 {
		return fmt.Errorf("Could not find property '%s'", propName)
	}

	class.Properties[propIdx] = class.Properties[len(class.Properties)-1]
	class.Properties[len(class.Properties)-1] = nil // to prevent leaking this pointer.
	class.Properties = class.Properties[:len(class.Properties)-1]

	err = l.saveSchema(ctx)

	if err != nil {
		return nil
	}

	return l.connectorMigrator.DropProperty(ctx, kind, className, propName)
}
<commit_msg>gh-811: don't ignore validation on UpdateSchemaClass<commit_after>/*                          _       _
 *__      _____  __ ___   ___  __ _| |_ ___
 *\ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
 * \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
 *  \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
 *
 * Copyright © 2016 - 2019 Weaviate. All rights reserved.
 * LICENSE: https://github.com/creativesoftwarefdn/weaviate/blob/develop/LICENSE.md
 * DESIGN & CONCEPT: Bob van Luijt (@bobvanluijt)
 * CONTACT: hello@creativesoftwarefdn.org
 */
package etcd

import (
	"context"
	"fmt"

	"github.com/creativesoftwarefdn/weaviate/contextionary"
	"github.com/creativesoftwarefdn/weaviate/database/schema"
	"github.com/creativesoftwarefdn/weaviate/database/schema/kind"
	"github.com/creativesoftwarefdn/weaviate/models"
	"github.com/go-openapi/strfmt"
)

func (l *etcdSchemaManager) GetSchema() schema.Schema {
	return schema.Schema{
		Actions: l.schemaState.ActionSchema,
		Things:  l.schemaState.ThingSchema,
	}
}

func (l *etcdSchemaManager) UpdateMeta(ctx context.Context, kind kind.Kind,
	atContext strfmt.URI, maintainer strfmt.Email, name string) error {
	semanticSchema := l.schemaState.SchemaFor(kind)
	semanticSchema.AtContext = atContext
	semanticSchema.Maintainer = maintainer
	semanticSchema.Name = name

	return l.saveSchema(ctx)
}

func (l *etcdSchemaManager) SetContextionary(context contextionary.Contextionary) {
	l.contextionary = context
}

func (l *etcdSchemaManager) AddClass(ctx context.Context, kind kind.Kind, class *models.SemanticSchemaClass) error {
	err := l.validateCanAddClass(kind, class)
	if err != nil {
		return err
	} else {
		semanticSchema := l.schemaState.SchemaFor(kind)
		semanticSchema.Classes = append(semanticSchema.Classes, class)
		err := l.saveSchema(ctx)
		if err != nil {
			return err
		}

		return l.connectorMigrator.AddClass(ctx, kind, class)
	}
}

func (l *etcdSchemaManager) DropClass(ctx context.Context, kind kind.Kind, className string) error {
	semanticSchema := l.schemaState.SchemaFor(kind)

	var classIdx int = -1
	for idx, class := range semanticSchema.Classes {
		if class.Class == className {
			classIdx = idx
			break
		}
	}

	if classIdx == -1 {
		return fmt.Errorf("Could not find class '%s'", className)
	}

	semanticSchema.Classes[classIdx] = semanticSchema.Classes[len(semanticSchema.Classes)-1]
	semanticSchema.Classes[len(semanticSchema.Classes)-1] = nil // to prevent leaking this pointer.
	semanticSchema.Classes = semanticSchema.Classes[:len(semanticSchema.Classes)-1]

	err := l.saveSchema(ctx)
	if err != nil {
		return err
	}

	return l.connectorMigrator.DropClass(ctx, kind, className)
}

func (l *etcdSchemaManager) UpdateClass(ctx context.Context, kind kind.Kind, className string, newClassName *string, newKeywords *models.SemanticSchemaKeywords) error {
	semanticSchema := l.schemaState.SchemaFor(kind)

	class, err := schema.GetClassByName(semanticSchema, className)
	if err != nil {
		return err
	}

	classNameAfterUpdate := className
	keywordsAfterUpdate := class.Keywords

	// First validate the request
	if newClassName != nil {
		err = l.validateClassNameUniqueness(*newClassName)
		classNameAfterUpdate = *newClassName
		if err != nil {
			return err
		}
	}

	if newKeywords != nil {
		keywordsAfterUpdate = *newKeywords
	}

	// Validate name / keywords in contextionary
	if err = l.validateClassNameOrKeywordsCorrect(kind, classNameAfterUpdate, keywordsAfterUpdate); err != nil {
		return err
	}

	// Validated! Now apply the changes.
	class.Class = classNameAfterUpdate
	class.Keywords = keywordsAfterUpdate

	err = l.saveSchema(ctx)

	if err != nil {
		return nil
	}

	return l.connectorMigrator.UpdateClass(ctx, kind, className, newClassName, newKeywords)
}

func (l *etcdSchemaManager) AddProperty(ctx context.Context, kind kind.Kind, className string, prop *models.SemanticSchemaClassProperty) error {
	semanticSchema := l.schemaState.SchemaFor(kind)
	class, err := schema.GetClassByName(semanticSchema, className)
	if err != nil {
		return err
	}

	err = l.validateCanAddProperty(prop, class)
	if err != nil {
		return err
	}

	class.Properties = append(class.Properties, prop)

	err = l.saveSchema(ctx)

	if err != nil {
		return nil
	}

	return l.connectorMigrator.AddProperty(ctx, kind, className, prop)
}

func (l *etcdSchemaManager) UpdateProperty(ctx context.Context, kind kind.Kind, className string, propName string, newName *string, newKeywords *models.SemanticSchemaKeywords) error {
	semanticSchema := l.schemaState.SchemaFor(kind)
	class, err := schema.GetClassByName(semanticSchema, className)
	if err != nil {
		return err
	}

	prop, err := schema.GetPropertyByName(class, propName)
	if err != nil {
		return err
	}

	propNameAfterUpdate := propName
	keywordsAfterUpdate := prop.Keywords

	if newName != nil {
		// verify uniqueness
		err = validatePropertyNameUniqueness(*newName, class)
		propNameAfterUpdate = *newName
		if err != nil {
			return err
		}
	}

	if newKeywords != nil {
		keywordsAfterUpdate = *newKeywords
	}

	// Validate name / keywords in contextionary
	l.validatePropertyNameOrKeywordsCorrect(className, propNameAfterUpdate, keywordsAfterUpdate)

	// Validated! Now apply the changes.
	prop.Name = propNameAfterUpdate
	prop.Keywords = keywordsAfterUpdate

	err = l.saveSchema(ctx)

	if err != nil {
		return nil
	}

	return l.connectorMigrator.UpdateProperty(ctx, kind, className, propName, newName, newKeywords)
}

func (l *etcdSchemaManager) UpdatePropertyAddDataType(ctx context.Context, kind kind.Kind, className string, propName string, newDataType string) error {
	semanticSchema := l.schemaState.SchemaFor(kind)
	class, err := schema.GetClassByName(semanticSchema, className)
	if err != nil {
		return err
	}

	prop, err := schema.GetPropertyByName(class, propName)
	if err != nil {
		return err
	}

	if dataTypeAlreadyContained(prop.AtDataType, newDataType) {
		return nil
	}

	prop.AtDataType = append(prop.AtDataType, newDataType)
	err = l.saveSchema(ctx)

	if err != nil {
		return nil
	}

	return l.connectorMigrator.UpdatePropertyAddDataType(ctx, kind, className, propName, newDataType)
}

func dataTypeAlreadyContained(haystack []string, needle string) bool {
	for _, hay := range haystack {
		if hay == needle {
			return true
		}
	}
	return false
}

func (l *etcdSchemaManager) DropProperty(ctx context.Context, kind kind.Kind, className string, propName string) error {
	semanticSchema := l.schemaState.SchemaFor(kind)
	class, err := schema.GetClassByName(semanticSchema, className)
	if err != nil {
		return err
	}

	var propIdx int = -1
	for idx, prop := range class.Properties {
		if prop.Name == propName {
			propIdx = idx
			break
		}
	}

	if propIdx == -1 {
		return fmt.Errorf("Could not find property '%s'", propName)
	}

	class.Properties[propIdx] = class.Properties[len(class.Properties)-1]
	class.Properties[len(class.Properties)-1] = nil // to prevent leaking this pointer.
	class.Properties = class.Properties[:len(class.Properties)-1]

	err = l.saveSchema(ctx)

	if err != nil {
		return nil
	}

	return l.connectorMigrator.DropProperty(ctx, kind, className, propName)
}
<|endoftext|>


<commit_before>package iptables

import (
	"errors"
	"fmt"
	"net"
	"os"
	"os/exec"
	"strconv"
	"strings"
)

type Action string

const (
	Add    Action = "-A"
	Delete Action = "-D"
)

var (
	ErrIptablesNotFound = errors.New("Iptables not found")
	nat                 = []string{"-t", "nat"}
)

type Chain struct {
	Name   string
	Bridge string
}

func NewChain(name, bridge string) (*Chain, error) {
	if output, err := Raw("-t", "nat", "-N", name); err != nil {
		return nil, err
	} else if len(output) != 0 {
		return nil, fmt.Errorf("Error creating new iptables chain: %s", output)
	}
	chain := &Chain{
		Name:   name,
		Bridge: bridge,
	}

	if err := chain.Prerouting(Add, "-m", "addrtype", "--dst-type", "LOCAL"); err != nil {
		return nil, fmt.Errorf("Failed to inject docker in PREROUTING chain: %s", err)
	}
	if err := chain.Output(Add, "-m", "addrtype", "--dst-type", "LOCAL", "!", "--dst", "127.0.0.0/8"); err != nil {
		return nil, fmt.Errorf("Failed to inject docker in OUTPUT chain: %s", err)
	}
	return chain, nil
}

func RemoveExistingChain(name string) error {
	chain := &Chain{
		Name: name,
	}
	return chain.Remove()
}

func (c *Chain) Forward(action Action, ip net.IP, port int, proto, dest_addr string, dest_port int) error {
	daddr := ip.String()
	if ip.IsUnspecified() {
		// iptables interprets "0.0.0.0" as "0.0.0.0/32", whereas we
		// want "0.0.0.0/0". "0/0" is correctly interpreted as "any
		// value" by both iptables and ip6tables.
		daddr = "0/0"
	}
	if output, err := Raw("-t", "nat", fmt.Sprint(action), c.Name,
		"-p", proto,
		"-d", daddr,
		"--dport", strconv.Itoa(port),
		"!", "-i", c.Bridge,
		"-j", "DNAT",
		"--to-destination", net.JoinHostPort(dest_addr, strconv.Itoa(dest_port))); err != nil {
		return err
	} else if len(output) != 0 {
		return fmt.Errorf("Error iptables forward: %s", output)
	}

	fAction := action
	if fAction == Add {
		fAction = "-I"
	}
	if output, err := Raw(string(fAction), "FORWARD",
		"!", "-i", c.Bridge,
		"-o", c.Bridge,
		"-p", proto,
		"-d", dest_addr,
		"--dport", strconv.Itoa(dest_port),
		"-j", "ACCEPT"); err != nil {
		return err
	} else if len(output) != 0 {
		return fmt.Errorf("Error iptables forward: %s", output)
	}

	return nil
}

func (c *Chain) Prerouting(action Action, args ...string) error {
	a := append(nat, fmt.Sprint(action), "PREROUTING")
	if len(args) > 0 {
		a = append(a, args...)
	}
	if output, err := Raw(append(a, "-j", c.Name)...); err != nil {
		return err
	} else if len(output) != 0 {
		return fmt.Errorf("Error iptables prerouting: %s", output)
	}
	return nil
}

func (c *Chain) Output(action Action, args ...string) error {
	a := append(nat, fmt.Sprint(action), "OUTPUT")
	if len(args) > 0 {
		a = append(a, args...)
	}
	if output, err := Raw(append(a, "-j", c.Name)...); err != nil {
		return err
	} else if len(output) != 0 {
		return fmt.Errorf("Error iptables output: %s", output)
	}
	return nil
}

func (c *Chain) Remove() error {
	// Ignore errors - This could mean the chains were never set up
	c.Prerouting(Delete, "-m", "addrtype", "--dst-type", "LOCAL")
	c.Output(Delete, "-m", "addrtype", "--dst-type", "LOCAL", "!", "--dst", "127.0.0.0/8")
	c.Output(Delete, "-m", "addrtype", "--dst-type", "LOCAL") // Created in versions <= 0.1.6

	c.Prerouting(Delete)
	c.Output(Delete)

	Raw("-t", "nat", "-F", c.Name)
	Raw("-t", "nat", "-X", c.Name)

	return nil
}

// Check if an existing rule exists
func Exists(args ...string) bool {
	if _, err := Raw(append([]string{"-C"}, args...)...); err != nil {
		return false
	}
	return true
}

func Raw(args ...string) ([]byte, error) {
	path, err := exec.LookPath("iptables")
	if err != nil {
		return nil, ErrIptablesNotFound
	}
	if os.Getenv("DEBUG") != "" {
		fmt.Printf("[DEBUG] [iptables]: %s, %v\n", path, args)
	}
	output, err := exec.Command(path, args...).CombinedOutput()
	if err != nil {
		return nil, fmt.Errorf("iptables failed: iptables %v: %s (%s)", strings.Join(args, " "), output, err)
	}
	return output, err
}
<commit_msg>pkg/iptables: Support hairpin NAT without going through docker server<commit_after>package iptables

import (
	"errors"
	"fmt"
	"net"
	"os"
	"os/exec"
	"strconv"
	"strings"
)

type Action string

const (
	Add    Action = "-A"
	Delete Action = "-D"
)

var (
	ErrIptablesNotFound = errors.New("Iptables not found")
	nat                 = []string{"-t", "nat"}
)

type Chain struct {
	Name   string
	Bridge string
}

func NewChain(name, bridge string) (*Chain, error) {
	if output, err := Raw("-t", "nat", "-N", name); err != nil {
		return nil, err
	} else if len(output) != 0 {
		return nil, fmt.Errorf("Error creating new iptables chain: %s", output)
	}
	chain := &Chain{
		Name:   name,
		Bridge: bridge,
	}

	if err := chain.Prerouting(Add, "-m", "addrtype", "--dst-type", "LOCAL"); err != nil {
		return nil, fmt.Errorf("Failed to inject docker in PREROUTING chain: %s", err)
	}
	if err := chain.Output(Add, "-m", "addrtype", "--dst-type", "LOCAL", "!", "--dst", "127.0.0.0/8"); err != nil {
		return nil, fmt.Errorf("Failed to inject docker in OUTPUT chain: %s", err)
	}
	return chain, nil
}

func RemoveExistingChain(name string) error {
	chain := &Chain{
		Name: name,
	}
	return chain.Remove()
}

func (c *Chain) Forward(action Action, ip net.IP, port int, proto, dest_addr string, dest_port int) error {
	daddr := ip.String()
	if ip.IsUnspecified() {
		// iptables interprets "0.0.0.0" as "0.0.0.0/32", whereas we
		// want "0.0.0.0/0". "0/0" is correctly interpreted as "any
		// value" by both iptables and ip6tables.
		daddr = "0/0"
	}
	if output, err := Raw("-t", "nat", fmt.Sprint(action), c.Name,
		"-p", proto,
		"-d", daddr,
		"--dport", strconv.Itoa(port),
		"-j", "DNAT",
		"--to-destination", net.JoinHostPort(dest_addr, strconv.Itoa(dest_port))); err != nil {
		return err
	} else if len(output) != 0 {
		return fmt.Errorf("Error iptables forward: %s", output)
	}

	fAction := action
	if fAction == Add {
		fAction = "-I"
	}
	if output, err := Raw(string(fAction), "FORWARD",
		"!", "-i", c.Bridge,
		"-o", c.Bridge,
		"-p", proto,
		"-d", dest_addr,
		"--dport", strconv.Itoa(dest_port),
		"-j", "ACCEPT"); err != nil {
		return err
	} else if len(output) != 0 {
		return fmt.Errorf("Error iptables forward: %s", output)
	}

	return nil
}

func (c *Chain) Prerouting(action Action, args ...string) error {
	a := append(nat, fmt.Sprint(action), "PREROUTING")
	if len(args) > 0 {
		a = append(a, args...)
	}
	if output, err := Raw(append(a, "-j", c.Name)...); err != nil {
		return err
	} else if len(output) != 0 {
		return fmt.Errorf("Error iptables prerouting: %s", output)
	}
	return nil
}

func (c *Chain) Output(action Action, args ...string) error {
	a := append(nat, fmt.Sprint(action), "OUTPUT")
	if len(args) > 0 {
		a = append(a, args...)
	}
	if output, err := Raw(append(a, "-j", c.Name)...); err != nil {
		return err
	} else if len(output) != 0 {
		return fmt.Errorf("Error iptables output: %s", output)
	}
	return nil
}

func (c *Chain) Remove() error {
	// Ignore errors - This could mean the chains were never set up
	c.Prerouting(Delete, "-m", "addrtype", "--dst-type", "LOCAL")
	c.Output(Delete, "-m", "addrtype", "--dst-type", "LOCAL", "!", "--dst", "127.0.0.0/8")
	c.Output(Delete, "-m", "addrtype", "--dst-type", "LOCAL") // Created in versions <= 0.1.6

	c.Prerouting(Delete)
	c.Output(Delete)

	Raw("-t", "nat", "-F", c.Name)
	Raw("-t", "nat", "-X", c.Name)

	return nil
}

// Check if an existing rule exists
func Exists(args ...string) bool {
	if _, err := Raw(append([]string{"-C"}, args...)...); err != nil {
		return false
	}
	return true
}

func Raw(args ...string) ([]byte, error) {
	path, err := exec.LookPath("iptables")
	if err != nil {
		return nil, ErrIptablesNotFound
	}
	if os.Getenv("DEBUG") != "" {
		fmt.Printf("[DEBUG] [iptables]: %s, %v\n", path, args)
	}
	output, err := exec.Command(path, args...).CombinedOutput()
	if err != nil {
		return nil, fmt.Errorf("iptables failed: iptables %v: %s (%s)", strings.Join(args, " "), output, err)
	}
	return output, err
}
<|endoftext|>


<commit_before>package awscloudwatch

import (
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"golang.org/x/net/context"

	"github.com/cloudstax/openmanage/common"
	"github.com/cloudstax/openmanage/utils"
)

func TestCloudWatchLog(t *testing.T) {
	region := "us-east-1"
	config := aws.NewConfig().WithRegion(region)
	sess, err := session.NewSession(config)
	if err != nil {
		t.Fatalf("NewSession error %s", err)
	}

	ins := NewLog(sess, region, common.ContainerPlatformECS)

	ctx := context.Background()
	uuid := utils.GenUUID()
	cluster := "cluster-" + uuid
	service := "service-" + uuid
	serviceUUID := "serviceuuid-" + uuid
	stream := "stream-" + uuid

	cfg := ins.CreateServiceLogConfig(ctx, cluster, service, serviceUUID)
	if cfg.Name != driverName {
		t.Fatalf("expect log driver name %s, got %s", driverName, cfg.Name)
	}

	cfg = ins.CreateLogConfigForStream(ctx, cluster, service, serviceUUID, stream)
	if cfg.Name != driverName {
		t.Fatalf("expect log driver name %s, got %s", driverName, cfg.Name)
	}
	if cfg.Options[logStream] != stream {
		t.Fatalf("expect log stream %s, got %s", stream, cfg.Options)
	}

	err = ins.InitializeServiceLogConfig(ctx, cluster, service, serviceUUID)
	if err != nil {
		t.Fatalf("InitializeServiceLogConfig error %s, cluster %s", err, cluster)
	}

	err = ins.DeleteServiceLogConfig(ctx, cluster, service, serviceUUID)
	if err != nil {
		t.Fatalf("DeleteServiceLogConfig error %s, cluster %s", err, cluster)
	}
}
<commit_msg>add log init/delete again test case<commit_after>package awscloudwatch

import (
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"golang.org/x/net/context"

	"github.com/cloudstax/openmanage/common"
	"github.com/cloudstax/openmanage/utils"
)

func TestCloudWatchLog(t *testing.T) {
	region := "us-east-1"
	config := aws.NewConfig().WithRegion(region)
	sess, err := session.NewSession(config)
	if err != nil {
		t.Fatalf("NewSession error %s", err)
	}

	ins := NewLog(sess, region, common.ContainerPlatformECS)

	ctx := context.Background()
	uuid := utils.GenUUID()
	cluster := "cluster-" + uuid
	service := "service-" + uuid
	serviceUUID := "serviceuuid-" + uuid
	stream := "stream-" + uuid

	cfg := ins.CreateServiceLogConfig(ctx, cluster, service, serviceUUID)
	if cfg.Name != driverName {
		t.Fatalf("expect log driver name %s, got %s", driverName, cfg.Name)
	}

	cfg = ins.CreateLogConfigForStream(ctx, cluster, service, serviceUUID, stream)
	if cfg.Name != driverName {
		t.Fatalf("expect log driver name %s, got %s", driverName, cfg.Name)
	}
	if cfg.Options[logStreamPrefix] != stream {
		t.Fatalf("expect log stream %s, got %s", stream, cfg.Options)
	}

	err = ins.InitializeServiceLogConfig(ctx, cluster, service, serviceUUID)
	if err != nil {
		t.Fatalf("InitializeServiceLogConfig error %s, cluster %s", err, cluster)
	}

	// initialize again to test creating the same log group
	err = ins.InitializeServiceLogConfig(ctx, cluster, service, serviceUUID)
	if err != nil {
		t.Fatalf("InitializeServiceLogConfig again error %s, cluster %s", err, cluster)
	}

	err = ins.DeleteServiceLogConfig(ctx, cluster, service, serviceUUID)
	if err != nil {
		t.Fatalf("DeleteServiceLogConfig error %s, cluster %s", err, cluster)
	}

	// delete again to test deleting unexist log group
	err = ins.DeleteServiceLogConfig(ctx, cluster, service, serviceUUID)
	if err != nil {
		t.Fatalf("DeleteServiceLogConfig again error %s, cluster %s", err, cluster)
	}
}
<|endoftext|>


<commit_before>package terraform

import (
	"fmt"
)

// NodeApplyableResource represents a resource that is "applyable":
// it is ready to be applied and is represented by a diff.
type NodeApplyableResource struct {
	*NodeAbstractResource
}

// GraphNodeCreator
func (n *NodeApplyableResource) CreateAddr() *ResourceAddress {
	return n.NodeAbstractResource.Addr
}

// GraphNodeEvalable
func (n *NodeApplyableResource) EvalTree() EvalNode {
	addr := n.NodeAbstractResource.Addr

	// stateId is the ID to put into the state
	stateId := addr.stateId()
	if addr.Index > -1 {
		stateId = fmt.Sprintf("%s.%d", stateId, addr.Index)
	}

	// Build the instance info. More of this will be populated during eval
	info := &InstanceInfo{
		Id:   stateId,
		Type: addr.Type,
	}

	// Build the resource for eval
	resource := &Resource{
		Name:       addr.Name,
		Type:       addr.Type,
		CountIndex: addr.Index,
	}
	if resource.CountIndex < 0 {
		resource.CountIndex = 0
	}

	// Determine the dependencies for the state. We use some older
	// code for this that we've used for a long time.
	var stateDeps []string
	{
		oldN := &graphNodeExpandedResource{Resource: n.Config}
		stateDeps = oldN.StateDependencies()
	}

	// Declare a bunch of variables that are used for state during
	// evaluation. Most of this are written to by-address below.
	var provider ResourceProvider
	var diff, diffApply *InstanceDiff
	var state *InstanceState
	var resourceConfig *ResourceConfig
	var err error
	var createNew bool
	var createBeforeDestroyEnabled bool

	return &EvalSequence{
		Nodes: []EvalNode{
			// Build the instance info
			&EvalInstanceInfo{
				Info: info,
			},

			// Get the saved diff for apply
			&EvalReadDiff{
				Name: stateId,
				Diff: &diffApply,
			},

			// We don't want to do any destroys
			&EvalIf{
				If: func(ctx EvalContext) (bool, error) {
					if diffApply == nil {
						return true, EvalEarlyExitError{}
					}

					if diffApply.GetDestroy() && diffApply.GetAttributesLen() == 0 {
						return true, EvalEarlyExitError{}
					}

					diffApply.SetDestroy(false)
					return true, nil
				},
				Then: EvalNoop{},
			},

			&EvalIf{
				If: func(ctx EvalContext) (bool, error) {
					destroy := false
					if diffApply != nil {
						destroy = diffApply.GetDestroy() || diffApply.RequiresNew()
					}

					createBeforeDestroyEnabled =
						n.Config.Lifecycle.CreateBeforeDestroy &&
							destroy

					return createBeforeDestroyEnabled, nil
				},
				Then: &EvalDeposeState{
					Name: stateId,
				},
			},

			&EvalInterpolate{
				Config:   n.Config.RawConfig.Copy(),
				Resource: resource,
				Output:   &resourceConfig,
			},
			&EvalGetProvider{
				Name:   n.ProvidedBy()[0],
				Output: &provider,
			},
			&EvalReadState{
				Name:   stateId,
				Output: &state,
			},
			// Re-run validation to catch any errors we missed, e.g. type
			// mismatches on computed values.
			&EvalValidateResource{
				Provider:       &provider,
				Config:         &resourceConfig,
				ResourceName:   n.Config.Name,
				ResourceType:   n.Config.Type,
				ResourceMode:   n.Config.Mode,
				IgnoreWarnings: true,
			},
			&EvalDiff{
				Info:       info,
				Config:     &resourceConfig,
				Resource:   n.Config,
				Provider:   &provider,
				Diff:       &diffApply,
				State:      &state,
				OutputDiff: &diffApply,
			},

			// Get the saved diff
			&EvalReadDiff{
				Name: stateId,
				Diff: &diff,
			},

			// Compare the diffs
			&EvalCompareDiff{
				Info: info,
				One:  &diff,
				Two:  &diffApply,
			},

			&EvalGetProvider{
				Name:   n.ProvidedBy()[0],
				Output: &provider,
			},
			&EvalReadState{
				Name:   stateId,
				Output: &state,
			},
			&EvalApply{
				Info:      info,
				State:     &state,
				Diff:      &diffApply,
				Provider:  &provider,
				Output:    &state,
				Error:     &err,
				CreateNew: &createNew,
			},
			&EvalWriteState{
				Name:         stateId,
				ResourceType: n.Config.Type,
				Provider:     n.Config.Provider,
				Dependencies: stateDeps,
				State:        &state,
			},
			&EvalApplyProvisioners{
				Info:           info,
				State:          &state,
				Resource:       n.Config,
				InterpResource: resource,
				CreateNew:      &createNew,
				Error:          &err,
			},
			&EvalIf{
				If: func(ctx EvalContext) (bool, error) {
					return createBeforeDestroyEnabled && err != nil, nil
				},
				Then: &EvalUndeposeState{
					Name:  stateId,
					State: &state,
				},
				Else: &EvalWriteState{
					Name:         stateId,
					ResourceType: n.Config.Type,
					Provider:     n.Config.Provider,
					Dependencies: stateDeps,
					State:        &state,
				},
			},

			// We clear the diff out here so that future nodes
			// don't see a diff that is already complete. There
			// is no longer a diff!
			&EvalWriteDiff{
				Name: stateId,
				Diff: nil,
			},

			&EvalApplyPost{
				Info:  info,
				State: &state,
				Error: &err,
			},
			&EvalUpdateStateHook{},
		},
	}
}
<commit_msg>terraform: new apply resource node supports data sources<commit_after>package terraform

import (
	"fmt"

	"github.com/hashicorp/terraform/config"
)

// NodeApplyableResource represents a resource that is "applyable":
// it is ready to be applied and is represented by a diff.
type NodeApplyableResource struct {
	*NodeAbstractResource
}

// GraphNodeCreator
func (n *NodeApplyableResource) CreateAddr() *ResourceAddress {
	return n.NodeAbstractResource.Addr
}

// GraphNodeEvalable
func (n *NodeApplyableResource) EvalTree() EvalNode {
	addr := n.NodeAbstractResource.Addr

	// stateId is the ID to put into the state
	stateId := addr.stateId()
	if addr.Index > -1 {
		stateId = fmt.Sprintf("%s.%d", stateId, addr.Index)
	}

	// Build the instance info. More of this will be populated during eval
	info := &InstanceInfo{
		Id:   stateId,
		Type: addr.Type,
	}

	// Build the resource for eval
	resource := &Resource{
		Name:       addr.Name,
		Type:       addr.Type,
		CountIndex: addr.Index,
	}
	if resource.CountIndex < 0 {
		resource.CountIndex = 0
	}

	// Determine the dependencies for the state. We use some older
	// code for this that we've used for a long time.
	var stateDeps []string
	{
		oldN := &graphNodeExpandedResource{Resource: n.Config}
		stateDeps = oldN.StateDependencies()
	}

	// Eval info is different depending on what kind of resource this is
	switch n.Config.Mode {
	case config.ManagedResourceMode:
		return n.evalTreeManagedResource(
			stateId, info, resource, stateDeps,
		)
	case config.DataResourceMode:
		return n.evalTreeDataResource(
			stateId, info, resource, stateDeps)
	default:
		panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
	}
}

func (n *NodeApplyableResource) evalTreeDataResource(
	stateId string, info *InstanceInfo,
	resource *Resource, stateDeps []string) EvalNode {
	var provider ResourceProvider
	var config *ResourceConfig
	var diff *InstanceDiff
	var state *InstanceState

	return &EvalSequence{
		Nodes: []EvalNode{
			// Get the saved diff for apply
			&EvalReadDiff{
				Name: stateId,
				Diff: &diff,
			},

			// Stop here if we don't actually have a diff
			&EvalIf{
				If: func(ctx EvalContext) (bool, error) {
					if diff == nil {
						return true, EvalEarlyExitError{}
					}

					if diff.GetAttributesLen() == 0 {
						return true, EvalEarlyExitError{}
					}

					return true, nil
				},
				Then: EvalNoop{},
			},

			// We need to re-interpolate the config here, rather than
			// just using the diff's values directly, because we've
			// potentially learned more variable values during the
			// apply pass that weren't known when the diff was produced.
			&EvalInterpolate{
				Config:   n.Config.RawConfig.Copy(),
				Resource: resource,
				Output:   &config,
			},

			&EvalGetProvider{
				Name:   n.ProvidedBy()[0],
				Output: &provider,
			},

			// Make a new diff with our newly-interpolated config.
			&EvalReadDataDiff{
				Info:     info,
				Config:   &config,
				Previous: &diff,
				Provider: &provider,
				Output:   &diff,
			},

			&EvalReadDataApply{
				Info:     info,
				Diff:     &diff,
				Provider: &provider,
				Output:   &state,
			},

			&EvalWriteState{
				Name:         stateId,
				ResourceType: n.Config.Type,
				Provider:     n.Config.Provider,
				Dependencies: stateDeps,
				State:        &state,
			},

			// Clear the diff now that we've applied it, so
			// later nodes won't see a diff that's now a no-op.
			&EvalWriteDiff{
				Name: stateId,
				Diff: nil,
			},

			&EvalUpdateStateHook{},
		},
	}
}

func (n *NodeApplyableResource) evalTreeManagedResource(
	stateId string, info *InstanceInfo,
	resource *Resource, stateDeps []string) EvalNode {
	// Declare a bunch of variables that are used for state during
	// evaluation. Most of this are written to by-address below.
	var provider ResourceProvider
	var diff, diffApply *InstanceDiff
	var state *InstanceState
	var resourceConfig *ResourceConfig
	var err error
	var createNew bool
	var createBeforeDestroyEnabled bool

	return &EvalSequence{
		Nodes: []EvalNode{
			// Build the instance info
			&EvalInstanceInfo{
				Info: info,
			},

			// Get the saved diff for apply
			&EvalReadDiff{
				Name: stateId,
				Diff: &diffApply,
			},

			// We don't want to do any destroys
			&EvalIf{
				If: func(ctx EvalContext) (bool, error) {
					if diffApply == nil {
						return true, EvalEarlyExitError{}
					}

					if diffApply.GetDestroy() && diffApply.GetAttributesLen() == 0 {
						return true, EvalEarlyExitError{}
					}

					diffApply.SetDestroy(false)
					return true, nil
				},
				Then: EvalNoop{},
			},

			&EvalIf{
				If: func(ctx EvalContext) (bool, error) {
					destroy := false
					if diffApply != nil {
						destroy = diffApply.GetDestroy() || diffApply.RequiresNew()
					}

					createBeforeDestroyEnabled =
						n.Config.Lifecycle.CreateBeforeDestroy &&
							destroy

					return createBeforeDestroyEnabled, nil
				},
				Then: &EvalDeposeState{
					Name: stateId,
				},
			},

			&EvalInterpolate{
				Config:   n.Config.RawConfig.Copy(),
				Resource: resource,
				Output:   &resourceConfig,
			},
			&EvalGetProvider{
				Name:   n.ProvidedBy()[0],
				Output: &provider,
			},
			&EvalReadState{
				Name:   stateId,
				Output: &state,
			},
			// Re-run validation to catch any errors we missed, e.g. type
			// mismatches on computed values.
			&EvalValidateResource{
				Provider:       &provider,
				Config:         &resourceConfig,
				ResourceName:   n.Config.Name,
				ResourceType:   n.Config.Type,
				ResourceMode:   n.Config.Mode,
				IgnoreWarnings: true,
			},
			&EvalDiff{
				Info:       info,
				Config:     &resourceConfig,
				Resource:   n.Config,
				Provider:   &provider,
				Diff:       &diffApply,
				State:      &state,
				OutputDiff: &diffApply,
			},

			// Get the saved diff
			&EvalReadDiff{
				Name: stateId,
				Diff: &diff,
			},

			// Compare the diffs
			&EvalCompareDiff{
				Info: info,
				One:  &diff,
				Two:  &diffApply,
			},

			&EvalGetProvider{
				Name:   n.ProvidedBy()[0],
				Output: &provider,
			},
			&EvalReadState{
				Name:   stateId,
				Output: &state,
			},
			&EvalApply{
				Info:      info,
				State:     &state,
				Diff:      &diffApply,
				Provider:  &provider,
				Output:    &state,
				Error:     &err,
				CreateNew: &createNew,
			},
			&EvalWriteState{
				Name:         stateId,
				ResourceType: n.Config.Type,
				Provider:     n.Config.Provider,
				Dependencies: stateDeps,
				State:        &state,
			},
			&EvalApplyProvisioners{
				Info:           info,
				State:          &state,
				Resource:       n.Config,
				InterpResource: resource,
				CreateNew:      &createNew,
				Error:          &err,
			},
			&EvalIf{
				If: func(ctx EvalContext) (bool, error) {
					return createBeforeDestroyEnabled && err != nil, nil
				},
				Then: &EvalUndeposeState{
					Name:  stateId,
					State: &state,
				},
				Else: &EvalWriteState{
					Name:         stateId,
					ResourceType: n.Config.Type,
					Provider:     n.Config.Provider,
					Dependencies: stateDeps,
					State:        &state,
				},
			},

			// We clear the diff out here so that future nodes
			// don't see a diff that is already complete. There
			// is no longer a diff!
			&EvalWriteDiff{
				Name: stateId,
				Diff: nil,
			},

			&EvalApplyPost{
				Info:  info,
				State: &state,
				Error: &err,
			},
			&EvalUpdateStateHook{},
		},
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2019-2021, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package validators

import (
	"fmt"
	"strings"
	"sync"

	"github.com/ava-labs/avalanchego/ids"
)

var _ Manager = &manager{}

// Manager holds the validator set of each subnet
type Manager interface {
	fmt.Stringer

	// Set a subnet's validator set
	Set(ids.ID, Set) error

	// AddWeight adds weight to a given validator on the given subnet
	AddWeight(ids.ID, ids.NodeID, uint64) error

	// RemoveWeight removes weight from a given validator on a given subnet
	RemoveWeight(ids.ID, ids.NodeID, uint64) error

	// GetValidators returns the validator set for the given subnet
	// Returns false if the subnet doesn't exist
	GetValidators(ids.ID) (Set, bool)

	// MaskValidator hides the named validator from future samplings
	MaskValidator(ids.NodeID) error

	// RevealValidator ensures the named validator is not hidden from future
	// samplings
	RevealValidator(ids.NodeID) error

	// Contains returns true if there is a validator with the specified ID
	// currently in the set.
	Contains(ids.ID, ids.NodeID) bool
}

// NewManager returns a new, empty manager
func NewManager() Manager {
	return &manager{
		subnetToVdrs: make(map[ids.ID]Set),
	}
}

type manager struct {
	lock sync.Mutex

	// Key: Subnet ID
	// Value: The validators that validate the subnet
	subnetToVdrs map[ids.ID]Set

	maskedVdrs ids.NodeIDSet
}

func (m *manager) Set(subnetID ids.ID, newSet Set) error {
	m.lock.Lock()
	defer m.lock.Unlock()

	oldSet, exists := m.subnetToVdrs[subnetID]
	if !exists {
		m.subnetToVdrs[subnetID] = newSet
		return nil
	}
	return oldSet.Set(newSet.List())
}

func (m *manager) AddWeight(subnetID ids.ID, vdrID ids.NodeID, weight uint64) error {
	m.lock.Lock()
	defer m.lock.Unlock()

	vdrs, ok := m.subnetToVdrs[subnetID]
	if !ok {
		vdrs = NewSet()
		for _, maskedVdrID := range m.maskedVdrs.List() {
			if err := vdrs.MaskValidator(maskedVdrID); err != nil {
				return err
			}
		}
		m.subnetToVdrs[subnetID] = vdrs
	}
	return vdrs.AddWeight(vdrID, weight)
}

func (m *manager) RemoveWeight(subnetID ids.ID, vdrID ids.NodeID, weight uint64) error {
	m.lock.Lock()
	defer m.lock.Unlock()

	if vdrs, ok := m.subnetToVdrs[subnetID]; ok {
		return vdrs.RemoveWeight(vdrID, weight)
	}
	return nil
}

func (m *manager) GetValidators(subnetID ids.ID) (Set, bool) {
	m.lock.Lock()
	defer m.lock.Unlock()

	vdrs, ok := m.subnetToVdrs[subnetID]
	return vdrs, ok
}

func (m *manager) MaskValidator(vdrID ids.NodeID) error {
	m.lock.Lock()
	defer m.lock.Unlock()

	if m.maskedVdrs.Contains(vdrID) {
		return nil
	}
	m.maskedVdrs.Add(vdrID)

	for _, vdrs := range m.subnetToVdrs {
		if err := vdrs.MaskValidator(vdrID); err != nil {
			return err
		}
	}
	return nil
}

func (m *manager) RevealValidator(vdrID ids.NodeID) error {
	m.lock.Lock()
	defer m.lock.Unlock()

	if !m.maskedVdrs.Contains(vdrID) {
		return nil
	}
	m.maskedVdrs.Remove(vdrID)

	for _, vdrs := range m.subnetToVdrs {
		if err := vdrs.RevealValidator(vdrID); err != nil {
			return err
		}
	}
	return nil
}

func (m *manager) Contains(subnetID ids.ID, vdrID ids.NodeID) bool {
	m.lock.Lock()
	defer m.lock.Unlock()

	vdrs, ok := m.subnetToVdrs[subnetID]
	if ok {
		return vdrs.Contains(vdrID)
	}
	return false
}

func (m *manager) String() string {
	m.lock.Lock()
	defer m.lock.Unlock()

	subnets := make([]ids.ID, 0, len(m.subnetToVdrs))
	for subnetID := range m.subnetToVdrs {
		subnets = append(subnets, subnetID)
	}
	ids.SortIDs(subnets)

	sb := strings.Builder{}

	sb.WriteString(fmt.Sprintf("Validator Manager: (Size = %d)",
		len(subnets),
	))
	for _, subnetID := range subnets {
		vdrs := m.subnetToVdrs[subnetID]
		sb.WriteString(fmt.Sprintf(
			"\n    Subnet[%s]: %s",
			subnetID,
			vdrs.PrefixedString("    "),
		))
	}

	return sb.String()
}
<commit_msg>Allow concurrent readers in the validator manager (#1497)<commit_after>// Copyright (C) 2019-2021, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package validators

import (
	"fmt"
	"strings"
	"sync"

	"github.com/ava-labs/avalanchego/ids"
)

var _ Manager = &manager{}

// Manager holds the validator set of each subnet
type Manager interface {
	fmt.Stringer

	// Set a subnet's validator set
	Set(ids.ID, Set) error

	// AddWeight adds weight to a given validator on the given subnet
	AddWeight(ids.ID, ids.NodeID, uint64) error

	// RemoveWeight removes weight from a given validator on a given subnet
	RemoveWeight(ids.ID, ids.NodeID, uint64) error

	// GetValidators returns the validator set for the given subnet
	// Returns false if the subnet doesn't exist
	GetValidators(ids.ID) (Set, bool)

	// MaskValidator hides the named validator from future samplings
	MaskValidator(ids.NodeID) error

	// RevealValidator ensures the named validator is not hidden from future
	// samplings
	RevealValidator(ids.NodeID) error

	// Contains returns true if there is a validator with the specified ID
	// currently in the set.
	Contains(ids.ID, ids.NodeID) bool
}

// NewManager returns a new, empty manager
func NewManager() Manager {
	return &manager{
		subnetToVdrs: make(map[ids.ID]Set),
	}
}

type manager struct {
	lock sync.RWMutex

	// Key: Subnet ID
	// Value: The validators that validate the subnet
	subnetToVdrs map[ids.ID]Set

	maskedVdrs ids.NodeIDSet
}

func (m *manager) Set(subnetID ids.ID, newSet Set) error {
	m.lock.Lock()
	defer m.lock.Unlock()

	oldSet, exists := m.subnetToVdrs[subnetID]
	if !exists {
		m.subnetToVdrs[subnetID] = newSet
		return nil
	}
	return oldSet.Set(newSet.List())
}

func (m *manager) AddWeight(subnetID ids.ID, vdrID ids.NodeID, weight uint64) error {
	m.lock.Lock()
	defer m.lock.Unlock()

	vdrs, ok := m.subnetToVdrs[subnetID]
	if !ok {
		vdrs = NewSet()
		for _, maskedVdrID := range m.maskedVdrs.List() {
			if err := vdrs.MaskValidator(maskedVdrID); err != nil {
				return err
			}
		}
		m.subnetToVdrs[subnetID] = vdrs
	}
	return vdrs.AddWeight(vdrID, weight)
}

func (m *manager) RemoveWeight(subnetID ids.ID, vdrID ids.NodeID, weight uint64) error {
	m.lock.Lock()
	defer m.lock.Unlock()

	if vdrs, ok := m.subnetToVdrs[subnetID]; ok {
		return vdrs.RemoveWeight(vdrID, weight)
	}
	return nil
}

func (m *manager) GetValidators(subnetID ids.ID) (Set, bool) {
	m.lock.RLock()
	defer m.lock.RUnlock()

	vdrs, ok := m.subnetToVdrs[subnetID]
	return vdrs, ok
}

func (m *manager) MaskValidator(vdrID ids.NodeID) error {
	m.lock.Lock()
	defer m.lock.Unlock()

	if m.maskedVdrs.Contains(vdrID) {
		return nil
	}
	m.maskedVdrs.Add(vdrID)

	for _, vdrs := range m.subnetToVdrs {
		if err := vdrs.MaskValidator(vdrID); err != nil {
			return err
		}
	}
	return nil
}

func (m *manager) RevealValidator(vdrID ids.NodeID) error {
	m.lock.Lock()
	defer m.lock.Unlock()

	if !m.maskedVdrs.Contains(vdrID) {
		return nil
	}
	m.maskedVdrs.Remove(vdrID)

	for _, vdrs := range m.subnetToVdrs {
		if err := vdrs.RevealValidator(vdrID); err != nil {
			return err
		}
	}
	return nil
}

func (m *manager) Contains(subnetID ids.ID, vdrID ids.NodeID) bool {
	m.lock.RLock()
	defer m.lock.RUnlock()

	vdrs, ok := m.subnetToVdrs[subnetID]
	if ok {
		return vdrs.Contains(vdrID)
	}
	return false
}

func (m *manager) String() string {
	m.lock.RLock()
	defer m.lock.RUnlock()

	subnets := make([]ids.ID, 0, len(m.subnetToVdrs))
	for subnetID := range m.subnetToVdrs {
		subnets = append(subnets, subnetID)
	}
	ids.SortIDs(subnets)

	sb := strings.Builder{}

	sb.WriteString(fmt.Sprintf("Validator Manager: (Size = %d)",
		len(subnets),
	))
	for _, subnetID := range subnets {
		vdrs := m.subnetToVdrs[subnetID]
		sb.WriteString(fmt.Sprintf(
			"\n    Subnet[%s]: %s",
			subnetID,
			vdrs.PrefixedString("    "),
		))
	}

	return sb.String()
}
<|endoftext|>


<commit_before>package maintain

import (
	"errors"
	"os"
	"syscall"
	"time"

	Bbs "github.com/cloudfoundry-incubator/runtime-schema/bbs"
	steno "github.com/cloudfoundry/gosteno"
)

type Maintainer struct {
	url               string
	id                string
	bbs               Bbs.FileServerBBS
	logger            *steno.Logger
	heartbeatInterval time.Duration
}

func New(url, id string, bbs Bbs.FileServerBBS, logger *steno.Logger, heartbeatInterval time.Duration) *Maintainer {
	return &Maintainer{
		url:               url,
		id:                id,
		bbs:               bbs,
		logger:            logger,
		heartbeatInterval: heartbeatInterval,
	}
}

func (m *Maintainer) Run(sigChan <-chan os.Signal, ready chan<- struct{}) error {
	presence, status, err := m.bbs.MaintainFileServerPresence(m.heartbeatInterval, m.url, m.id)
	if err != nil {
		m.logger.Errord(map[string]interface{}{
			"error": err.Error(),
		}, "file-server.maintain_presence_begin.failed")
	}

	if ready != nil {
		close(ready)
	}

	for {
		select {
		case sig := <-sigChan:
			switch sig {
			case syscall.SIGINT, syscall.SIGTERM:
				presence.Remove()
				return nil
			}

		case locked, ok := <-status:
			if !ok {
				return nil
			}

			if !locked {
				m.logger.Error("file-server.maintain_presence.failed")
				return errors.New("Failed to maintain presence")
			}
		}
	}
}
<commit_msg>maintainer retries on disconnect<commit_after>package maintain

import (
	"os"
	"time"

	Bbs "github.com/cloudfoundry-incubator/runtime-schema/bbs"
	steno "github.com/cloudfoundry/gosteno"
)

type Maintainer struct {
	url               string
	id                string
	bbs               Bbs.FileServerBBS
	logger            *steno.Logger
	heartbeatInterval time.Duration
}

func New(url, id string, bbs Bbs.FileServerBBS, logger *steno.Logger, heartbeatInterval time.Duration) *Maintainer {
	return &Maintainer{
		url:               url,
		id:                id,
		bbs:               bbs,
		logger:            logger,
		heartbeatInterval: heartbeatInterval,
	}
}

func (m *Maintainer) Run(sigChan <-chan os.Signal, ready chan<- struct{}) error {
	presence, status, err := m.bbs.MaintainFileServerPresence(m.heartbeatInterval, m.url, m.id)
	if err != nil {
		m.logger.Errord(map[string]interface{}{
			"error": err.Error(),
		}, "file-server.maintain_presence_begin.failed")
	}

	if ready != nil {
		close(ready)
	}

	for {
		select {
		case <-sigChan:
			presence.Remove()
			return nil

		case _, ok := <-status:
			if !ok {
				return nil
			}
		}
	}
}
<|endoftext|>


<commit_before>package makecoe

import (
	"fmt"
	"net/http"

	"strings"

	"time"

	"github.com/getcarina/carina/common"
	"github.com/getcarina/libcarina"
	"github.com/pkg/errors"
)

// MakeCOE is an adapter between the cli and Carina (make-coe)
type MakeCOE struct {
	client           *libcarina.CarinaClient
	clusterTypeCache map[int]*libcarina.ClusterType
	Account          *Account
}

func (carina *MakeCOE) init() error {
	if carina.client == nil {
		carinaClient, err := carina.Account.Authenticate()
		if err != nil {
			return err
		}
		carina.client = carinaClient
	}
	return nil
}

// GetQuotas retrieves the quotas set for the account
func (carina *MakeCOE) GetQuotas() (common.Quotas, error) {
	return &Quotas{}, nil
}

// CreateCluster creates a new cluster and prints the cluster information
func (carina *MakeCOE) CreateCluster(name string, template string, nodes int) (common.Cluster, error) {
	if template == "" {
		return nil, errors.New("--template is required")
	}

	err := carina.init()
	if err != nil {
		return nil, err
	}

	clusterType, err := carina.lookupClusterTypeByName(template)
	if err != nil {
		return nil, err
	}

	common.Log.WriteDebug("[make-coe] Creating a %d-node %s cluster hosted on %s named %s", nodes, clusterType.COE, clusterType.HostType, name)
	createOpts := &libcarina.CreateClusterOpts{
		Name:          name,
		ClusterTypeID: clusterType.ID,
		Nodes:         nodes,
	}

	result, err := carina.client.Create(createOpts)
	if err != nil {
		return nil, errors.Wrap(err, "[make-coe] Unable to create cluster")
	}

	cluster := &Cluster{Cluster: result}

	return cluster, nil
}

// GetClusterCredentials retrieves the TLS certificates and configuration scripts for a cluster by its id or name (if unique)
func (carina *MakeCOE) GetClusterCredentials(token string) (*libcarina.CredentialsBundle, error) {
	err := carina.init()
	if err != nil {
		return nil, err
	}

	common.Log.WriteDebug("[make-coe] Retrieving cluster credentials (%s)", token)
	creds, err := carina.client.GetCredentials(token)
	if err != nil {
		return nil, errors.Wrap(err, "[make-coe] Unable to retrieve the cluster credentials")
	}

	return creds, nil
}

// ListClusters prints out a list of the user's clusters to the console
func (carina *MakeCOE) ListClusters() ([]common.Cluster, error) {
	var clusters []common.Cluster

	err := carina.init()
	if err != nil {
		return clusters, err
	}

	common.Log.WriteDebug("[make-coe] Listing clusters")
	results, err := carina.client.List()
	if err != nil {
		return clusters, errors.Wrap(err, "[make-coe] Unable to list clusters")
	}

	for _, result := range results {
		cluster := &Cluster{Cluster: result}
		clusters = append(clusters, cluster)
	}

	return clusters, err
}

// ListClusterTemplates retrieves available templates for creating a new cluster
func (carina *MakeCOE) ListClusterTemplates() ([]common.ClusterTemplate, error) {
	err := carina.init()
	if err != nil {
		return nil, err
	}

	results, err := carina.listClusterTypes()
	if err != nil {
		return nil, err
	}

	var templates []common.ClusterTemplate
	for _, result := range results {
		template := &ClusterTemplate{ClusterType: result}
		templates = append(templates, template)
	}

	return templates, err
}

// RebuildCluster destroys and recreates the cluster by its id or name (if unique)
func (carina *MakeCOE) RebuildCluster(token string) (common.Cluster, error) {
	return nil, errors.New("[make-coe] Rebuilding clusters from the carina cli is not supported yet")
}

// GetCluster prints out a cluster's information to the console by its id or name (if unique)
func (carina *MakeCOE) GetCluster(token string) (common.Cluster, error) {
	err := carina.init()
	if err != nil {
		return nil, err
	}

	common.Log.WriteDebug("[make-coe] Retrieving cluster (%s)", token)
	result, err := carina.client.Get(token)
	if err != nil {
		return nil, errors.Wrap(err, fmt.Sprintf("[make-coe] Unable to retrieve cluster (%s)", token))
	}
	cluster := &Cluster{Cluster: result}

	return cluster, nil
}

// DeleteCluster permanently deletes a cluster by its id or name (if unique)
func (carina *MakeCOE) DeleteCluster(token string) (common.Cluster, error) {
	err := carina.init()
	if err != nil {
		return nil, err
	}

	common.Log.WriteDebug("[make-coe] Deleting cluster (%s)", token)
	result, err := carina.client.Delete(token)
	if err != nil {
		if httpErr, ok := err.(libcarina.HTTPErr); ok {
			if httpErr.StatusCode == http.StatusNotFound {
				common.Log.WriteWarning("Could not find the cluster (%s) to delete", token)
				cluster := newCluster()
				cluster.Status = "deleted"
				return cluster, nil
			}
		}

		return nil, errors.Wrap(err, fmt.Sprintf("[make-coe] Unable to delete cluster (%s)", token))
	}

	cluster := &Cluster{Cluster: result}

	return cluster, nil
}

// GrowCluster adds nodes to a cluster by its id or name (if unique)
func (carina *MakeCOE) GrowCluster(token string, nodes int) (common.Cluster, error) {
	return nil, errors.New("[make-coe] Grow command not supported. Please use 'resize'.")
}

// ResizeCluster resizes the cluster to the specified number of nodes
func (carina *MakeCOE) ResizeCluster(token string, nodes int) (common.Cluster, error) {
	err := carina.init()
	if err != nil {
		return nil, err
	}

	common.Log.WriteDebug("[make-coe] Resizing cluster (%s) to %d nodes", token, nodes)

	result, err := carina.client.Resize(token, nodes)
	if err != nil {
		return nil, errors.Wrap(err, fmt.Sprintf("[make-coe] Unable to resize cluster (%s)", token))
	}

	cluster := &Cluster{Cluster: result}

	return cluster, nil
}

// SetAutoScale is not supported
func (carina *MakeCOE) SetAutoScale(token string, value bool) (common.Cluster, error) {
	return nil, errors.New("make-coe does not support autoscaling")
}

// WaitUntilClusterIsActive waits until the prior cluster operation is completed
func (carina *MakeCOE) WaitUntilClusterIsActive(cluster common.Cluster) (common.Cluster, error) {
	isDone := func(cluster common.Cluster) bool {
		status := strings.ToLower(cluster.GetStatus())
		return status == "active" || status == "error"
	}

	if isDone(cluster) {
		return cluster, nil
	}

	pollingInterval := 5 * time.Second
	for {
		cluster, err := carina.GetCluster(cluster.GetID())
		if err != nil {
			err = errors.Cause(err)
			return nil, err
		}

		if isDone(cluster) {
			return cluster, nil
		}

		common.Log.WriteDebug("[make-coe] Waiting until cluster (%s) is active, currently in %s", cluster.GetName(), cluster.GetStatus())
		time.Sleep(pollingInterval)
	}
}

// WaitUntilClusterIsDeleted polls the cluster status until either the cluster is gone or an error state is hit
func (carina *MakeCOE) WaitUntilClusterIsDeleted(cluster common.Cluster) error {
	isDone := func(cluster common.Cluster) bool {
		status := strings.ToUpper(cluster.GetStatus())
		return status == "deleted"
	}

	if isDone(cluster) {
		return nil
	}

	pollingInterval := 5 * time.Second
	for {
		cluster, err := carina.GetCluster(cluster.GetID())
		if err != nil {
			err = errors.Cause(err)

			// Gracefully handle a 404 Not Found when the cluster is deleted quickly
			if httpErr, ok := err.(libcarina.HTTPErr); ok {
				if httpErr.StatusCode == http.StatusNotFound {
					return nil
				}
			}

			return err
		}

		if isDone(cluster) {
			return nil
		}

		common.Log.WriteDebug("[make-coe] Waiting until cluster (%s) is deleted, currently in %s", cluster.GetName(), cluster.GetStatus())
		time.Sleep(pollingInterval)
	}
}

func (carina *MakeCOE) listClusterTypes() ([]*libcarina.ClusterType, error) {
	common.Log.WriteDebug("[make-coe] Listing cluster types")
	clusterTypes, err := carina.client.ListClusterTypes()
	if err != nil {
		return nil, errors.Wrap(err, "[make-coe] Unabe to list cluster types")
	}

	return clusterTypes, err
}

func (carina *MakeCOE) getClusterTypeCache() (map[int]*libcarina.ClusterType, error) {
	if carina.clusterTypeCache == nil {
		clusterTypes, err := carina.listClusterTypes()
		if err != nil {
			return nil, err
		}

		carina.clusterTypeCache = make(map[int]*libcarina.ClusterType)
		for _, clusterType := range clusterTypes {
			carina.clusterTypeCache[clusterType.ID] = clusterType
		}
	}

	return carina.clusterTypeCache, nil
}

func (carina *MakeCOE) lookupClusterTypeByName(name string) (*libcarina.ClusterType, error) {
	cache, err := carina.getClusterTypeCache()
	if err != nil {
		return nil, err
	}

	name = strings.ToLower(name)
	var clusterType *libcarina.ClusterType
	for _, m := range cache {
		if strings.ToLower(m.Name) == name {
			clusterType = m
			break
		}
	}

	if clusterType == nil {
		return nil, fmt.Errorf("Could not find template named %s", name)
	}

	return clusterType, nil
}
<commit_msg>carina delete --wait should halt on error<commit_after>package makecoe

import (
	"fmt"
	"net/http"

	"strings"

	"time"

	"github.com/getcarina/carina/common"
	"github.com/getcarina/libcarina"
	"github.com/pkg/errors"
)

// MakeCOE is an adapter between the cli and Carina (make-coe)
type MakeCOE struct {
	client           *libcarina.CarinaClient
	clusterTypeCache map[int]*libcarina.ClusterType
	Account          *Account
}

func (carina *MakeCOE) init() error {
	if carina.client == nil {
		carinaClient, err := carina.Account.Authenticate()
		if err != nil {
			return err
		}
		carina.client = carinaClient
	}
	return nil
}

// GetQuotas retrieves the quotas set for the account
func (carina *MakeCOE) GetQuotas() (common.Quotas, error) {
	return &Quotas{}, nil
}

// CreateCluster creates a new cluster and prints the cluster information
func (carina *MakeCOE) CreateCluster(name string, template string, nodes int) (common.Cluster, error) {
	if template == "" {
		return nil, errors.New("--template is required")
	}

	err := carina.init()
	if err != nil {
		return nil, err
	}

	clusterType, err := carina.lookupClusterTypeByName(template)
	if err != nil {
		return nil, err
	}

	common.Log.WriteDebug("[make-coe] Creating a %d-node %s cluster hosted on %s named %s", nodes, clusterType.COE, clusterType.HostType, name)
	createOpts := &libcarina.CreateClusterOpts{
		Name:          name,
		ClusterTypeID: clusterType.ID,
		Nodes:         nodes,
	}

	result, err := carina.client.Create(createOpts)
	if err != nil {
		return nil, errors.Wrap(err, "[make-coe] Unable to create cluster")
	}

	cluster := &Cluster{Cluster: result}

	return cluster, nil
}

// GetClusterCredentials retrieves the TLS certificates and configuration scripts for a cluster by its id or name (if unique)
func (carina *MakeCOE) GetClusterCredentials(token string) (*libcarina.CredentialsBundle, error) {
	err := carina.init()
	if err != nil {
		return nil, err
	}

	common.Log.WriteDebug("[make-coe] Retrieving cluster credentials (%s)", token)
	creds, err := carina.client.GetCredentials(token)
	if err != nil {
		return nil, errors.Wrap(err, "[make-coe] Unable to retrieve the cluster credentials")
	}

	return creds, nil
}

// ListClusters prints out a list of the user's clusters to the console
func (carina *MakeCOE) ListClusters() ([]common.Cluster, error) {
	var clusters []common.Cluster

	err := carina.init()
	if err != nil {
		return clusters, err
	}

	common.Log.WriteDebug("[make-coe] Listing clusters")
	results, err := carina.client.List()
	if err != nil {
		return clusters, errors.Wrap(err, "[make-coe] Unable to list clusters")
	}

	for _, result := range results {
		cluster := &Cluster{Cluster: result}
		clusters = append(clusters, cluster)
	}

	return clusters, err
}

// ListClusterTemplates retrieves available templates for creating a new cluster
func (carina *MakeCOE) ListClusterTemplates() ([]common.ClusterTemplate, error) {
	err := carina.init()
	if err != nil {
		return nil, err
	}

	results, err := carina.listClusterTypes()
	if err != nil {
		return nil, err
	}

	var templates []common.ClusterTemplate
	for _, result := range results {
		template := &ClusterTemplate{ClusterType: result}
		templates = append(templates, template)
	}

	return templates, err
}

// RebuildCluster destroys and recreates the cluster by its id or name (if unique)
func (carina *MakeCOE) RebuildCluster(token string) (common.Cluster, error) {
	return nil, errors.New("[make-coe] Rebuilding clusters from the carina cli is not supported yet")
}

// GetCluster prints out a cluster's information to the console by its id or name (if unique)
func (carina *MakeCOE) GetCluster(token string) (common.Cluster, error) {
	err := carina.init()
	if err != nil {
		return nil, err
	}

	common.Log.WriteDebug("[make-coe] Retrieving cluster (%s)", token)
	result, err := carina.client.Get(token)
	if err != nil {
		return nil, errors.Wrap(err, fmt.Sprintf("[make-coe] Unable to retrieve cluster (%s)", token))
	}
	cluster := &Cluster{Cluster: result}

	return cluster, nil
}

// DeleteCluster permanently deletes a cluster by its id or name (if unique)
func (carina *MakeCOE) DeleteCluster(token string) (common.Cluster, error) {
	err := carina.init()
	if err != nil {
		return nil, err
	}

	common.Log.WriteDebug("[make-coe] Deleting cluster (%s)", token)
	result, err := carina.client.Delete(token)
	if err != nil {
		if httpErr, ok := err.(libcarina.HTTPErr); ok {
			if httpErr.StatusCode == http.StatusNotFound {
				common.Log.WriteWarning("Could not find the cluster (%s) to delete", token)
				cluster := newCluster()
				cluster.Status = "deleted"
				return cluster, nil
			}
		}

		return nil, errors.Wrap(err, fmt.Sprintf("[make-coe] Unable to delete cluster (%s)", token))
	}

	cluster := &Cluster{Cluster: result}

	return cluster, nil
}

// GrowCluster adds nodes to a cluster by its id or name (if unique)
func (carina *MakeCOE) GrowCluster(token string, nodes int) (common.Cluster, error) {
	return nil, errors.New("[make-coe] Grow command not supported. Please use 'resize'.")
}

// ResizeCluster resizes the cluster to the specified number of nodes
func (carina *MakeCOE) ResizeCluster(token string, nodes int) (common.Cluster, error) {
	err := carina.init()
	if err != nil {
		return nil, err
	}

	common.Log.WriteDebug("[make-coe] Resizing cluster (%s) to %d nodes", token, nodes)

	result, err := carina.client.Resize(token, nodes)
	if err != nil {
		return nil, errors.Wrap(err, fmt.Sprintf("[make-coe] Unable to resize cluster (%s)", token))
	}

	cluster := &Cluster{Cluster: result}

	return cluster, nil
}

// SetAutoScale is not supported
func (carina *MakeCOE) SetAutoScale(token string, value bool) (common.Cluster, error) {
	return nil, errors.New("make-coe does not support autoscaling")
}

// WaitUntilClusterIsActive waits until the prior cluster operation is completed
func (carina *MakeCOE) WaitUntilClusterIsActive(cluster common.Cluster) (common.Cluster, error) {
	isDone := func(cluster common.Cluster) bool {
		status := strings.ToLower(cluster.GetStatus())
		return status == "active" || status == "error"
	}

	if isDone(cluster) {
		return cluster, nil
	}

	pollingInterval := 5 * time.Second
	for {
		cluster, err := carina.GetCluster(cluster.GetID())
		if err != nil {
			err = errors.Cause(err)
			return nil, err
		}

		if isDone(cluster) {
			return cluster, nil
		}

		common.Log.WriteDebug("[make-coe] Waiting until cluster (%s) is active, currently in %s", cluster.GetName(), cluster.GetStatus())
		time.Sleep(pollingInterval)
	}
}

// WaitUntilClusterIsDeleted polls the cluster status until either the cluster is gone or an error state is hit
func (carina *MakeCOE) WaitUntilClusterIsDeleted(cluster common.Cluster) error {
	isDone := func(cluster common.Cluster) (bool, error) {
		status := strings.ToLower(cluster.GetStatus())
		if status == "error" {
			return true, errors.New("Unable to delete cluster, an error occured while deleting.")
		}
		return status == "deleted", nil
	}

	if done, err := isDone(cluster); done {
		return err
	}

	pollingInterval := 5 * time.Second
	for {
		cluster, err := carina.GetCluster(cluster.GetID())
		if err != nil {
			err = errors.Cause(err)

			// Gracefully handle a 404 Not Found when the cluster is deleted quickly
			if httpErr, ok := err.(libcarina.HTTPErr); ok {
				if httpErr.StatusCode == http.StatusNotFound {
					return nil
				}
			}

			return err
		}

		if done, err := isDone(cluster); done {
			return err
		}

		common.Log.WriteDebug("[make-coe] Waiting until cluster (%s) is deleted, currently in %s", cluster.GetName(), cluster.GetStatus())
		time.Sleep(pollingInterval)
	}
}

func (carina *MakeCOE) listClusterTypes() ([]*libcarina.ClusterType, error) {
	common.Log.WriteDebug("[make-coe] Listing cluster types")
	clusterTypes, err := carina.client.ListClusterTypes()
	if err != nil {
		return nil, errors.Wrap(err, "[make-coe] Unabe to list cluster types")
	}

	return clusterTypes, err
}

func (carina *MakeCOE) getClusterTypeCache() (map[int]*libcarina.ClusterType, error) {
	if carina.clusterTypeCache == nil {
		clusterTypes, err := carina.listClusterTypes()
		if err != nil {
			return nil, err
		}

		carina.clusterTypeCache = make(map[int]*libcarina.ClusterType)
		for _, clusterType := range clusterTypes {
			carina.clusterTypeCache[clusterType.ID] = clusterType
		}
	}

	return carina.clusterTypeCache, nil
}

func (carina *MakeCOE) lookupClusterTypeByName(name string) (*libcarina.ClusterType, error) {
	cache, err := carina.getClusterTypeCache()
	if err != nil {
		return nil, err
	}

	name = strings.ToLower(name)
	var clusterType *libcarina.ClusterType
	for _, m := range cache {
		if strings.ToLower(m.Name) == name {
			clusterType = m
			break
		}
	}

	if clusterType == nil {
		return nil, fmt.Errorf("Could not find template named %s", name)
	}

	return clusterType, nil
}
<|endoftext|>


<commit_before>package pttbbs

import (
	"bytes"
	"errors"
	"fmt"
	"strconv"
	"strings"

	"code.google.com/p/vitess/go/memcache"
)

var (
	ErrInvalidArticleLine   = errors.New("article line format error")
	ErrAttributeFetchFailed = errors.New("cannot fetch some attributes")
	ErrUnknownValueType     = errors.New("unknown value type")
	ErrArgumentCount        = errors.New("invalid argument count")
	ErrResultCountMismatch  = errors.New("result count returned from memcached mismatch")
)

type RemotePtt struct {
	BoarddAddr string

	connPool *MemcacheConnPool
}

func NewRemotePtt(boarddAddr string) *RemotePtt {
	return &RemotePtt{
		BoarddAddr: boarddAddr,
		connPool:   NewMemcacheConnPool(boarddAddr, 16),
	}
}

func key(bid int, attr string) string {
	return fmt.Sprintf("%d.%s", bid, attr)
}

func (p *RemotePtt) queryMemd(types string, keyvalue ...interface{}) (int, error) {
	if 2*len(types) != len(keyvalue) {
		return 0, ErrArgumentCount
	}

	var err error
	var memd *memcache.Connection
	if memd, err = p.connPool.GetConn(); err != nil {
		return 0, err
	}
	defer func() {
		p.connPool.ReleaseConn(memd, err)
	}()

	// Prepare keys to fetch in batch
	keys := make([]string, len(types))
	for i := range keys {
		keys[i] = keyvalue[2*i].(string)
	}

	res, err := memd.Get(keys...)
	if err != nil {
		return 0, err
	} else if len(res) != len(keys) {
		return 0, ErrResultCountMismatch
	}

	// Put results back
	for i, r := range res {
		val := keyvalue[2*i+1]
		switch types[i] {
		case 's':
			*val.(*string) = string(r.Value)
		case 'i':
			*val.(*int), err = strconv.Atoi(string(r.Value))
		case 'b':
			*val.(*[]byte) = r.Value
		default:
			return i, ErrUnknownValueType
		}
		if err != nil {
			return i, err
		}
	}

	return len(types), nil
}

func (p *RemotePtt) GetBoardChildren(bid int) (children []int, err error) {
	var result []byte
	if _, err = p.queryMemd("b", key(bid, "children"), &result); err != nil {
		return
	}

	children = make([]int, 0, 16)
	buf := bytes.NewReader(result)
	for {
		child := 0
		if n, err := fmt.Fscanf(buf, "%d,", &child); n != 1 || err != nil {
			break
		}
		children = append(children, child)
	}
	return
}

func (p *RemotePtt) GetBoard(bid int) (brd Board, err error) {
	var isboard, over18, hidden int
	if _, err = p.queryMemd("iiissssi",
		key(bid, "isboard"), &isboard,
		key(bid, "over18"), &over18,
		key(bid, "hidden"), &hidden,
		key(bid, "brdname"), &brd.BrdName,
		key(bid, "title"), &brd.Title,
		key(bid, "class"), &brd.Class,
		key(bid, "BM"), &brd.BM,
		key(bid, "parent"), &brd.Parent); err != nil {
		err = ErrAttributeFetchFailed
		return
	}
	brd.IsBoard = isboard == 1
	brd.Over18 = over18 == 1
	brd.Hidden = hidden == 1
	brd.Bid = bid
	return
}

func (p *RemotePtt) GetArticleCount(bid int) (count int, err error) {
	_, err = p.queryMemd("i", key(bid, "count"), &count)
	return
}

func (p *RemotePtt) GetArticleList(bid, offset int) (articles []Article, err error) {
	var result string
	if _, err = p.queryMemd("s", key(bid, "articles."+strconv.Itoa(offset)), &result); err != nil {
		return nil, err
	}

	articles = make([]Article, 0, 20)

	for _, line := range strings.Split(result, "\n") {
		if line == "" {
			break
		}

		parts := strings.SplitN(line, ",", 7)
		if len(parts) != 7 {
			return nil, ErrInvalidArticleLine
		}

		var off, rec, mode int
		if off, err = strconv.Atoi(parts[0]); err != nil {
			return nil, err
		}
		if rec, err = strconv.Atoi(parts[3]); err != nil {
			return nil, err
		}
		if mode, err = strconv.Atoi(parts[4]); err != nil {
			return nil, err
		}

		articles = append(articles, Article{
			Offset:    off,
			FileName:  parts[1],
			Date:      parts[2],
			Recommend: rec,
			FileMode:  mode,
			Owner:     parts[5],
			Title:     parts[6],
		})
	}
	return articles, nil
}

func (p *RemotePtt) GetArticleContent(bid int, filename string) (content []byte, err error) {
	_, err = p.queryMemd("b", key(bid, "article."+filename), &content)
	return
}

func (p *RemotePtt) BrdName2Bid(brdname string) (bid int, err error) {
	_, err = p.queryMemd("i", "tobid."+brdname, &bid)
	return
}
<commit_msg>Fix errors caused by boardd not returning empty fields.<commit_after>package pttbbs

import (
	"bytes"
	"errors"
	"fmt"
	"strconv"
	"strings"

	"code.google.com/p/vitess/go/memcache"
)

var (
	ErrInvalidArticleLine   = errors.New("article line format error")
	ErrAttributeFetchFailed = errors.New("cannot fetch some attributes")
	ErrUnknownValueType     = errors.New("unknown value type")
	ErrArgumentCount        = errors.New("invalid argument count")
	ErrResultCountMismatch  = errors.New("result count returned from memcached mismatch")
)

type RemotePtt struct {
	BoarddAddr string

	connPool *MemcacheConnPool
}

func NewRemotePtt(boarddAddr string) *RemotePtt {
	return &RemotePtt{
		BoarddAddr: boarddAddr,
		connPool:   NewMemcacheConnPool(boarddAddr, 16),
	}
}

func key(bid int, attr string) string {
	return fmt.Sprintf("%d.%s", bid, attr)
}

func (p *RemotePtt) queryMemd(types string, keyvalue ...interface{}) (int, error) {
	if 2*len(types) != len(keyvalue) {
		return 0, ErrArgumentCount
	}

	var err error
	var memd *memcache.Connection
	if memd, err = p.connPool.GetConn(); err != nil {
		return 0, err
	}
	defer func() {
		p.connPool.ReleaseConn(memd, err)
	}()

	// Prepare keys to fetch in batch
	keys := make([]string, len(types))
	for i := range keys {
		keys[i] = keyvalue[2*i].(string)
	}

	res, err := memd.Get(keys...)
	if err != nil {
		return 0, err
	}

	// Put results back
	j := 0
	for i, key := range keys {
		var val []byte
		if j < len(res) && key == res[j].Key {
			// Consume the result
			val = res[j].Value
			j++
		}
		if err = setVal(types[i], keyvalue[2*i+1], val); err != nil {
			return i, err
		}
	}

	return len(types), nil
}

func setVal(t uint8, dst interface{}, src []byte) (err error) {
	if src != nil {
		switch t {
		case 's':
			*dst.(*string) = string(src)
		case 'i':
			*dst.(*int), err = strconv.Atoi(string(src))
		case 'b':
			*dst.(*[]byte) = src
		default:
			err = ErrUnknownValueType
		}
	} else {
		switch t {
		case 's':
			*dst.(*string) = ""
		case 'i':
			*dst.(*int) = 0
		case 'b':
			*dst.(*[]byte) = nil
		default:
			err = ErrUnknownValueType
		}
	}
	return
}

func (p *RemotePtt) GetBoardChildren(bid int) (children []int, err error) {
	var result []byte
	if _, err = p.queryMemd("b", key(bid, "children"), &result); err != nil {
		return
	}

	children = make([]int, 0, 16)
	buf := bytes.NewReader(result)
	for {
		child := 0
		if n, err := fmt.Fscanf(buf, "%d,", &child); n != 1 || err != nil {
			break
		}
		children = append(children, child)
	}
	return
}

func (p *RemotePtt) GetBoard(bid int) (brd Board, err error) {
	var isboard, over18, hidden int
	if _, err = p.queryMemd("iiissssi",
		key(bid, "isboard"), &isboard,
		key(bid, "over18"), &over18,
		key(bid, "hidden"), &hidden,
		key(bid, "brdname"), &brd.BrdName,
		key(bid, "title"), &brd.Title,
		key(bid, "class"), &brd.Class,
		key(bid, "BM"), &brd.BM,
		key(bid, "parent"), &brd.Parent); err != nil {
		err = ErrAttributeFetchFailed
		return
	}
	brd.IsBoard = isboard == 1
	brd.Over18 = over18 == 1
	brd.Hidden = hidden == 1
	brd.Bid = bid
	return
}

func (p *RemotePtt) GetArticleCount(bid int) (count int, err error) {
	_, err = p.queryMemd("i", key(bid, "count"), &count)
	return
}

func (p *RemotePtt) GetArticleList(bid, offset int) (articles []Article, err error) {
	var result string
	if _, err = p.queryMemd("s", key(bid, "articles."+strconv.Itoa(offset)), &result); err != nil {
		return nil, err
	}

	articles = make([]Article, 0, 20)

	for _, line := range strings.Split(result, "\n") {
		if line == "" {
			break
		}

		parts := strings.SplitN(line, ",", 7)
		if len(parts) != 7 {
			return nil, ErrInvalidArticleLine
		}

		var off, rec, mode int
		if off, err = strconv.Atoi(parts[0]); err != nil {
			return nil, err
		}
		if rec, err = strconv.Atoi(parts[3]); err != nil {
			return nil, err
		}
		if mode, err = strconv.Atoi(parts[4]); err != nil {
			return nil, err
		}

		articles = append(articles, Article{
			Offset:    off,
			FileName:  parts[1],
			Date:      parts[2],
			Recommend: rec,
			FileMode:  mode,
			Owner:     parts[5],
			Title:     parts[6],
		})
	}
	return articles, nil
}

func (p *RemotePtt) GetArticleContent(bid int, filename string) (content []byte, err error) {
	_, err = p.queryMemd("b", key(bid, "article."+filename), &content)
	return
}

func (p *RemotePtt) BrdName2Bid(brdname string) (bid int, err error) {
	_, err = p.queryMemd("i", "tobid."+brdname, &bid)
	return
}
<|endoftext|>


<commit_before>package dev

import (
	"encoding/json"
	"net"
	"net/http"
	"puma/httpu"
	"puma/httputil"
	"strings"
	"time"

	"github.com/bmizerany/pat"
)

type HTTPServer struct {
	Address    string
	TLSAddress string
	Pool       *AppPool
	Debug      bool

	mux       *pat.PatternServeMux
	transport *httpu.Transport
	proxy     *httputil.ReverseProxy
}

func (h *HTTPServer) Setup() {
	h.transport = &httpu.Transport{
		Dial: (&net.Dialer{
			Timeout:   5 * time.Second,
			KeepAlive: 10 * time.Second,
		}).Dial,
		TLSHandshakeTimeout:   10 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
	}

	h.Pool.AppClosed = h.AppClosed

	h.proxy = &httputil.ReverseProxy{
		Director:      h.director,
		Transport:     h.transport,
		FlushInterval: 1 * time.Second,
		Debug:         h.Debug,
	}

	h.mux = pat.New()

	h.mux.Get("/status", http.HandlerFunc(h.status))
}

func (h *HTTPServer) AppClosed(app *App) {
	// Whenever an app is closed, wipe out all idle conns. This
	// obviously closes down more than just this one apps connections
	// but that's ok.
	h.transport.CloseIdleConnections()
}

func pruneSub(name string) string {
	dot := strings.IndexByte(name, '.')
	if dot == -1 {
		return ""
	}

	return name[dot+1:]
}

func (h *HTTPServer) hostForApp(name string) (string, string, error) {
	var (
		app *App
		err error
	)

	for name != "" {
		app, err = h.Pool.App(name)
		if err != nil {
			if err == ErrUnknownApp {
				name = pruneSub(name)
				continue
			}

			return "", "", err
		}

		break
	}

	if app == nil {
		app, err = h.Pool.App("default")
		if err != nil {
			return "", "", err
		}
	}

	err = app.WaitTilReady()
	if err != nil {
		return "", "", err
	}

	return app.Scheme, app.Address(), nil
}

func (h *HTTPServer) director(req *http.Request) error {
	dot := strings.LastIndexByte(req.Host, '.')

	var name string
	if dot == -1 {
		name = req.Host
	} else {
		name = req.Host[:dot]
	}

	var err error
	req.URL.Scheme, req.URL.Host, err = h.hostForApp(name)
	return err
}

func (h *HTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	if req.Host == "puma-dev" {
		h.mux.ServeHTTP(w, req)
	} else {
		h.proxy.ServeHTTP(w, req)
	}
}

func (h *HTTPServer) status(w http.ResponseWriter, req *http.Request) {
	type appStatus struct {
		Scheme  string `json:"scheme"`
		Address string `json:"address"`
		Status  string `json:"status"`
		Log     string `json:"log"`
	}

	statuses := map[string]appStatus{}

	h.Pool.ForApps(func(a *App) {
		var status string

		switch a.Status() {
		case Dead:
			status = "dead"
		case Booting:
			status = "booting"
		case Running:
			status = "running"
		default:
			status = "unknown"
		}

		statuses[a.Name] = appStatus{
			Scheme:  a.Scheme,
			Address: a.Address(),
			Status:  status,
			Log:     a.Log(),
		}
	})

	json.NewEncoder(w).Encode(statuses)
}
<commit_msg>Add support for xip.io. Fixes #38<commit_after>package dev

import (
	"encoding/json"
	"net"
	"net/http"
	"puma/httpu"
	"puma/httputil"
	"strings"
	"time"

	"github.com/bmizerany/pat"
)

type HTTPServer struct {
	Address    string
	TLSAddress string
	Pool       *AppPool
	Debug      bool

	mux       *pat.PatternServeMux
	transport *httpu.Transport
	proxy     *httputil.ReverseProxy
}

func (h *HTTPServer) Setup() {
	h.transport = &httpu.Transport{
		Dial: (&net.Dialer{
			Timeout:   5 * time.Second,
			KeepAlive: 10 * time.Second,
		}).Dial,
		TLSHandshakeTimeout:   10 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
	}

	h.Pool.AppClosed = h.AppClosed

	h.proxy = &httputil.ReverseProxy{
		Director:      h.director,
		Transport:     h.transport,
		FlushInterval: 1 * time.Second,
		Debug:         h.Debug,
	}

	h.mux = pat.New()

	h.mux.Get("/status", http.HandlerFunc(h.status))
}

func (h *HTTPServer) AppClosed(app *App) {
	// Whenever an app is closed, wipe out all idle conns. This
	// obviously closes down more than just this one apps connections
	// but that's ok.
	h.transport.CloseIdleConnections()
}

func pruneSub(name string) string {
	dot := strings.IndexByte(name, '.')
	if dot == -1 {
		return ""
	}

	return name[dot+1:]
}

func (h *HTTPServer) hostForApp(name string) (string, string, error) {
	var (
		app *App
		err error
	)

	for name != "" {
		app, err = h.Pool.App(name)
		if err != nil {
			if err == ErrUnknownApp {
				name = pruneSub(name)
				continue
			}

			return "", "", err
		}

		break
	}

	if app == nil {
		app, err = h.Pool.App("default")
		if err != nil {
			return "", "", err
		}
	}

	err = app.WaitTilReady()
	if err != nil {
		return "", "", err
	}

	return app.Scheme, app.Address(), nil
}

func (h *HTTPServer) removeTLD(host string) string {
	colon := strings.LastIndexByte(host, ':')
	if colon != -1 {
		if h, _, err := net.SplitHostPort(host); err == nil {
			host = h
		}
	}

	if strings.HasSuffix(host, ".xip.io") {
		parts := strings.Split(host, ".")
		if len(parts) < 6 {
			return ""
		}

		name := strings.Join(parts[:len(parts)-6], ".")

		return name
	}

	dot := strings.LastIndexByte(host, '.')

	if dot == -1 {
		return host
	} else {
		return host[:dot]
	}
}

func (h *HTTPServer) director(req *http.Request) error {
	name := h.removeTLD(req.Host)

	var err error
	req.URL.Scheme, req.URL.Host, err = h.hostForApp(name)
	return err
}

func (h *HTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	if req.Host == "puma-dev" {
		h.mux.ServeHTTP(w, req)
	} else {
		h.proxy.ServeHTTP(w, req)
	}
}

func (h *HTTPServer) status(w http.ResponseWriter, req *http.Request) {
	type appStatus struct {
		Scheme  string `json:"scheme"`
		Address string `json:"address"`
		Status  string `json:"status"`
		Log     string `json:"log"`
	}

	statuses := map[string]appStatus{}

	h.Pool.ForApps(func(a *App) {
		var status string

		switch a.Status() {
		case Dead:
			status = "dead"
		case Booting:
			status = "booting"
		case Running:
			status = "running"
		default:
			status = "unknown"
		}

		statuses[a.Name] = appStatus{
			Scheme:  a.Scheme,
			Address: a.Address(),
			Status:  status,
			Log:     a.Log(),
		}
	})

	json.NewEncoder(w).Encode(statuses)
}
<|endoftext|>