<commit_before>package google

import (
	"bytes"
	"fmt"
	"sort"
	"time"

	"code.google.com/p/google-api-go-client/compute/v1"
	"code.google.com/p/google-api-go-client/googleapi"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceComputeFirewall() *schema.Resource {
	return &schema.Resource{
		Create: resourceComputeFirewallCreate,
		Read:   resourceComputeFirewallRead,
		Update: resourceComputeFirewallUpdate,
		Delete: resourceComputeFirewallDelete,

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

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

			"allow": &schema.Schema{
				Type:     schema.TypeSet,
				Required: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"protocol": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},

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

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

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

func resourceComputeFirewallAllowHash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%s-", m["protocol"].(string)))

	// We need to make sure to sort the strings below so that we always
	// generate the same hash code no matter what is in the set.
	if v, ok := m["ports"]; ok {
		vs := v.(*schema.Set).List()
		s := make([]string, len(vs))
		for i, raw := range vs {
			s[i] = raw.(string)
		}
		sort.Strings(s)

		for _, v := range s {
			buf.WriteString(fmt.Sprintf("%s-", v))
		}
	}

	return hashcode.String(buf.String())
}

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

	firewall, err := resourceFirewall(d, meta)
	if err != nil {
		return err
	}

	op, err := config.clientCompute.Firewalls.Insert(
		config.Project, firewall).Do()
	if err != nil {
		return fmt.Errorf("Error creating firewall: %s", err)
	}

	// It probably maybe worked, so store the ID now
	d.SetId(firewall.Name)

	// Wait for the operation to complete
	w := &OperationWaiter{
		Service: config.clientCompute,
		Op:      op,
		Project: config.Project,
		Type:    OperationWaitGlobal,
	}
	state := w.Conf()
	state.Timeout = 2 * time.Minute
	state.MinTimeout = 1 * time.Second
	opRaw, err := state.WaitForState()
	if err != nil {
		return fmt.Errorf("Error waiting for firewall to create: %s", err)
	}
	op = opRaw.(*compute.Operation)
	if op.Error != nil {
		// The resource didn't actually create
		d.SetId("")

		// Return the error
		return OperationError(*op.Error)
	}

	return resourceComputeFirewallRead(d, meta)
}

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

	_, err := config.clientCompute.Firewalls.Get(
		config.Project, d.Id()).Do()
	if err != nil {
		if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
			// The resource doesn't exist anymore
			d.SetId("")

			return nil
		}

		return fmt.Errorf("Error reading firewall: %s", err)
	}

	return nil
}

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

	d.Partial(true)

	firewall, err := resourceFirewall(d, meta)
	if err != nil {
		return err
	}

	op, err := config.clientCompute.Firewalls.Update(
		config.Project, d.Id(), firewall).Do()
	if err != nil {
		return fmt.Errorf("Error updating firewall: %s", err)
	}

	// Wait for the operation to complete
	w := &OperationWaiter{
		Service: config.clientCompute,
		Op:      op,
		Project: config.Project,
		Type:    OperationWaitGlobal,
	}
	state := w.Conf()
	state.Timeout = 2 * time.Minute
	state.MinTimeout = 1 * time.Second
	opRaw, err := state.WaitForState()
	if err != nil {
		return fmt.Errorf("Error waiting for firewall to update: %s", err)
	}
	op = opRaw.(*compute.Operation)
	if op.Error != nil {
		// Return the error
		return OperationError(*op.Error)
	}

	d.Partial(false)

	return resourceComputeFirewallRead(d, meta)
}

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

	// Delete the firewall
	op, err := config.clientCompute.Firewalls.Delete(
		config.Project, d.Id()).Do()
	if err != nil {
		return fmt.Errorf("Error deleting firewall: %s", err)
	}

	// Wait for the operation to complete
	w := &OperationWaiter{
		Service: config.clientCompute,
		Op:      op,
		Project: config.Project,
		Type:    OperationWaitGlobal,
	}
	state := w.Conf()
	state.Timeout = 2 * time.Minute
	state.MinTimeout = 1 * time.Second
	opRaw, err := state.WaitForState()
	if err != nil {
		return fmt.Errorf("Error waiting for firewall to delete: %s", err)
	}
	op = opRaw.(*compute.Operation)
	if op.Error != nil {
		// Return the error
		return OperationError(*op.Error)
	}

	d.SetId("")
	return nil
}

func resourceFirewall(
	d *schema.ResourceData,
	meta interface{}) (*compute.Firewall, error) {
	config := meta.(*Config)

	// Look up the network to attach the firewall to
	network, err := config.clientCompute.Networks.Get(
		config.Project, d.Get("network").(string)).Do()
	if err != nil {
		return nil, fmt.Errorf("Error reading network: %s", err)
	}

	// Build up the list of allowed entries
	var allowed []*compute.FirewallAllowed
	if v := d.Get("allow").(*schema.Set); v.Len() > 0 {
		allowed = make([]*compute.FirewallAllowed, 0, v.Len())
		for _, v := range v.List() {
			m := v.(map[string]interface{})

			var ports []string
			if v := m["ports"].(*schema.Set); v.Len() > 0 {
				ports = make([]string, v.Len())
				for i, v := range v.List() {
					ports[i] = v.(string)
				}
			}

			allowed = append(allowed, &compute.FirewallAllowed{
				IPProtocol: m["protocol"].(string),
				Ports:      ports,
			})
		}
	}

	// Build up the list of sources
	var sourceRanges, sourceTags []string
	if v := d.Get("source_ranges").(*schema.Set); v.Len() > 0 {
		sourceRanges = make([]string, v.Len())
		for i, v := range v.List() {
			sourceRanges[i] = v.(string)
		}
	}
	if v := d.Get("source_tags").(*schema.Set); v.Len() > 0 {
		sourceTags = make([]string, v.Len())
		for i, v := range v.List() {
			sourceTags[i] = v.(string)
		}
	}

	// Build the firewall parameter
	return &compute.Firewall{
		Name:         d.Get("name").(string),
		Network:      network.SelfLink,
		Allowed:      allowed,
		SourceRanges: sourceRanges,
		SourceTags:   sourceTags,
	}, nil
}
<commit_msg>google_compute_firewall: Support target tags<commit_after>package google

import (
	"bytes"
	"fmt"
	"sort"
	"time"

	"code.google.com/p/google-api-go-client/compute/v1"
	"code.google.com/p/google-api-go-client/googleapi"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceComputeFirewall() *schema.Resource {
	return &schema.Resource{
		Create: resourceComputeFirewallCreate,
		Read:   resourceComputeFirewallRead,
		Update: resourceComputeFirewallUpdate,
		Delete: resourceComputeFirewallDelete,

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

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

			"allow": &schema.Schema{
				Type:     schema.TypeSet,
				Required: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"protocol": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},

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

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

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

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

func resourceComputeFirewallAllowHash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})
	buf.WriteString(fmt.Sprintf("%s-", m["protocol"].(string)))

	// We need to make sure to sort the strings below so that we always
	// generate the same hash code no matter what is in the set.
	if v, ok := m["ports"]; ok {
		vs := v.(*schema.Set).List()
		s := make([]string, len(vs))
		for i, raw := range vs {
			s[i] = raw.(string)
		}
		sort.Strings(s)

		for _, v := range s {
			buf.WriteString(fmt.Sprintf("%s-", v))
		}
	}

	return hashcode.String(buf.String())
}

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

	firewall, err := resourceFirewall(d, meta)
	if err != nil {
		return err
	}

	op, err := config.clientCompute.Firewalls.Insert(
		config.Project, firewall).Do()
	if err != nil {
		return fmt.Errorf("Error creating firewall: %s", err)
	}

	// It probably maybe worked, so store the ID now
	d.SetId(firewall.Name)

	// Wait for the operation to complete
	w := &OperationWaiter{
		Service: config.clientCompute,
		Op:      op,
		Project: config.Project,
		Type:    OperationWaitGlobal,
	}
	state := w.Conf()
	state.Timeout = 2 * time.Minute
	state.MinTimeout = 1 * time.Second
	opRaw, err := state.WaitForState()
	if err != nil {
		return fmt.Errorf("Error waiting for firewall to create: %s", err)
	}
	op = opRaw.(*compute.Operation)
	if op.Error != nil {
		// The resource didn't actually create
		d.SetId("")

		// Return the error
		return OperationError(*op.Error)
	}

	return resourceComputeFirewallRead(d, meta)
}

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

	_, err := config.clientCompute.Firewalls.Get(
		config.Project, d.Id()).Do()
	if err != nil {
		if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
			// The resource doesn't exist anymore
			d.SetId("")

			return nil
		}

		return fmt.Errorf("Error reading firewall: %s", err)
	}

	return nil
}

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

	d.Partial(true)

	firewall, err := resourceFirewall(d, meta)
	if err != nil {
		return err
	}

	op, err := config.clientCompute.Firewalls.Update(
		config.Project, d.Id(), firewall).Do()
	if err != nil {
		return fmt.Errorf("Error updating firewall: %s", err)
	}

	// Wait for the operation to complete
	w := &OperationWaiter{
		Service: config.clientCompute,
		Op:      op,
		Project: config.Project,
		Type:    OperationWaitGlobal,
	}
	state := w.Conf()
	state.Timeout = 2 * time.Minute
	state.MinTimeout = 1 * time.Second
	opRaw, err := state.WaitForState()
	if err != nil {
		return fmt.Errorf("Error waiting for firewall to update: %s", err)
	}
	op = opRaw.(*compute.Operation)
	if op.Error != nil {
		// Return the error
		return OperationError(*op.Error)
	}

	d.Partial(false)

	return resourceComputeFirewallRead(d, meta)
}

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

	// Delete the firewall
	op, err := config.clientCompute.Firewalls.Delete(
		config.Project, d.Id()).Do()
	if err != nil {
		return fmt.Errorf("Error deleting firewall: %s", err)
	}

	// Wait for the operation to complete
	w := &OperationWaiter{
		Service: config.clientCompute,
		Op:      op,
		Project: config.Project,
		Type:    OperationWaitGlobal,
	}
	state := w.Conf()
	state.Timeout = 2 * time.Minute
	state.MinTimeout = 1 * time.Second
	opRaw, err := state.WaitForState()
	if err != nil {
		return fmt.Errorf("Error waiting for firewall to delete: %s", err)
	}
	op = opRaw.(*compute.Operation)
	if op.Error != nil {
		// Return the error
		return OperationError(*op.Error)
	}

	d.SetId("")
	return nil
}

func resourceFirewall(
	d *schema.ResourceData,
	meta interface{}) (*compute.Firewall, error) {
	config := meta.(*Config)

	// Look up the network to attach the firewall to
	network, err := config.clientCompute.Networks.Get(
		config.Project, d.Get("network").(string)).Do()
	if err != nil {
		return nil, fmt.Errorf("Error reading network: %s", err)
	}

	// Build up the list of allowed entries
	var allowed []*compute.FirewallAllowed
	if v := d.Get("allow").(*schema.Set); v.Len() > 0 {
		allowed = make([]*compute.FirewallAllowed, 0, v.Len())
		for _, v := range v.List() {
			m := v.(map[string]interface{})

			var ports []string
			if v := m["ports"].(*schema.Set); v.Len() > 0 {
				ports = make([]string, v.Len())
				for i, v := range v.List() {
					ports[i] = v.(string)
				}
			}

			allowed = append(allowed, &compute.FirewallAllowed{
				IPProtocol: m["protocol"].(string),
				Ports:      ports,
			})
		}
	}

	// Build up the list of sources
	var sourceRanges, sourceTags []string
	if v := d.Get("source_ranges").(*schema.Set); v.Len() > 0 {
		sourceRanges = make([]string, v.Len())
		for i, v := range v.List() {
			sourceRanges[i] = v.(string)
		}
	}
	if v := d.Get("source_tags").(*schema.Set); v.Len() > 0 {
		sourceTags = make([]string, v.Len())
		for i, v := range v.List() {
			sourceTags[i] = v.(string)
		}
	}

	// Build up the list of targets
	var targetTags []string
	if v := d.Get("target_tags").(*schema.Set); v.Len() > 0 {
		targetTags = make([]string, v.Len())
		for i, v:= range v.List() {
			targetTags[i] = v.(string)
		}
	}

	// Build the firewall parameter
	return &compute.Firewall{
		Name:         d.Get("name").(string),
		Network:      network.SelfLink,
		Allowed:      allowed,
		SourceRanges: sourceRanges,
		SourceTags:   sourceTags,
		TargetTags:   targetTags,
	}, nil
}
<|endoftext|>


<commit_before>package thermal

// The cipherSet interface defines behavior expected from a cipher set plugin
type cipherSet interface {
	initialize() error
	fingerprint() (string, string)

	encryptOpenPacketBody(packet []byte, remotePublicKey *[32]byte) (openPacketBody []byte, localLineSecret [32]byte, err error)
	decryptOpenPacketBody(openPacketBody []byte, remotePublicKey *[32]byte) (packet []byte, remoteLineSecret [32]byte, err error)

	generateLineEncryptionKey(localLineSecret *[32]byte, localLineId, remoteLineId *[16]byte) [32]byte
	generateLineDecryptionKey(remoteLineSecret *[32]byte, localLineId, remoteLineId *[16]byte) [32]byte

	encryptLinePacketBody(packet []byte, lineEncryptionKey *[32]byte) (linePacketBody []byte, err error)
	decryptLinePacketBody(linePacketBody []byte, lineDecryptionKey *[32]byte) (packet []byte, err error)
}

// A cipherPack holds a group of cipher sets
type cipherPack map[string]cipherSet

// extractParts will pull out the hashname parts from a cipherPack
func extractParts(cpack *cipherPack) (map[string]string, error) {

	if len(*cpack) == 0 {
		return nil, fmt.Errorf("cipherPack is empty")
	}

	parts := make(map[string]string)

	for _, cset := range *cpack {
		csid, fingerprint := cset.fingerprint()

		if fingerprint == "" {
			return nil, fmt.Errorf("fingerprint for %s is empty", csid)
		}

		parts[csid] = fingerprint
	}

	return parts, nil
}
<commit_msg>add missing import<commit_after>package thermal

import (
	"fmt"
)

// The cipherSet interface defines behavior expected from a cipher set plugin
type cipherSet interface {
	initialize() error
	fingerprint() (string, string)

	encryptOpenPacketBody(packet []byte, remotePublicKey *[32]byte) (openPacketBody []byte, localLineSecret [32]byte, err error)
	decryptOpenPacketBody(openPacketBody []byte, remotePublicKey *[32]byte) (packet []byte, remoteLineSecret [32]byte, err error)

	generateLineEncryptionKey(localLineSecret *[32]byte, localLineId, remoteLineId *[16]byte) [32]byte
	generateLineDecryptionKey(remoteLineSecret *[32]byte, localLineId, remoteLineId *[16]byte) [32]byte

	encryptLinePacketBody(packet []byte, lineEncryptionKey *[32]byte) (linePacketBody []byte, err error)
	decryptLinePacketBody(linePacketBody []byte, lineDecryptionKey *[32]byte) (packet []byte, err error)
}

// A cipherPack holds a group of cipher sets
type cipherPack map[string]cipherSet

// extractParts will pull out the hashname parts from a cipherPack
func extractParts(cpack *cipherPack) (map[string]string, error) {

	if len(*cpack) == 0 {
		return nil, fmt.Errorf("cipherPack is empty")
	}

	parts := make(map[string]string)

	for _, cset := range *cpack {
		csid, fingerprint := cset.fingerprint()

		if fingerprint == "" {
			return nil, fmt.Errorf("fingerprint for %s is empty", csid)
		}

		parts[csid] = fingerprint
	}

	return parts, nil
}
<|endoftext|>


<commit_before><commit_msg>data/sessions: add db.DeleteSession method<commit_after><|endoftext|>


<commit_before>package metrics

import (
	"context"
	"crypto/sha1"
	"encoding/binary"
	"fmt"
	"sync"
)

func NewCollectableArray(m Metric, c CollectableCreator, l []string) *CollectableArray {
	for _, label := range l {
		if _, ok := m.Labels[label]; ok {
			panic("Cannot create ValuerArray with label in base and l")
		}
	}
	return &CollectableArray{
		Metric:    m,
		Creator:   c,
		LabelKeys: l,
	}
}

// Store an array of metrics.
type CollectableArray struct {
	// Base name + labelset to apply to all sub-metrics
	Metric

	// Function to create a new Value
	Creator CollectableCreator

	// Keys of all the labels allowed for metrics in this array
	LabelKeys []string

	// Map of labelset-hash -> Collectable
	//m map[uint64]Collectable
	m sync.Map
	// Map of labelset-hash -> label values
	// uint64->[]string
	mL sync.Map
}

func (m *CollectableArray) Describe(ctx context.Context, c chan<- MetricDesc) error {
	transformations := []MetricDescTransformation{
		func(d *MetricDesc) (bool, error) {
			if d.Name != "" {
				d.Name = m.Metric.Name + "_" + d.Name
			} else {
				d.Name = m.Metric.Name
			}
			// TODO: labels
			return true, nil
		},
	}
	return StreamMetricDescs(ctx, m.Creator(), c, transformations)
}

func (m *CollectableArray) Collect(ctx context.Context, c chan<- MetricPoint) error {
	var err error
	f := func(kRaw, vRaw interface{}) bool {
		k := kRaw.(uint64)
		v := vRaw.(Collectable)

		labelValues, ok := m.mL.Load(k)
		if !ok {
			err = fmt.Errorf("Unable to get label values")
			return false
		}

		transformations := []MetricPointTransformation{
			func(point *MetricPoint) (bool, error) {
				name := m.Metric.Name
				if point.Metric.Name != "" {
					name += "_" + point.Metric.Name
				}
				*point = MetricPoint{
					Metric{
						Name: name,
						Labels: MergeLabelsDirect(
							MergeLabels(m.Metric.Labels, m.LabelKeys, labelValues.([]string)),
							point.Metric.Labels),
					},
					point.Value,
				}
				return true, nil
			},
		}

		err = StreamMetricPoints(ctx, v, c, transformations)
		if err != nil {
			return false
		}
		return true
	}

	m.m.Range(f)
	return nil
}

// Access it by the slice of values
func (m *CollectableArray) WithValues(vals ...string) Collectable {

	h := sha1.New()

	for _, v := range vals {
		h.Write([]byte(v))
		h.Write([]byte(","))
	}

	// TODO: use hashing from sharding package?
	s := binary.LittleEndian.Uint64(h.Sum(nil)[:])

	collectable, ok := m.m.Load(s)
	if ok {
		return collectable.(Collectable)
	} else {
		// Otherwise it doesn't exist, so lets try adding it
		if _, ok := m.mL.LoadOrStore(s, vals); ok {
			return m.WithValues(vals...)
		}
		collectable = m.Creator()
		if _, ok = m.m.LoadOrStore(s, collectable); ok {
			return m.WithValues(vals...)
		}
		return collectable.(Collectable)
	}
}

func (m *CollectableArray) CounterWithValues(vals ...string) CounterType {
	v := m.WithValues(vals...)
	return v.(CounterType)
}

func (m *CollectableArray) GaugeWithValues(vals ...string) GaugeType {
	v := m.WithValues(vals...)
	return v.(GaugeType)
}

func (m *CollectableArray) ObserveWithValues(vals ...string) ObserveType {
	v := m.WithValues(vals...)
	return v.(ObserveType)
}
<commit_msg>Add len check for array<commit_after>package metrics

import (
	"context"
	"crypto/sha1"
	"encoding/binary"
	"fmt"
	"sync"
)

func NewCollectableArray(m Metric, c CollectableCreator, l []string) *CollectableArray {
	for _, label := range l {
		if _, ok := m.Labels[label]; ok {
			panic("Cannot create ValuerArray with label in base and l")
		}
	}
	return &CollectableArray{
		Metric:    m,
		Creator:   c,
		LabelKeys: l,
	}
}

// Store an array of metrics.
type CollectableArray struct {
	// Base name + labelset to apply to all sub-metrics
	Metric

	// Function to create a new Value
	Creator CollectableCreator

	// Keys of all the labels allowed for metrics in this array
	LabelKeys []string

	// Map of labelset-hash -> Collectable
	//m map[uint64]Collectable
	m sync.Map
	// Map of labelset-hash -> label values
	// uint64->[]string
	mL sync.Map
}

func (m *CollectableArray) Describe(ctx context.Context, c chan<- MetricDesc) error {
	transformations := []MetricDescTransformation{
		func(d *MetricDesc) (bool, error) {
			if d.Name != "" {
				d.Name = m.Metric.Name + "_" + d.Name
			} else {
				d.Name = m.Metric.Name
			}
			// TODO: labels
			return true, nil
		},
	}
	return StreamMetricDescs(ctx, m.Creator(), c, transformations)
}

func (m *CollectableArray) Collect(ctx context.Context, c chan<- MetricPoint) error {
	var err error
	f := func(kRaw, vRaw interface{}) bool {
		k := kRaw.(uint64)
		v := vRaw.(Collectable)

		labelValues, ok := m.mL.Load(k)
		if !ok {
			err = fmt.Errorf("Unable to get label values")
			return false
		}

		transformations := []MetricPointTransformation{
			func(point *MetricPoint) (bool, error) {
				name := m.Metric.Name
				if point.Metric.Name != "" {
					name += "_" + point.Metric.Name
				}
				*point = MetricPoint{
					Metric{
						Name: name,
						Labels: MergeLabelsDirect(
							MergeLabels(m.Metric.Labels, m.LabelKeys, labelValues.([]string)),
							point.Metric.Labels),
					},
					point.Value,
				}
				return true, nil
			},
		}

		err = StreamMetricPoints(ctx, v, c, transformations)
		if err != nil {
			return false
		}
		return true
	}

	m.m.Range(f)
	return nil
}

// Access it by the slice of values
func (m *CollectableArray) WithValues(vals ...string) Collectable {
	if len(vals) != len(m.LabelKeys) {
		panic("number of label values must match LabelKeys")
	}

	h := sha1.New()

	for _, v := range vals {
		h.Write([]byte(v))
		h.Write([]byte(","))
	}

	// TODO: use hashing from sharding package?
	s := binary.LittleEndian.Uint64(h.Sum(nil)[:])

	collectable, ok := m.m.Load(s)
	if ok {
		return collectable.(Collectable)
	} else {
		// Otherwise it doesn't exist, so lets try adding it
		if _, ok := m.mL.LoadOrStore(s, vals); ok {
			return m.WithValues(vals...)
		}
		collectable = m.Creator()
		if _, ok = m.m.LoadOrStore(s, collectable); ok {
			return m.WithValues(vals...)
		}
		return collectable.(Collectable)
	}
}

func (m *CollectableArray) CounterWithValues(vals ...string) CounterType {
	v := m.WithValues(vals...)
	return v.(CounterType)
}

func (m *CollectableArray) GaugeWithValues(vals ...string) GaugeType {
	v := m.WithValues(vals...)
	return v.(GaugeType)
}

func (m *CollectableArray) ObserveWithValues(vals ...string) ObserveType {
	v := m.WithValues(vals...)
	return v.(ObserveType)
}
<|endoftext|>


<commit_before>// Package teststat provides helpers for testing metrics backends.
package teststat

import (
	"errors"
	"fmt"
	"math"
	"math/rand"
	"strings"

	"github.com/go-kit/kit/metrics"
)

// TestCounter puts some deltas through the counter, and then calls the value
// func to check that the counter has the correct final value.
func TestCounter(counter metrics.Counter, value func() float64) error {
	a := rand.Perm(100)
	n := rand.Intn(len(a))

	var want float64
	for i := 0; i < n; i++ {
		f := float64(a[i])
		counter.Add(f)
		want += f
	}

	if have := value(); want != have {
		return fmt.Errorf("want %f, have %f", want, have)
	}

	return nil
}

// TestGauge puts some values through the gauge, and then calls the value func
// to check that the gauge has the correct final value.
func TestGauge(gauge metrics.Gauge, value func() float64) error {
	a := rand.Perm(100)
	n := rand.Intn(len(a))

	var want float64
	for i := 0; i < n; i++ {
		f := float64(a[i])
		gauge.Set(f)
		want = f
	}

	for i := 0; i < n; i++ {
		f := float64(a[i])
		gauge.Add(f)
		want += f
	}

	if have := value(); want != have {
		return fmt.Errorf("want %f, have %f", want, have)
	}

	return nil
}

// TestHistogram puts some observations through the histogram, and then calls
// the quantiles func to checks that the histogram has computed the correct
// quantiles within some tolerance
func TestHistogram(histogram metrics.Histogram, quantiles func() (p50, p90, p95, p99 float64), tolerance float64) error {
	PopulateNormalHistogram(histogram, rand.Int())

	want50, want90, want95, want99 := normalQuantiles()
	have50, have90, have95, have99 := quantiles()

	var errs []string
	if want, have := want50, have50; !cmp(want, have, tolerance) {
		errs = append(errs, fmt.Sprintf("p50: want %f, have %f", want, have))
	}
	if want, have := want90, have90; !cmp(want, have, tolerance) {
		errs = append(errs, fmt.Sprintf("p90: want %f, have %f", want, have))
	}
	if want, have := want95, have95; !cmp(want, have, tolerance) {
		errs = append(errs, fmt.Sprintf("p95: want %f, have %f", want, have))
	}
	if want, have := want99, have99; !cmp(want, have, tolerance) {
		errs = append(errs, fmt.Sprintf("p99: want %f, have %f", want, have))
	}
	if len(errs) > 0 {
		return errors.New(strings.Join(errs, "; "))
	}

	return nil
}

var (
	// Count is the number of observations.
	Count = 12345

	// Mean is the center of the normal distribution of observations.
	Mean = 500

	// Stdev of the normal distribution of observations.
	Stdev = 25
)

// ExpectedObservationsLessThan returns the number of observations that should
// have a value less than or equal to the given value, given a normal
// distribution of observations described by Count, Mean, and Stdev.
func ExpectedObservationsLessThan(bucket int64) int64 {
	// https://code.google.com/p/gostat/source/browse/stat/normal.go
	cdf := ((1.0 / 2.0) * (1 + math.Erf((float64(bucket)-float64(Mean))/(float64(Stdev)*math.Sqrt2))))
	return int64(cdf * float64(Count))
}

func cmp(want, have, tol float64) bool {
	if (math.Abs(want-have) / want) > tol {
		return false
	}
	return true
}
<commit_msg>Issue #529: Extracted FillCounter() from TestCounter() to reuse counter-filling logic in cloudwatch_test.go<commit_after>// Package teststat provides helpers for testing metrics backends.
package teststat

import (
	"errors"
	"fmt"
	"math"
	"math/rand"
	"strings"

	"github.com/go-kit/kit/metrics"
)

// TestCounter puts some deltas through the counter, and then calls the value
// func to check that the counter has the correct final value.
func TestCounter(counter metrics.Counter, value func() float64) error {
	want := FillCounter(counter)
	if have := value(); want != have {
		return fmt.Errorf("want %f, have %f", want, have)
	}

	return nil
}

// FillCounter puts some deltas through the counter and returns the total value.
func FillCounter(counter metrics.Counter) float64 {
	a := rand.Perm(100)
	n := rand.Intn(len(a))

	var want float64
	for i := 0; i < n; i++ {
		f := float64(a[i])
		counter.Add(f)
		want += f
	}
	return want
}

// TestGauge puts some values through the gauge, and then calls the value func
// to check that the gauge has the correct final value.
func TestGauge(gauge metrics.Gauge, value func() float64) error {
	a := rand.Perm(100)
	n := rand.Intn(len(a))

	var want float64
	for i := 0; i < n; i++ {
		f := float64(a[i])
		gauge.Set(f)
		want = f
	}

	for i := 0; i < n; i++ {
		f := float64(a[i])
		gauge.Add(f)
		want += f
	}

	if have := value(); want != have {
		return fmt.Errorf("want %f, have %f", want, have)
	}

	return nil
}

// TestHistogram puts some observations through the histogram, and then calls
// the quantiles func to checks that the histogram has computed the correct
// quantiles within some tolerance
func TestHistogram(histogram metrics.Histogram, quantiles func() (p50, p90, p95, p99 float64), tolerance float64) error {
	PopulateNormalHistogram(histogram, rand.Int())

	want50, want90, want95, want99 := normalQuantiles()
	have50, have90, have95, have99 := quantiles()

	var errs []string
	if want, have := want50, have50; !cmp(want, have, tolerance) {
		errs = append(errs, fmt.Sprintf("p50: want %f, have %f", want, have))
	}
	if want, have := want90, have90; !cmp(want, have, tolerance) {
		errs = append(errs, fmt.Sprintf("p90: want %f, have %f", want, have))
	}
	if want, have := want95, have95; !cmp(want, have, tolerance) {
		errs = append(errs, fmt.Sprintf("p95: want %f, have %f", want, have))
	}
	if want, have := want99, have99; !cmp(want, have, tolerance) {
		errs = append(errs, fmt.Sprintf("p99: want %f, have %f", want, have))
	}
	if len(errs) > 0 {
		return errors.New(strings.Join(errs, "; "))
	}

	return nil
}

var (
	// Count is the number of observations.
	Count = 12345

	// Mean is the center of the normal distribution of observations.
	Mean = 500

	// Stdev of the normal distribution of observations.
	Stdev = 25
)

// ExpectedObservationsLessThan returns the number of observations that should
// have a value less than or equal to the given value, given a normal
// distribution of observations described by Count, Mean, and Stdev.
func ExpectedObservationsLessThan(bucket int64) int64 {
	// https://code.google.com/p/gostat/source/browse/stat/normal.go
	cdf := ((1.0 / 2.0) * (1 + math.Erf((float64(bucket)-float64(Mean))/(float64(Stdev)*math.Sqrt2))))
	return int64(cdf * float64(Count))
}

func cmp(want, have, tol float64) bool {
	if (math.Abs(want-have) / want) > tol {
		return false
	}
	return true
}
<|endoftext|>


<commit_before>package resources

import (
	"github.com/hashicorp/terraform/helper/schema"
	"code.cloudfoundry.org/cli/cf/models"
	"github.com/orange-cloudfoundry/terraform-provider-cloudfoundry/cf_client"
	"log"
	"reflect"
	"fmt"
	"bytes"
	"github.com/hashicorp/terraform/helper/hashcode"
	"strconv"
	"github.com/orange-cloudfoundry/terraform-provider-cloudfoundry/resources/caching"
	"errors"
	"strings"
	"regexp"
)

var validProtocoles []string = []string{"icm", "tcp", "udp", "all"}

type CfSecurityGroupResource struct {
	CfResource
}

func NewCfSecurityGroupResource() CfResource {
	return &CfSecurityGroupResource{}
}

func (c CfSecurityGroupResource) resourceObject(d *schema.ResourceData) models.SecurityGroupFields {
	rulesSchema := d.Get("rules").(*schema.Set)
	rules := make([]map[string]interface{}, 0)
	for _, rule := range rulesSchema.List() {
		rules = append(rules, c.sanitizeRule(rule.(map[string]interface{})))
	}
	return models.SecurityGroupFields{
		GUID: d.Id(),
		Name: d.Get("name").(string),
		Rules: rules,
	}
}
func (c CfSecurityGroupResource) unSanitizeRule(rule map[string]interface{}) map[string]interface{} {
	unSanitizedRule := make(map[string]interface{})
	if _, ok := rule["code"]; !ok {
		unSanitizedRule["code"] = 0
	}
	if _, ok := rule["type"]; !ok {
		unSanitizedRule["type"] = 0
	}
	for index, content := range rule {
		unSanitizedRule[index] = content
	}
	return unSanitizedRule
}
func (c CfSecurityGroupResource) sanitizeRule(rule map[string]interface{}) map[string]interface{} {
	sanitizedRule := make(map[string]interface{})

	for index, content := range rule {
		if index == "code" && content.(int) == 0 {
			continue
		}
		if index == "type" && content.(int) == 0 {
			continue
		}
		sanitizedRule[index] = content
	}
	return sanitizedRule
}
func (c CfSecurityGroupResource) Create(d *schema.ResourceData, meta interface{}) error {
	client := meta.(cf_client.Client)
	secGroup := c.resourceObject(d)
	var err error
	if ok, _ := c.Exists(d, meta); ok {
		log.Printf(
			"[INFO] skipping creation of security group %s/%s because it already exists on your Cloud Foundry",
			client.Config().ApiEndpoint,
			secGroup.Name,
		)
		err = client.SecurityGroups().Update(d.Id(), secGroup.Rules)
		if err != nil {
			return err
		}
	} else {
		err = client.SecurityGroups().Create(secGroup.Name, secGroup.Rules)
		if err != nil {
			return err
		}
		_, err = c.Exists(d, meta)
		if err != nil {
			return err
		}
	}
	if d.Get("on_staging").(bool) {
		err = client.SecurityGroupsStagingBinder().BindToStagingSet(d.Id())
		if err != nil {
			return err
		}
	}
	if d.Get("on_running").(bool) {
		err = client.SecurityGroupsRunningBinder().BindToRunningSet(d.Id())
		if err != nil {
			return err
		}
	}
	return nil
}

func (c CfSecurityGroupResource) Read(d *schema.ResourceData, meta interface{}) error {
	client := meta.(cf_client.Client)
	secGroupName := d.Get("name").(string)
	secGroup, err := c.getSecGroupFromCf(client, d.Id(), true)
	if err != nil {
		return err
	}
	if secGroup.GUID == "" {
		log.Printf(
			"[WARN] removing security group %s/%s from state because it no longer exists in your Cloud Foundry",
			client.Config().ApiEndpoint,
			secGroupName,
		)
		d.SetId("")
		return nil
	}
	d.Set("name", secGroup.Name)
	rules := make([]interface{}, 0)
	rulesSchema := schema.NewSet(d.Get("rules").(*schema.Set).F, rules)
	for _, rule := range secGroup.Rules {
		rulesSchema.Add(c.unSanitizeRule(rule))
	}
	d.Set("rules", rulesSchema)
	isOnStaging, err := c.isOnStaging(client, secGroup.GUID)
	if err != nil {
		return err
	}
	isOnRunning, err := c.isOnRunning(client, secGroup.GUID)
	if err != nil {
		return err
	}
	d.Set("on_staging", isOnStaging)
	d.Set("on_running", isOnRunning)
	return nil
}
func (c CfSecurityGroupResource) Update(d *schema.ResourceData, meta interface{}) error {
	client := meta.(cf_client.Client)
	secGroup := c.resourceObject(d)
	secGroupCf, err := c.getSecGroupFromCf(client, d.Id(), false)
	if err != nil {
		return err
	}
	if secGroupCf.GUID == "" {
		log.Printf(
			"[WARN] removing security group %s/%s from state because it no longer exists in your Cloud Foundry",
			client.Config().ApiEndpoint,
			secGroup.Name,
		)
		d.SetId("")
		return nil
	}
	if c.isRulesChange(secGroupCf.Rules, secGroup.Rules) {
		client.SecurityGroups().Update(d.Id(), secGroup.Rules)
	}
	isOnStaging, err := c.isOnStaging(client, d.Id())
	if err != nil {
		return err
	}
	if d.Get("on_staging").(bool) != isOnStaging {
		err = c.updateBindingStaging(client, d.Id(), d.Get("on_staging").(bool))
		if err != nil {
			return err
		}
	}
	if d.Get("on_running").(bool) != isOnStaging {
		err = c.updateBindingStaging(client, d.Id(), d.Get("on_running").(bool))
		if err != nil {
			return err
		}
	}
	return nil
}
func (c CfSecurityGroupResource) Delete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(cf_client.Client)
	return client.SecurityGroups().Delete(d.Id())
}
func (c CfSecurityGroupResource) updateBindingStaging(client cf_client.Client, guid string, onStaging bool) error {
	if onStaging {
		return client.SecurityGroupsStagingBinder().BindToStagingSet(guid)
	}
	return client.SecurityGroupsStagingBinder().UnbindFromStagingSet(guid)
}
func (c CfSecurityGroupResource) updateBindingRunning(client cf_client.Client, guid string, onRunning bool) error {
	if onRunning {
		return client.SecurityGroupsRunningBinder().BindToRunningSet(guid)
	}
	return client.SecurityGroupsRunningBinder().UnbindFromRunningSet(guid)
}
func (c CfSecurityGroupResource) isRulesChange(rulesFrom, rulesTo []map[string]interface{}) bool {
	if rulesFrom == nil && rulesTo == nil {
		return false;
	}
	if rulesFrom == nil || rulesTo == nil {
		return true;
	}
	if len(rulesFrom) != len(rulesTo) {
		return true
	}
	for i := range rulesFrom {
		if !reflect.DeepEqual(rulesFrom[i], rulesTo[i]) {
			return true
		}
	}
	for i := range rulesTo {
		if !reflect.DeepEqual(rulesFrom[i], rulesTo[i]) {
			return true
		}
	}
	return false

}
func (c CfSecurityGroupResource) isOnStaging(client cf_client.Client, secGroupId string) (bool, error) {
	secGroups, err := client.SecurityGroupsStagingBinder().List()
	if err != nil {
		return false, err
	}
	return c.existsSecurityGroup(secGroups, secGroupId), nil
}
func (c CfSecurityGroupResource) isOnRunning(client cf_client.Client, secGroupId string) (bool, error) {
	secGroups, err := client.SecurityGroupsRunningBinder().List()
	if err != nil {
		return false, err
	}
	return c.existsSecurityGroup(secGroups, secGroupId), nil
}
func (c CfSecurityGroupResource) existsSecurityGroup(secGroups []models.SecurityGroupFields, secGroupId string) bool {
	for _, secGroup := range secGroups {
		if secGroup.GUID == secGroupId {
			return true
		}
	}
	return false
}
func (c CfSecurityGroupResource) getSecGroupFromCf(client cf_client.Client, secGroupId string, updateCache bool) (models.SecurityGroupFields, error) {
	secGroups, err := caching.GetSecGroupsFromCf(client, updateCache)
	if err != nil {
		return models.SecurityGroupFields{}, err
	}
	for _, secGroup := range secGroups {
		if secGroup.GUID == secGroupId {
			return secGroup.SecurityGroupFields, nil
		}
	}
	return models.SecurityGroupFields{}, nil
}
func (c CfSecurityGroupResource) Exists(d *schema.ResourceData, meta interface{}) (bool, error) {
	client := meta.(cf_client.Client)
	name := d.Get("name").(string)
	secGroups, err := caching.GetSecGroupsFromCf(client, true)
	if err != nil {
		return false, err
	}
	for _, secGroup := range secGroups {
		if secGroup.Name == name {
			d.SetId(secGroup.GUID)
			return true, nil
		}
	}

	return false, nil
}

func (c CfSecurityGroupResource) Schema() map[string]*schema.Schema {
	return map[string]*schema.Schema{
		"name": &schema.Schema{
			Type:     schema.TypeString,
			Required: true,
			ForceNew: true,
		},
		"rules": &schema.Schema{
			Type:     schema.TypeSet,
			Required: true,

			Elem:     &schema.Resource{
				Schema: map[string]*schema.Schema{
					"protocol": &schema.Schema{
						Type:     schema.TypeString,
						Required: true,
						ValidateFunc: func(elem interface{}, index string) ([]string, []error) {
							prot := elem.(string)
							found := false
							for _, validProt := range validProtocoles {
								if validProt == prot {
									found = true
									break
								}
							}
							if found {
								return make([]string, 0), make([]error, 0)
							}
							errMsg := fmt.Sprintf(
								"Protocol '%s' is not valid, it must be one of %s",
								prot,
								strings.Join(validProtocoles, ", "),
							)
							err := errors.New(errMsg)
							return make([]string, 0), []error{err}
						},
					},
					"destination": &schema.Schema{
						Type:     schema.TypeString,
						Optional: true,
					},
					"description": &schema.Schema{
						Type:     schema.TypeString,
						Optional: true,
					},
					"ports": &schema.Schema{
						Type:     schema.TypeString,
						Optional: true,
						ValidateFunc: func(elem interface{}, index string) ([]string, []error) {
							ports := elem.(string)
							match, _ := regexp.MatchString("^[0-9][0-9-,],[0-9]?$", ports)
							if match {
								return make([]string, 0), make([]error, 0)
							}
							errMsg := fmt.Sprintf(
								"Ports '%s' is not valid. (valid examples: '443', '80,8080,8081', '8080-8081')",
								ports,
							)
							err := errors.New(errMsg)
							return make([]string, 0), []error{err}
						},
					},
					"code": &schema.Schema{
						Type:     schema.TypeInt,
						Optional: true,
					},
					"type": &schema.Schema{
						Type:     schema.TypeInt,
						Optional: true,
					},
					"log": &schema.Schema{
						Type:     schema.TypeBool,
						Default: true,
						Optional: true,
					},
				},
			},
			Set: func(v interface{}) int {
				var buf bytes.Buffer
				m := v.(map[string]interface{})
				buf.WriteString(fmt.Sprintf("%s-", m["protocol"].(string)))
				buf.WriteString(fmt.Sprintf("%s-", m["destination"].(string)))
				buf.WriteString(fmt.Sprintf("%s-", m["description"].(string)))
				buf.WriteString(fmt.Sprintf("%s-", m["ports"].(string)))
				buf.WriteString(fmt.Sprintf("%s-", strconv.Itoa(m["code"].(int))))
				buf.WriteString(fmt.Sprintf("%s-", strconv.Itoa(m["type"].(int))))
				buf.WriteString(fmt.Sprintf("%s-", strconv.FormatBool(m["log"].(bool))))
				return hashcode.String(buf.String())
			},
		},
		"on_staging": &schema.Schema{
			Type:     schema.TypeBool,
			Optional: true,
		},
		"on_running": &schema.Schema{
			Type:     schema.TypeBool,
			Optional: true,
		},
	}
}

<commit_msg>fix regex for ports checking in security group<commit_after>package resources

import (
	"github.com/hashicorp/terraform/helper/schema"
	"code.cloudfoundry.org/cli/cf/models"
	"github.com/orange-cloudfoundry/terraform-provider-cloudfoundry/cf_client"
	"log"
	"reflect"
	"fmt"
	"bytes"
	"github.com/hashicorp/terraform/helper/hashcode"
	"strconv"
	"github.com/orange-cloudfoundry/terraform-provider-cloudfoundry/resources/caching"
	"errors"
	"strings"
	"regexp"
)

var validProtocoles []string = []string{"icm", "tcp", "udp", "all"}

type CfSecurityGroupResource struct {
	CfResource
}

func NewCfSecurityGroupResource() CfResource {
	return &CfSecurityGroupResource{}
}

func (c CfSecurityGroupResource) resourceObject(d *schema.ResourceData) models.SecurityGroupFields {
	rulesSchema := d.Get("rules").(*schema.Set)
	rules := make([]map[string]interface{}, 0)
	for _, rule := range rulesSchema.List() {
		rules = append(rules, c.sanitizeRule(rule.(map[string]interface{})))
	}
	return models.SecurityGroupFields{
		GUID: d.Id(),
		Name: d.Get("name").(string),
		Rules: rules,
	}
}
func (c CfSecurityGroupResource) unSanitizeRule(rule map[string]interface{}) map[string]interface{} {
	unSanitizedRule := make(map[string]interface{})
	if _, ok := rule["code"]; !ok {
		unSanitizedRule["code"] = 0
	}
	if _, ok := rule["type"]; !ok {
		unSanitizedRule["type"] = 0
	}
	for index, content := range rule {
		unSanitizedRule[index] = content
	}
	return unSanitizedRule
}
func (c CfSecurityGroupResource) sanitizeRule(rule map[string]interface{}) map[string]interface{} {
	sanitizedRule := make(map[string]interface{})

	for index, content := range rule {
		if index == "code" && content.(int) == 0 {
			continue
		}
		if index == "type" && content.(int) == 0 {
			continue
		}
		sanitizedRule[index] = content
	}
	return sanitizedRule
}
func (c CfSecurityGroupResource) Create(d *schema.ResourceData, meta interface{}) error {
	client := meta.(cf_client.Client)
	secGroup := c.resourceObject(d)
	var err error
	if ok, _ := c.Exists(d, meta); ok {
		log.Printf(
			"[INFO] skipping creation of security group %s/%s because it already exists on your Cloud Foundry",
			client.Config().ApiEndpoint,
			secGroup.Name,
		)
		err = client.SecurityGroups().Update(d.Id(), secGroup.Rules)
		if err != nil {
			return err
		}
	} else {
		err = client.SecurityGroups().Create(secGroup.Name, secGroup.Rules)
		if err != nil {
			return err
		}
		_, err = c.Exists(d, meta)
		if err != nil {
			return err
		}
	}
	if d.Get("on_staging").(bool) {
		err = client.SecurityGroupsStagingBinder().BindToStagingSet(d.Id())
		if err != nil {
			return err
		}
	}
	if d.Get("on_running").(bool) {
		err = client.SecurityGroupsRunningBinder().BindToRunningSet(d.Id())
		if err != nil {
			return err
		}
	}
	return nil
}

func (c CfSecurityGroupResource) Read(d *schema.ResourceData, meta interface{}) error {
	client := meta.(cf_client.Client)
	secGroupName := d.Get("name").(string)
	secGroup, err := c.getSecGroupFromCf(client, d.Id(), true)
	if err != nil {
		return err
	}
	if secGroup.GUID == "" {
		log.Printf(
			"[WARN] removing security group %s/%s from state because it no longer exists in your Cloud Foundry",
			client.Config().ApiEndpoint,
			secGroupName,
		)
		d.SetId("")
		return nil
	}
	d.Set("name", secGroup.Name)
	rules := make([]interface{}, 0)
	rulesSchema := schema.NewSet(d.Get("rules").(*schema.Set).F, rules)
	for _, rule := range secGroup.Rules {
		rulesSchema.Add(c.unSanitizeRule(rule))
	}
	d.Set("rules", rulesSchema)
	isOnStaging, err := c.isOnStaging(client, secGroup.GUID)
	if err != nil {
		return err
	}
	isOnRunning, err := c.isOnRunning(client, secGroup.GUID)
	if err != nil {
		return err
	}
	d.Set("on_staging", isOnStaging)
	d.Set("on_running", isOnRunning)
	return nil
}
func (c CfSecurityGroupResource) Update(d *schema.ResourceData, meta interface{}) error {
	client := meta.(cf_client.Client)
	secGroup := c.resourceObject(d)
	secGroupCf, err := c.getSecGroupFromCf(client, d.Id(), false)
	if err != nil {
		return err
	}
	if secGroupCf.GUID == "" {
		log.Printf(
			"[WARN] removing security group %s/%s from state because it no longer exists in your Cloud Foundry",
			client.Config().ApiEndpoint,
			secGroup.Name,
		)
		d.SetId("")
		return nil
	}
	if c.isRulesChange(secGroupCf.Rules, secGroup.Rules) {
		client.SecurityGroups().Update(d.Id(), secGroup.Rules)
	}
	isOnStaging, err := c.isOnStaging(client, d.Id())
	if err != nil {
		return err
	}
	if d.Get("on_staging").(bool) != isOnStaging {
		err = c.updateBindingStaging(client, d.Id(), d.Get("on_staging").(bool))
		if err != nil {
			return err
		}
	}
	if d.Get("on_running").(bool) != isOnStaging {
		err = c.updateBindingStaging(client, d.Id(), d.Get("on_running").(bool))
		if err != nil {
			return err
		}
	}
	return nil
}
func (c CfSecurityGroupResource) Delete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(cf_client.Client)
	return client.SecurityGroups().Delete(d.Id())
}
func (c CfSecurityGroupResource) updateBindingStaging(client cf_client.Client, guid string, onStaging bool) error {
	if onStaging {
		return client.SecurityGroupsStagingBinder().BindToStagingSet(guid)
	}
	return client.SecurityGroupsStagingBinder().UnbindFromStagingSet(guid)
}
func (c CfSecurityGroupResource) updateBindingRunning(client cf_client.Client, guid string, onRunning bool) error {
	if onRunning {
		return client.SecurityGroupsRunningBinder().BindToRunningSet(guid)
	}
	return client.SecurityGroupsRunningBinder().UnbindFromRunningSet(guid)
}
func (c CfSecurityGroupResource) isRulesChange(rulesFrom, rulesTo []map[string]interface{}) bool {
	if rulesFrom == nil && rulesTo == nil {
		return false;
	}
	if rulesFrom == nil || rulesTo == nil {
		return true;
	}
	if len(rulesFrom) != len(rulesTo) {
		return true
	}
	for i := range rulesFrom {
		if !reflect.DeepEqual(rulesFrom[i], rulesTo[i]) {
			return true
		}
	}
	for i := range rulesTo {
		if !reflect.DeepEqual(rulesFrom[i], rulesTo[i]) {
			return true
		}
	}
	return false

}
func (c CfSecurityGroupResource) isOnStaging(client cf_client.Client, secGroupId string) (bool, error) {
	secGroups, err := client.SecurityGroupsStagingBinder().List()
	if err != nil {
		return false, err
	}
	return c.existsSecurityGroup(secGroups, secGroupId), nil
}
func (c CfSecurityGroupResource) isOnRunning(client cf_client.Client, secGroupId string) (bool, error) {
	secGroups, err := client.SecurityGroupsRunningBinder().List()
	if err != nil {
		return false, err
	}
	return c.existsSecurityGroup(secGroups, secGroupId), nil
}
func (c CfSecurityGroupResource) existsSecurityGroup(secGroups []models.SecurityGroupFields, secGroupId string) bool {
	for _, secGroup := range secGroups {
		if secGroup.GUID == secGroupId {
			return true
		}
	}
	return false
}
func (c CfSecurityGroupResource) getSecGroupFromCf(client cf_client.Client, secGroupId string, updateCache bool) (models.SecurityGroupFields, error) {
	secGroups, err := caching.GetSecGroupsFromCf(client, updateCache)
	if err != nil {
		return models.SecurityGroupFields{}, err
	}
	for _, secGroup := range secGroups {
		if secGroup.GUID == secGroupId {
			return secGroup.SecurityGroupFields, nil
		}
	}
	return models.SecurityGroupFields{}, nil
}
func (c CfSecurityGroupResource) Exists(d *schema.ResourceData, meta interface{}) (bool, error) {
	client := meta.(cf_client.Client)
	name := d.Get("name").(string)
	secGroups, err := caching.GetSecGroupsFromCf(client, true)
	if err != nil {
		return false, err
	}
	for _, secGroup := range secGroups {
		if secGroup.Name == name {
			d.SetId(secGroup.GUID)
			return true, nil
		}
	}

	return false, nil
}

func (c CfSecurityGroupResource) Schema() map[string]*schema.Schema {
	return map[string]*schema.Schema{
		"name": &schema.Schema{
			Type:     schema.TypeString,
			Required: true,
			ForceNew: true,
		},
		"rules": &schema.Schema{
			Type:     schema.TypeSet,
			Required: true,

			Elem:     &schema.Resource{
				Schema: map[string]*schema.Schema{
					"protocol": &schema.Schema{
						Type:     schema.TypeString,
						Required: true,
						ValidateFunc: func(elem interface{}, index string) ([]string, []error) {
							prot := elem.(string)
							found := false
							for _, validProt := range validProtocoles {
								if validProt == prot {
									found = true
									break
								}
							}
							if found {
								return make([]string, 0), make([]error, 0)
							}
							errMsg := fmt.Sprintf(
								"Protocol '%s' is not valid, it must be one of %s",
								prot,
								strings.Join(validProtocoles, ", "),
							)
							err := errors.New(errMsg)
							return make([]string, 0), []error{err}
						},
					},
					"destination": &schema.Schema{
						Type:     schema.TypeString,
						Optional: true,
					},
					"description": &schema.Schema{
						Type:     schema.TypeString,
						Optional: true,
					},
					"ports": &schema.Schema{
						Type:     schema.TypeString,
						Optional: true,
						ValidateFunc: func(elem interface{}, index string) ([]string, []error) {
							ports := elem.(string)
							match, _ := regexp.MatchString("^[0-9][0-9-,]*[0-9]?$", ports)
							if match {
								return make([]string, 0), make([]error, 0)
							}
							errMsg := fmt.Sprintf(
								"Ports '%s' is not valid. (valid examples: '443', '80,8080,8081', '8080-8081')",
								ports,
							)
							err := errors.New(errMsg)
							return make([]string, 0), []error{err}
						},
					},
					"code": &schema.Schema{
						Type:     schema.TypeInt,
						Optional: true,
					},
					"type": &schema.Schema{
						Type:     schema.TypeInt,
						Optional: true,
					},
					"log": &schema.Schema{
						Type:     schema.TypeBool,
						Default: true,
						Optional: true,
					},
				},
			},
			Set: func(v interface{}) int {
				var buf bytes.Buffer
				m := v.(map[string]interface{})
				buf.WriteString(fmt.Sprintf("%s-", m["protocol"].(string)))
				buf.WriteString(fmt.Sprintf("%s-", m["destination"].(string)))
				buf.WriteString(fmt.Sprintf("%s-", m["description"].(string)))
				buf.WriteString(fmt.Sprintf("%s-", m["ports"].(string)))
				buf.WriteString(fmt.Sprintf("%s-", strconv.Itoa(m["code"].(int))))
				buf.WriteString(fmt.Sprintf("%s-", strconv.Itoa(m["type"].(int))))
				buf.WriteString(fmt.Sprintf("%s-", strconv.FormatBool(m["log"].(bool))))
				return hashcode.String(buf.String())
			},
		},
		"on_staging": &schema.Schema{
			Type:     schema.TypeBool,
			Optional: true,
		},
		"on_running": &schema.Schema{
			Type:     schema.TypeBool,
			Optional: true,
		},
	}
}

<|endoftext|>


<commit_before>package config

import (
	"reflect"
	"strings"
	"testing"
)

func TestNewInterpolation(t *testing.T) {
	cases := []struct {
		Input  string
		Result Interpolation
		Error  bool
	}{
		{
			"foo",
			nil,
			true,
		},

		{
			"var.foo",
			&VariableInterpolation{
				Variable: &UserVariable{
					Name: "foo",
					key:  "var.foo",
				},
				key: "var.foo",
			},
			false,
		},

		{
			"lookup(var.foo, var.bar)",
			&FunctionInterpolation{
				Func: nil, // Funcs["lookup"]
				Args: []InterpolatedVariable{
					&UserVariable{
						Name: "foo",
						key:  "var.foo",
					},
					&UserVariable{
						Name: "bar",
						key:  "var.bar",
					},
				},
				key: "lookup(var.foo, var.bar)",
			},
			false,
		},
	}

	for i, tc := range cases {
		actual, err := NewInterpolation(tc.Input)
		if (err != nil) != tc.Error {
			t.Fatalf("%d. Error: %s", i, err)
		}

		// This is jank, but reflect.DeepEqual never has functions
		// being the same.
		if f, ok := actual.(*FunctionInterpolation); ok {
			f.Func = nil
		}

		if !reflect.DeepEqual(actual, tc.Result) {
			t.Fatalf("%d bad: %#v", i, actual)
		}
	}
}

func TestNewInterpolatedVariable(t *testing.T) {
	cases := []struct {
		Input  string
		Result InterpolatedVariable
		Error  bool
	}{
		{
			"var.foo",
			&UserVariable{
				Name: "foo",
				key:  "var.foo",
			},
			false,
		},
	}

	for i, tc := range cases {
		actual, err := NewInterpolatedVariable(tc.Input)
		if (err != nil) != tc.Error {
			t.Fatalf("%d. Error: %s", i, err)
		}
		if !reflect.DeepEqual(actual, tc.Result) {
			t.Fatalf("%d bad: %#v", i, actual)
		}
	}
}

func TestNewResourceVariable(t *testing.T) {
	v, err := NewResourceVariable("foo.bar.baz")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if v.Type != "foo" {
		t.Fatalf("bad: %#v", v)
	}
	if v.Name != "bar" {
		t.Fatalf("bad: %#v", v)
	}
	if v.Field != "baz" {
		t.Fatalf("bad: %#v", v)
	}
	if v.Multi {
		t.Fatal("should not be multi")
	}

	if v.FullKey() != "foo.bar.baz" {
		t.Fatalf("bad: %#v", v)
	}
}

func TestNewUserVariable(t *testing.T) {
	v, err := NewUserVariable("var.bar")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if v.Name != "bar" {
		t.Fatalf("bad: %#v", v.Name)
	}
	if v.FullKey() != "var.bar" {
		t.Fatalf("bad: %#v", v)
	}
}

func TestFunctionInterpolation_impl(t *testing.T) {
	var _ Interpolation = new(FunctionInterpolation)
}

func TestFunctionInterpolation(t *testing.T) {
	v1, err := NewInterpolatedVariable("var.foo")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	v2, err := NewInterpolatedVariable("var.bar")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	fn := func(vs map[string]string, args ...string) (string, error) {
		return strings.Join(args, " "), nil
	}

	i := &FunctionInterpolation{
		Func: fn,
		Args: []InterpolatedVariable{v1, v2},
		key:  "foo",
	}
	if i.FullString() != "foo" {
		t.Fatalf("err: %#v", i)
	}

	expected := map[string]InterpolatedVariable{
		"var.foo": v1,
		"var.bar": v2,
	}
	if !reflect.DeepEqual(i.Variables(), expected) {
		t.Fatalf("bad: %#v", i.Variables())
	}

	actual, err := i.Interpolate(map[string]string{
		"var.foo": "bar",
		"var.bar": "baz",
	})
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if actual != "bar baz" {
		t.Fatalf("bad: %#v", actual)
	}
}

func TestResourceVariable_impl(t *testing.T) {
	var _ InterpolatedVariable = new(ResourceVariable)
}

func TestResourceVariable_Multi(t *testing.T) {
	v, err := NewResourceVariable("foo.bar.*.baz")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if v.Type != "foo" {
		t.Fatalf("bad: %#v", v)
	}
	if v.Name != "bar" {
		t.Fatalf("bad: %#v", v)
	}
	if v.Field != "baz" {
		t.Fatalf("bad: %#v", v)
	}
	if !v.Multi {
		t.Fatal("should be multi")
	}
}

func TestResourceVariable_MultiIndex(t *testing.T) {
	cases := []struct {
		Input string
		Index int
		Field string
	}{
		{"foo.bar.*.baz", -1, "baz"},
		{"foo.bar.0.baz", 0, "baz"},
		{"foo.bar.5.baz", 5, "baz"},
	}

	for _, tc := range cases {
		v, err := NewResourceVariable(tc.Input)
		if err != nil {
			t.Fatalf("err: %s", err)
		}
		if !v.Multi {
			t.Fatalf("should be multi: %s", tc.Input)
		}
		if v.Index != tc.Index {
			t.Fatalf("bad: %d\n\n%s", v.Index, tc.Input)
		}
		if v.Field != tc.Field {
			t.Fatalf("bad: %s\n\n%s", v.Field, tc.Input)
		}
	}
}

func TestUserVariable_impl(t *testing.T) {
	var _ InterpolatedVariable = new(UserVariable)
}

func TestVariableInterpolation_impl(t *testing.T) {
	var _ Interpolation = new(VariableInterpolation)
}

func TestVariableInterpolation(t *testing.T) {
	uv, err := NewUserVariable("var.foo")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	i := &VariableInterpolation{Variable: uv, key: "var.foo"}
	if i.FullString() != "var.foo" {
		t.Fatalf("err: %#v", i)
	}

	expected := map[string]InterpolatedVariable{"var.foo": uv}
	if !reflect.DeepEqual(i.Variables(), expected) {
		t.Fatalf("bad: %#v", i.Variables())
	}

	actual, err := i.Interpolate(map[string]string{
		"var.foo": "bar",
	})
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if actual != "bar" {
		t.Fatalf("bad: %#v", actual)
	}
}

func TestVariableInterpolation_missing(t *testing.T) {
	uv, err := NewUserVariable("var.foo")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	i := &VariableInterpolation{Variable: uv, key: "var.foo"}
	_, err = i.Interpolate(map[string]string{
		"var.bar": "bar",
	})
	if err == nil {
		t.Fatal("should error")
	}
}
<commit_msg>config: tests<commit_after>package config

import (
	"reflect"
	"strings"
	"testing"
)

func TestNewInterpolation(t *testing.T) {
	cases := []struct {
		Input  string
		Result Interpolation
		Error  bool
	}{
		{
			"foo",
			nil,
			true,
		},

		{
			"var.foo",
			&VariableInterpolation{
				Variable: &UserVariable{
					Name: "foo",
					key:  "var.foo",
				},
				key: "var.foo",
			},
			false,
		},

		{
			"lookup(var.foo, var.bar)",
			&FunctionInterpolation{
				Func: nil, // Funcs["lookup"]
				Args: []InterpolatedVariable{
					&UserVariable{
						Name: "foo",
						key:  "var.foo",
					},
					&UserVariable{
						Name: "bar",
						key:  "var.bar",
					},
				},
				key: "lookup(var.foo, var.bar)",
			},
			false,
		},
	}

	for i, tc := range cases {
		actual, err := NewInterpolation(tc.Input)
		if (err != nil) != tc.Error {
			t.Fatalf("%d. Error: %s", i, err)
		}

		// This is jank, but reflect.DeepEqual never has functions
		// being the same.
		if f, ok := actual.(*FunctionInterpolation); ok {
			f.Func = nil
		}

		if !reflect.DeepEqual(actual, tc.Result) {
			t.Fatalf("%d bad: %#v", i, actual)
		}
	}
}

func TestNewInterpolatedVariable(t *testing.T) {
	cases := []struct {
		Input  string
		Result InterpolatedVariable
		Error  bool
	}{
		{
			"var.foo",
			&UserVariable{
				Name: "foo",
				key:  "var.foo",
			},
			false,
		},
	}

	for i, tc := range cases {
		actual, err := NewInterpolatedVariable(tc.Input)
		if (err != nil) != tc.Error {
			t.Fatalf("%d. Error: %s", i, err)
		}
		if !reflect.DeepEqual(actual, tc.Result) {
			t.Fatalf("%d bad: %#v", i, actual)
		}
	}
}

func TestNewResourceVariable(t *testing.T) {
	v, err := NewResourceVariable("foo.bar.baz")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if v.Type != "foo" {
		t.Fatalf("bad: %#v", v)
	}
	if v.Name != "bar" {
		t.Fatalf("bad: %#v", v)
	}
	if v.Field != "baz" {
		t.Fatalf("bad: %#v", v)
	}
	if v.Multi {
		t.Fatal("should not be multi")
	}

	if v.FullKey() != "foo.bar.baz" {
		t.Fatalf("bad: %#v", v)
	}
}

func TestNewUserVariable(t *testing.T) {
	v, err := NewUserVariable("var.bar")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if v.Name != "bar" {
		t.Fatalf("bad: %#v", v.Name)
	}
	if v.FullKey() != "var.bar" {
		t.Fatalf("bad: %#v", v)
	}
}

func TestNewUserVariable_map(t *testing.T) {
	v, err := NewUserVariable("var.bar.baz")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if v.Name != "bar" {
		t.Fatalf("bad: %#v", v.Name)
	}
	if v.Elem != "baz" {
		t.Fatalf("bad: %#v", v.Elem)
	}
	if v.FullKey() != "var.bar.baz" {
		t.Fatalf("bad: %#v", v)
	}
}

func TestFunctionInterpolation_impl(t *testing.T) {
	var _ Interpolation = new(FunctionInterpolation)
}

func TestFunctionInterpolation(t *testing.T) {
	v1, err := NewInterpolatedVariable("var.foo")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	v2, err := NewInterpolatedVariable("var.bar")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	fn := func(vs map[string]string, args ...string) (string, error) {
		return strings.Join(args, " "), nil
	}

	i := &FunctionInterpolation{
		Func: fn,
		Args: []InterpolatedVariable{v1, v2},
		key:  "foo",
	}
	if i.FullString() != "foo" {
		t.Fatalf("err: %#v", i)
	}

	expected := map[string]InterpolatedVariable{
		"var.foo": v1,
		"var.bar": v2,
	}
	if !reflect.DeepEqual(i.Variables(), expected) {
		t.Fatalf("bad: %#v", i.Variables())
	}

	actual, err := i.Interpolate(map[string]string{
		"var.foo": "bar",
		"var.bar": "baz",
	})
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if actual != "bar baz" {
		t.Fatalf("bad: %#v", actual)
	}
}

func TestResourceVariable_impl(t *testing.T) {
	var _ InterpolatedVariable = new(ResourceVariable)
}

func TestResourceVariable_Multi(t *testing.T) {
	v, err := NewResourceVariable("foo.bar.*.baz")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if v.Type != "foo" {
		t.Fatalf("bad: %#v", v)
	}
	if v.Name != "bar" {
		t.Fatalf("bad: %#v", v)
	}
	if v.Field != "baz" {
		t.Fatalf("bad: %#v", v)
	}
	if !v.Multi {
		t.Fatal("should be multi")
	}
}

func TestResourceVariable_MultiIndex(t *testing.T) {
	cases := []struct {
		Input string
		Index int
		Field string
	}{
		{"foo.bar.*.baz", -1, "baz"},
		{"foo.bar.0.baz", 0, "baz"},
		{"foo.bar.5.baz", 5, "baz"},
	}

	for _, tc := range cases {
		v, err := NewResourceVariable(tc.Input)
		if err != nil {
			t.Fatalf("err: %s", err)
		}
		if !v.Multi {
			t.Fatalf("should be multi: %s", tc.Input)
		}
		if v.Index != tc.Index {
			t.Fatalf("bad: %d\n\n%s", v.Index, tc.Input)
		}
		if v.Field != tc.Field {
			t.Fatalf("bad: %s\n\n%s", v.Field, tc.Input)
		}
	}
}

func TestUserVariable_impl(t *testing.T) {
	var _ InterpolatedVariable = new(UserVariable)
}

func TestVariableInterpolation_impl(t *testing.T) {
	var _ Interpolation = new(VariableInterpolation)
}

func TestVariableInterpolation(t *testing.T) {
	uv, err := NewUserVariable("var.foo")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	i := &VariableInterpolation{Variable: uv, key: "var.foo"}
	if i.FullString() != "var.foo" {
		t.Fatalf("err: %#v", i)
	}

	expected := map[string]InterpolatedVariable{"var.foo": uv}
	if !reflect.DeepEqual(i.Variables(), expected) {
		t.Fatalf("bad: %#v", i.Variables())
	}

	actual, err := i.Interpolate(map[string]string{
		"var.foo": "bar",
	})
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if actual != "bar" {
		t.Fatalf("bad: %#v", actual)
	}
}

func TestVariableInterpolation_missing(t *testing.T) {
	uv, err := NewUserVariable("var.foo")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	i := &VariableInterpolation{Variable: uv, key: "var.foo"}
	_, err = i.Interpolate(map[string]string{
		"var.bar": "bar",
	})
	if err == nil {
		t.Fatal("should error")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"archive/tar"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"

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

func main() {
	endpoint := "unix:///var/run/docker.sock"
	client, _ := docker.NewClient(endpoint)
	if len(os.Args) < 2 {
		os.Exit(2)
	}
	historyList, err := client.ImageHistory(os.Args[1])
	if err != nil {
		fmt.Println("Error happens at client.ImageHistory")
		os.Exit(2)
	}
	// First CreatedBy newer to older
	var createdByHistoryList = []string{}
	// layer ID -> json
	var jsonMap = map[string]string{}
	var layerTarMap = map[string][]*tar.Header{}
	var first = false
	for _, history := range historyList {
		createdByHistoryList = append(createdByHistoryList, history.CreatedBy)
		image, err := client.InspectImage(history.ID)
		if err != nil || first {
			// continue to create CreatedBy list
			continue
		}
		if image != nil {
			var buf bytes.Buffer
			opts := docker.ExportImageOptions{Name: image.ID, OutputStream: &buf}
			err := client.ExportImage(opts)
			if err != nil {
				fmt.Println("Error happens at client.ExportImage")
				os.Exit(2)
			}
			r := bytes.NewReader(buf.Bytes())
			tr := tar.NewReader(r)
			var header *tar.Header
			for {
				header, err = tr.Next()
				if err == io.EOF {
					// end of image tar
					break
				}
				if err != nil {
					fmt.Println(err)
					fmt.Println("Error at tar extract")
					os.Exit(2)
				}

				buf2 := new(bytes.Buffer)
				if _, err = io.Copy(buf2, tr); err != nil {
					fmt.Println(err)
				}
				//
				var field = strings.Split(header.Name, "/")
				var layerID = field[0]
				// find json and layer.tar
				if strings.HasSuffix(header.Name, "/json") {
					var jsonstring = buf2.String()
					//var imagestring = ""

					if strings.Index(jsonstring, "\"Image\":\"\"") != -1 || !first {
						jsonMap[layerID] = jsonstring
					}
				} else if strings.HasSuffix(header.Name, "layer.tar") {

					r2 := bytes.NewReader(buf2.Bytes())
					layerTar := tar.NewReader(r2)
					for {
						layerTarHeader, e4 := layerTar.Next()
						if e4 == io.EOF {
							// end of layer.tar
							break
						}
						layerTarMap[layerID] = append(layerTarMap[layerID], layerTarHeader)
					}
				}
			}
		}
		first = true

	}
	// fmt.Println("---- createdBy")
	// for _, createdBy := range createdByHistoryList {
	// 	fmt.Println(createdBy)
	// }
	// construct parent map
	//fmt.Println("---- jsonMap")
	var relation = map[string]string{}
	//var key string
	var value string
	var noparentid string
	for _, value = range jsonMap {
		//fmt.Println(key + " -> " + value)
		//dec := json.NewDecoder(v)
		var f interface{}
		//dec.Decode(&d)
		json.Unmarshal([]byte(value), &f)
		//fmt.Printf("%+v\n", d)
		m := f.(map[string]interface{})
		var id = m["id"]
		var parent = m["parent"]
		if parent == nil {
			noparentid = id.(string)
		} else {
			var p = parent.(string)
			_, ok := relation[p]
			if !ok {
				relation[p] = id.(string)
			}
		}
	}

	// fmt.Println("---- tarinfo")
	// fmt.Println("Start from:" + noparentid)
	var currentid = noparentid

	for {
		//fmt.Println(currentid)
		// find next
		_, ok := relation[currentid]
		if !ok {
			break
		}
		currentid = relation[currentid]
	}
	//
	var fileHistoryListMap = map[string][]string{}
	var layerHistoryList = []string{}
	// fmt.Println("---- reconstruct")
	// fmt.Println("Start from:" + noparentid)
	currentid = noparentid
	for {
		//
		for _, layerTarHeader := range layerTarMap[currentid] {
			var filename = layerTarHeader.Name
			filename = strings.Replace(filename, ".wh.", "", -1)
			fileHistoryListMap[filename] = append(fileHistoryListMap[filename], currentid)
		}
		//
		layerHistoryList = append(layerHistoryList, currentid)
		_, ok := relation[currentid]
		if !ok {
			break
		}
		// fmt.Println(currentid + "->" + relation[currentid])
		currentid = relation[currentid]

	}
	//

	//
	// fmt.Println("---- layer")
	// reverse
	// SliceTricks · golang/go Wiki
	// https://github.com/golang/go/wiki/SliceTricks
	for i := len(layerHistoryList)/2 - 1; i >= 0; i-- {
		opp := len(layerHistoryList) - 1 - i
		layerHistoryList[i], layerHistoryList[opp] = layerHistoryList[opp], layerHistoryList[i]
	}
	// for _, layer := range layerHistoryList {
	// 	fmt.Println(layer)
	// }
	// fmt.Println("---- createdBy layer")
	// for _, createdBy := range createdByHistoryList {
	// 	fmt.Println(createdBy)
	// }
	//
	var layerIndex = 0
	fmt.Println("---- id and createdBy")
	for _, createdBy := range createdByHistoryList {
		if strings.Index(createdBy, "#(nop)") != -1 && strings.Index(createdBy, "ADD") == -1 && strings.Index(createdBy, "COPY") == -1 {
			fmt.Println("--------" + createdBy)
		} else {
			var layerID = layerHistoryList[layerIndex]
			fmt.Println(layerID + "  " + createdBy)

			for _, layerTarHeader := range layerTarMap[layerID] {
				var filename = layerTarHeader.Name
				var deleteflag = false
				if strings.Index(filename, ".wh.") != -1 {
					deleteflag = true
					filename = strings.Replace(filename, ".wh.", "", -1)
				}
				//
				var status = "A"

				// check add or changes
				var fileHistoryList = fileHistoryListMap[filename]
				var fileHistoryIndex = 0
				var fileSize int64
				fileSize = 0
				for _, fileHistoryID := range fileHistoryList {
					var lTH2Size int64
					lTH2Size = 0
					for _, lTH2 := range layerTarMap[fileHistoryID] {
						if lTH2.Name == layerTarHeader.Name || lTH2.Name == filename {
							lTH2Size = lTH2.Size
							break
						}
					}
					fileSize = lTH2Size - fileSize
					if fileHistoryID == layerID {
						if fileHistoryIndex == 0 {

						} else {
							status = "C"

						}
						break
					}
					fileHistoryIndex++
				}

				if deleteflag {
					status = "D"
				}
				// calc size

				fmt.Println(status + " " + filename + " " + strconv.FormatInt(fileSize, 10))
			}

			layerIndex++
		}
	}

}
<commit_msg>Add more information<commit_after>package main

import (
	"archive/tar"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"

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

func main() {
	endpoint := "unix:///var/run/docker.sock"
	client, _ := docker.NewClient(endpoint)
	if len(os.Args) < 2 {
		os.Exit(2)
	}
	historyList, err := client.ImageHistory(os.Args[1])
	if err != nil {
		fmt.Println("Error happens at client.ImageHistory")
		os.Exit(2)
	}
	// First CreatedBy newer to older
	var createdByHistoryList = []string{}
	// layer ID -> json
	var jsonMap = map[string]string{}
	var allJsonMap = map[string]string{}
	var layerTarMap = map[string][]*tar.Header{}
	var first = false
	for _, history := range historyList {
		createdByHistoryList = append(createdByHistoryList, history.CreatedBy)
		image, err := client.InspectImage(history.ID)
		if err != nil || first {
			// continue to create CreatedBy list
			continue
		}
		if image != nil {
			var buf bytes.Buffer
			opts := docker.ExportImageOptions{Name: image.ID, OutputStream: &buf}
			err := client.ExportImage(opts)
			if err != nil {
				fmt.Println("Error happens at client.ExportImage")
				os.Exit(2)
			}
			r := bytes.NewReader(buf.Bytes())
			tr := tar.NewReader(r)
			var header *tar.Header
			for {
				header, err = tr.Next()
				if err == io.EOF {
					// end of image tar
					break
				}
				if err != nil {
					fmt.Println(err)
					fmt.Println("Error at tar extract")
					os.Exit(2)
				}

				buf2 := new(bytes.Buffer)
				if _, err = io.Copy(buf2, tr); err != nil {
					fmt.Println(err)
				}
				//
				var field = strings.Split(header.Name, "/")
				var layerID = field[0]
				// find json and layer.tar
				if strings.HasSuffix(header.Name, "/json") {
					var jsonstring = buf2.String()
					//var imagestring = ""
					allJsonMap[layerID] = jsonstring
					if strings.Index(jsonstring, "\"Image\":\"\"") != -1 || !first {
						jsonMap[layerID] = jsonstring
					}
				} else if strings.HasSuffix(header.Name, "layer.tar") {

					r2 := bytes.NewReader(buf2.Bytes())
					layerTar := tar.NewReader(r2)
					for {
						layerTarHeader, e4 := layerTar.Next()
						if e4 == io.EOF {
							// end of layer.tar
							break
						}
						layerTarMap[layerID] = append(layerTarMap[layerID], layerTarHeader)
					}
				}
			}
		}
		first = true

	}
	// fmt.Println("---- createdBy")
	// for _, createdBy := range createdByHistoryList {
	// 	fmt.Println(createdBy)
	// }
	// construct parent map
	//fmt.Println("---- jsonMap")
	var relation = map[string]string{}
	//var key string
	var value string
	var noparentid string
	for _, value = range jsonMap {
		//fmt.Println(key + " -> " + value)
		//dec := json.NewDecoder(v)
		var f interface{}
		//dec.Decode(&d)
		json.Unmarshal([]byte(value), &f)
		//fmt.Printf("%+v\n", d)
		m := f.(map[string]interface{})
		var id = m["id"]
		var parent = m["parent"]
		if parent == nil {
			noparentid = id.(string)
		} else {
			var p = parent.(string)
			_, ok := relation[p]
			if !ok {
				relation[p] = id.(string)
			}
		}
	}

	// fmt.Println("---- tarinfo")
	// fmt.Println("Start from:" + noparentid)
	var currentid = noparentid

	for {
		//fmt.Println(currentid)
		// find next
		_, ok := relation[currentid]
		if !ok {
			break
		}
		currentid = relation[currentid]
	}
	//
	var fileHistoryListMap = map[string][]string{}
	var layerHistoryList = []string{}
	// fmt.Println("---- reconstruct")
	// fmt.Println("Start from:" + noparentid)
	currentid = noparentid
	for {
		//
		for _, layerTarHeader := range layerTarMap[currentid] {
			var filename = layerTarHeader.Name
			filename = strings.Replace(filename, ".wh.", "", -1)
			fileHistoryListMap[filename] = append(fileHistoryListMap[filename], currentid)
		}
		//
		layerHistoryList = append(layerHistoryList, currentid)
		_, ok := relation[currentid]
		if !ok {
			break
		}
		// fmt.Println(currentid + "->" + relation[currentid])
		currentid = relation[currentid]

	}
	//

	//
	// fmt.Println("---- layer")
	// reverse
	// SliceTricks · golang/go Wiki
	// https://github.com/golang/go/wiki/SliceTricks
	for i := len(layerHistoryList)/2 - 1; i >= 0; i-- {
		opp := len(layerHistoryList) - 1 - i
		layerHistoryList[i], layerHistoryList[opp] = layerHistoryList[opp], layerHistoryList[i]
	}
	// for _, layer := range layerHistoryList {
	// 	fmt.Println(layer)
	// }
	// fmt.Println("---- createdBy layer")
	// for _, createdBy := range createdByHistoryList {
	// 	fmt.Println(createdBy)
	// }
	var createdByListMap = map[string][]string{}
	var currentLayerID = ""
	var currentLayerIndex = 0
	for _, createdBy := range createdByHistoryList {
		if strings.Index(createdBy, "#(nop)") != -1 && strings.Index(createdBy, "ADD") == -1 && strings.Index(createdBy, "COPY") == -1 {
			//fmt.Println(strings.Repeat("-", 12) + " " + createdBy)
		} else {
			currentLayerID = layerHistoryList[currentLayerIndex]
			currentLayerIndex++
		}
		createdByListMap[currentLayerID] = append(createdByListMap[currentLayerID], createdBy)
	}
	//
	var layerIndex = 0

	for _, createdBy := range createdByHistoryList {
		if strings.Index(createdBy, "#(nop)") != -1 && strings.Index(createdBy, "ADD") == -1 && strings.Index(createdBy, "COPY") == -1 {
			//fmt.Println(strings.Repeat("-", 12) + " " + createdBy)
		} else {
			var layerID = layerHistoryList[layerIndex]
			for _, savedCreatedBy := range createdByListMap[layerID] {
				fmt.Println(layerID[:12] + "  " + savedCreatedBy)
			}
			//fmt.Println(allJsonMap[layerID])

			for _, layerTarHeader := range layerTarMap[layerID] {
				var filename = layerTarHeader.Name
				var deleteflag = false
				if strings.Index(filename, ".wh.") != -1 {
					deleteflag = true
					filename = strings.Replace(filename, ".wh.", "", -1)
				}
				//
				var status = "A"

				// check add or changes
				var fileHistoryList = fileHistoryListMap[filename]
				var fileHistoryIndex = 0
				var fileSize int64
				fileSize = 0
				for _, fileHistoryID := range fileHistoryList {
					var lTH2Size int64
					lTH2Size = 0
					for _, lTH2 := range layerTarMap[fileHistoryID] {
						if lTH2.Name == layerTarHeader.Name || lTH2.Name == filename {
							lTH2Size = lTH2.Size
							break
						}
					}
					fileSize = lTH2Size - fileSize
					if fileHistoryID == layerID {
						if fileHistoryIndex == 0 {

						} else {
							status = "C"

						}
						break
					}
					fileHistoryIndex++
				}

				if deleteflag {
					status = "D"
				}
				// calc size

				fmt.Println(status + " " + filename + " " + strconv.FormatInt(fileSize, 10) + " " + strconv.Itoa(layerTarHeader.Uid) + "(" + layerTarHeader.Uname + ")" + ":" + strconv.Itoa(layerTarHeader.Gid) + "(" + layerTarHeader.Gname + ")" + " " + strconv.FormatInt(layerTarHeader.Mode, 8))
			}

			layerIndex++
		}
	}

}
<|endoftext|>


<commit_before>package ui

import (
	"errors"
	"fmt"
	"math/rand"
	"os"
	"os/exec"
	"os/signal"
	"strings"
	"time"

	"github.com/fabiofalci/sconsify/events"
	sp "github.com/op/go-libspotify/spotify"
)

type NoUi struct {
	silent         *bool
	playlistFilter []string
	tracks         []*sp.Track
	events         *events.Events
}

func StartNoUserInterface(events *events.Events, silent *bool, playlistFilter *string, repeatOn *bool) error {
	noui := &NoUi{silent: silent, events: events}
	noui.setPlaylistFilter(*playlistFilter)

	playlists := noui.waitForPlaylists()
	if playlists == nil {
		return nil
	}

	go noui.listenForKeyboardEvents()

	noui.listenForTermination()

	err := noui.randomTracks(playlists)
	if err != nil {
		return err
	}

	if !*silent {
		noui.printPlaylistInfo()
	}

	nextToPlayIndex := 0
	numberOfTracks := len(noui.tracks)

	for {
		track := noui.tracks[nextToPlayIndex]

		events.ToPlay <- track

		if *silent {
			<-events.WaitForStatus()
		} else {
			fmt.Println(<-events.WaitForStatus())
		}
		<-events.NextPlay

		nextToPlayIndex++
		if nextToPlayIndex >= numberOfTracks {
			if *repeatOn {
				nextToPlayIndex = 0
			} else {
				return nil
			}
		}
	}

	return nil
}

func (noui *NoUi) waitForPlaylists() map[string]*sp.Playlist {
	select {
	case playlists := <-noui.events.WaitForPlaylists():
		if playlists != nil {
			return playlists
		}
	case <-noui.events.WaitForShutdown():
	}
	return nil
}

func (noui *NoUi) printPlaylistInfo() {
	fmt.Printf("%v track(s) from ", len(noui.tracks))
	if noui.playlistFilter == nil {
		fmt.Printf("all playlist(s)\n")
	} else {
		fmt.Printf("%v playlist(s)\n", len(noui.playlistFilter))
	}
}

func (noui *NoUi) listenForTermination() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		for _ = range c {
			noui.shutdownNogui()
		}
	}()
}

func (noui *NoUi) shutdownNogui() {
	noui.events.Shutdown()
	<-noui.events.WaitForShutdown()
	os.Exit(0)
}

func (noui *NoUi) listenForKeyboardEvents() {
	exec.Command("stty", "-F", "/dev/tty", "cbreak", "min", "1").Run()

	// we could disable echo but I can't enable it back

	// do not display entered characters on the screen
	// exec.Command("stty", "-F", "/dev/tty", "-echo").Run()
	// defer exec.Command("stty", "-F", "/dev/tty", "echo")

	var b []byte = make([]byte, 1)
	for {
		os.Stdin.Read(b)

		key := string(b)
		if key == ">" {
			fmt.Println("")
			noui.events.NextPlay <- true
		}
	}
}

func (noui *NoUi) randomTracks(playlists map[string]*sp.Playlist) error {
	numberOfTracks := 0
	for _, playlist := range playlists {
		playlist.Wait()
		if noui.isOnFilter(playlist.Name()) {
			numberOfTracks += playlist.Tracks()
		}
	}

	if numberOfTracks == 0 {
		return errors.New("No tracks selected")
	}

	noui.tracks = make([]*sp.Track, numberOfTracks)
	perm := getRandomPermutation(numberOfTracks)
	permIndex := 0

	for _, playlist := range playlists {
		playlist.Wait()
		if noui.isOnFilter(playlist.Name()) {
			for i := 0; i < playlist.Tracks(); i++ {
				track := playlist.Track(i).Track()
				track.Wait()

				noui.tracks[perm[permIndex]] = track
				permIndex++
			}
		}
	}

	return nil
}

func (noui *NoUi) setPlaylistFilter(playlistFilter string) {
	if playlistFilter == "" {
		return
	}
	noui.playlistFilter = strings.Split(playlistFilter, ",")
	for i := range noui.playlistFilter {
		noui.playlistFilter[i] = strings.Trim(noui.playlistFilter[i], " ")
	}
}

func (noui *NoUi) isOnFilter(playlist string) bool {
	if noui.playlistFilter == nil {
		return true
	}
	for _, filter := range noui.playlistFilter {
		if filter == playlist {
			return true
		}
	}
	return false
}

func getRandomPermutation(numberOfTracks int) []int {
	rand.Seed(time.Now().Unix())
	return rand.Perm(numberOfTracks)
}
<commit_msg>Press q to quit noui<commit_after>package ui

import (
	"errors"
	"fmt"
	"math/rand"
	"os"
	"os/exec"
	"os/signal"
	"strings"
	"time"

	"github.com/fabiofalci/sconsify/events"
	sp "github.com/op/go-libspotify/spotify"
)

type NoUi struct {
	silent         *bool
	playlistFilter []string
	tracks         []*sp.Track
	events         *events.Events
}

func StartNoUserInterface(events *events.Events, silent *bool, playlistFilter *string, repeatOn *bool) error {
	noui := &NoUi{silent: silent, events: events}
	noui.setPlaylistFilter(*playlistFilter)

	playlists := noui.waitForPlaylists()
	if playlists == nil {
		return nil
	}

	go noui.listenForKeyboardEvents()

	noui.listenForTermination()

	err := noui.randomTracks(playlists)
	if err != nil {
		return err
	}

	if !*silent {
		noui.printPlaylistInfo()
	}

	nextToPlayIndex := 0
	numberOfTracks := len(noui.tracks)

	for {
		track := noui.tracks[nextToPlayIndex]

		events.ToPlay <- track

		if *silent {
			<-events.WaitForStatus()
		} else {
			fmt.Println(<-events.WaitForStatus())
		}
		<-events.NextPlay

		nextToPlayIndex++
		if nextToPlayIndex >= numberOfTracks {
			if *repeatOn {
				nextToPlayIndex = 0
			} else {
				return nil
			}
		}
	}

	return nil
}

func (noui *NoUi) waitForPlaylists() map[string]*sp.Playlist {
	select {
	case playlists := <-noui.events.WaitForPlaylists():
		if playlists != nil {
			return playlists
		}
	case <-noui.events.WaitForShutdown():
	}
	return nil
}

func (noui *NoUi) printPlaylistInfo() {
	fmt.Printf("%v track(s) from ", len(noui.tracks))
	if noui.playlistFilter == nil {
		fmt.Printf("all playlist(s)\n")
	} else {
		fmt.Printf("%v playlist(s)\n", len(noui.playlistFilter))
	}
}

func (noui *NoUi) listenForTermination() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		for _ = range c {
			noui.shutdownNogui()
		}
	}()
}

func (noui *NoUi) shutdownNogui() {
	noui.events.Shutdown()
	<-noui.events.WaitForShutdown()
	os.Exit(0)
}

func (noui *NoUi) listenForKeyboardEvents() {
	exec.Command("stty", "-F", "/dev/tty", "cbreak", "min", "1").Run()

	// we could disable echo but I can't enable it back

	// do not display entered characters on the screen
	// exec.Command("stty", "-F", "/dev/tty", "-echo").Run()
	// defer exec.Command("stty", "-F", "/dev/tty", "echo")

	var b []byte = make([]byte, 1)
	for {
		os.Stdin.Read(b)

		key := string(b)
		if key == ">" {
			fmt.Println("")
			noui.events.NextPlay <- true
		} else if key == "q" {
			noui.shutdownNogui()
		}
	}
}

func (noui *NoUi) randomTracks(playlists map[string]*sp.Playlist) error {
	numberOfTracks := 0
	for _, playlist := range playlists {
		playlist.Wait()
		if noui.isOnFilter(playlist.Name()) {
			numberOfTracks += playlist.Tracks()
		}
	}

	if numberOfTracks == 0 {
		return errors.New("No tracks selected")
	}

	noui.tracks = make([]*sp.Track, numberOfTracks)
	perm := getRandomPermutation(numberOfTracks)
	permIndex := 0

	for _, playlist := range playlists {
		playlist.Wait()
		if noui.isOnFilter(playlist.Name()) {
			for i := 0; i < playlist.Tracks(); i++ {
				track := playlist.Track(i).Track()
				track.Wait()

				noui.tracks[perm[permIndex]] = track
				permIndex++
			}
		}
	}

	return nil
}

func (noui *NoUi) setPlaylistFilter(playlistFilter string) {
	if playlistFilter == "" {
		return
	}
	noui.playlistFilter = strings.Split(playlistFilter, ",")
	for i := range noui.playlistFilter {
		noui.playlistFilter[i] = strings.Trim(noui.playlistFilter[i], " ")
	}
}

func (noui *NoUi) isOnFilter(playlist string) bool {
	if noui.playlistFilter == nil {
		return true
	}
	for _, filter := range noui.playlistFilter {
		if filter == playlist {
			return true
		}
	}
	return false
}

func getRandomPermutation(numberOfTracks int) []int {
	rand.Seed(time.Now().Unix())
	return rand.Perm(numberOfTracks)
}
<|endoftext|>


<commit_before>package romulus

import (
	"bytes"
	"encoding/json"
	"fmt"
	"strings"
	"time"
)

var (
	bcknds       = "backends"
	frntnds      = "frontends"
	bckndDirFmt  = "backends/%s"
	frntndDirFmt = "frontends/%s"
	bckndFmt     = "backends/%s/backend"
	srvrDirFmt   = "backends/%s/servers"
	srvrFmt      = "backends/%s/servers/%s"
	frntndFmt    = "frontends/%s/frontend"

	annotationFmt = "romulus/%s%s"
	rteConv       = map[string]string{
		"host":         "Host(`%s`)",
		"method":       "Method(`%s`)",
		"path":         "Path(`%s`)",
		"header":       "Header(`%s`)",
		"hostRegexp":   "HostRegexp(`%s`)",
		"methodRegexp": "MethodRegexp(`%s`)",
		"pathRegexp":   "PathRegexp(`%s`)",
		"headerRegexp": "HeaderRegexp(`%s`)",
	}
)

// VulcanObject represents a vulcand component
type VulcanObject interface {
	// Key returns the etcd key for this object
	Key() string
	// Val returns the (JSON-ified) value to store in etcd
	Val() (string, error)
}

type BackendList map[int]*Backend

// Backend is a vulcand backend
type Backend struct {
	ID       string `json:"Id"`
	Type     string
	Settings *BackendSettings `json:",omitempty"`
}

// BackendSettings is vulcand backend settings
type BackendSettings struct {
	Timeouts  *BackendSettingsTimeouts  `json:",omitempty"`
	KeepAlive *BackendSettingsKeepAlive `json:",omitempty"`
}

// BackendSettingsTimeouts is vulcand settings for backend timeouts
type BackendSettingsTimeouts struct {
	Read         time.Duration `json:",omitempty"`
	Dial         time.Duration `json:",omitempty"`
	TLSHandshake time.Duration `json:",omitempty"`
}

// BackendSettingsKeepAlive is vulcand settings for backend keep alive
type BackendSettingsKeepAlive struct {
	Period              time.Duration `json:",omitempty"`
	MaxIdleConnsPerHost int           `json:",omitempty"`
}

// ServerMap is a map of IPs (string) -> Server
type ServerMap map[string]Server

// Server is a vulcand server
type Server struct {
	URL     *URL   `json:"URL"`
	Backend string `json:"-"`
}

// Frontend is a vulcand frontend
type Frontend struct {
	ID        string `json:"Id"`
	Type      string
	BackendID string `json:"BackendId"`
	Route     string
	Settings  *FrontendSettings `json:",omitempty"`
}

// FrontendSettings is vulcand frontend settings
type FrontendSettings struct {
	FailoverPredicate  string                  `json:",omitempty"`
	Hostname           string                  `json:",omitempty"`
	TrustForwardHeader bool                    `json:",omitempty"`
	Limits             *FrontendSettingsLimits `json:",omitempty"`
}

// FrontendSettingsLimits is vulcand settings for frontend limits
type FrontendSettingsLimits struct {
	MaxMemBodyBytes int
	MaxBodyBytes    int
}

// NewBackend returns a ref to a Backend object
func NewBackend(id string) *Backend {
	return &Backend{
		ID: id,
	}
}

// NewFrontend returns a ref to a Frontend object
func NewFrontend(id, bid string) *Frontend {
	return &Frontend{
		ID:        id,
		BackendID: bid,
	}
}

// NewBackendSettings returns BackendSettings from raw JSON
func NewBackendSettings(p []byte) *BackendSettings {
	var ba BackendSettings
	b := bytes.NewBuffer(p)
	json.NewDecoder(b).Decode(&ba)
	return &ba
}

// NewFrontendSettings returns FrontendSettings from raw JSON
func NewFrontendSettings(p []byte) *FrontendSettings {
	var f FrontendSettings
	b := bytes.NewBuffer(p)
	json.NewDecoder(b).Decode(&f)
	return &f
}

func (b Backend) Key() string { return fmt.Sprintf(bckndFmt, b.ID) }
func (s Server) Key() string {
	return fmt.Sprintf(srvrFmt, s.Backend, s.URL.GetHost())
}
func (f Frontend) Key() string         { return fmt.Sprintf(frntndFmt, f.ID) }
func (f FrontendSettings) Key() string { return "" }
func (b BackendSettings) Key() string  { return "" }

func (b Backend) Val() (string, error)          { return encode(b) }
func (s Server) Val() (string, error)           { return encode(s) }
func (f Frontend) Val() (string, error)         { return encode(f) }
func (f FrontendSettings) Val() (string, error) { return "", nil }
func (b BackendSettings) Val() (string, error)  { return "", nil }

// DirKey returns the etcd directory key for this Backend
func (b Backend) DirKey() string { return fmt.Sprintf(bckndDirFmt, b.ID) }

// DirKey returns the etcd directory key for this Frontend
func (f Frontend) DirKey() string { return fmt.Sprintf(frntndDirFmt, f.ID) }

func (f *FrontendSettings) String() string {
	s, e := encode(f)
	if e != nil {
		return e.Error()
	}
	return s
}

func (b *BackendSettings) String() string {
	s, e := encode(b)
	if e != nil {
		return e.Error()
	}
	return s
}

// IPs returns the ServerMap IPs
func (s ServerMap) IPs() []string {
	st := []string{}
	for ip := range s {
		st = append(st, ip)
	}
	return st
}

func encode(v VulcanObject) (string, error) {
	b := new(bytes.Buffer)
	e := json.NewEncoder(b).Encode(v)
	return strings.TrimSpace(HTMLUnescape(b.String())), e
}

func buildRoute(ns string, a map[string]string) string {
	rt := []string{}
	if ns != "" {
		ns = fmt.Sprintf(".%s", ns)
	}
	for k, f := range rteConv {
		pk := fmt.Sprintf(annotationFmt, k, ns)
		if v, ok := a[pk]; ok {
			if k == "method" {
				v = strings.ToUpper(v)
			}
			rt = append(rt, fmt.Sprintf(f, v))
		}
	}
	if len(rt) < 1 {
		rt = []string{"Path('/')"}
	}
	return strings.Join(rt, " && ")
}
<commit_msg>Adding backend TLS options<commit_after>package romulus

import (
	"bytes"
	"encoding/json"
	"fmt"
	"strings"
	"time"
)

var (
	bcknds       = "backends"
	frntnds      = "frontends"
	bckndDirFmt  = "backends/%s"
	frntndDirFmt = "frontends/%s"
	bckndFmt     = "backends/%s/backend"
	srvrDirFmt   = "backends/%s/servers"
	srvrFmt      = "backends/%s/servers/%s"
	frntndFmt    = "frontends/%s/frontend"

	annotationFmt = "romulus/%s%s"
	rteConv       = map[string]string{
		"host":         "Host(`%s`)",
		"method":       "Method(`%s`)",
		"path":         "Path(`%s`)",
		"header":       "Header(`%s`)",
		"hostRegexp":   "HostRegexp(`%s`)",
		"methodRegexp": "MethodRegexp(`%s`)",
		"pathRegexp":   "PathRegexp(`%s`)",
		"headerRegexp": "HeaderRegexp(`%s`)",
	}
)

// VulcanObject represents a vulcand component
type VulcanObject interface {
	// Key returns the etcd key for this object
	Key() string
	// Val returns the (JSON-ified) value to store in etcd
	Val() (string, error)
}

type BackendList map[int]*Backend

// Backend is a vulcand backend
type Backend struct {
	ID       string `json:"Id,omitempty"`
	Type     string
	Settings *BackendSettings `json:",omitempty"`
}

// BackendSettings is vulcand backend settings
type BackendSettings struct {
	Timeouts  *BackendSettingsTimeouts  `json:",omitempty"`
	KeepAlive *BackendSettingsKeepAlive `json:",omitempty"`
	TLS       *TLSSettings              `json:",omitempty"`
}

// BackendSettingsTimeouts is vulcand settings for backend timeouts
type BackendSettingsTimeouts struct {
	Read         time.Duration `json:",omitempty"`
	Dial         time.Duration `json:",omitempty"`
	TLSHandshake time.Duration `json:",omitempty"`
}

// BackendSettingsKeepAlive is vulcand settings for backend keep alive
type BackendSettingsKeepAlive struct {
	Period              time.Duration `json:",omitempty"`
	MaxIdleConnsPerHost int           `json:",omitempty"`
}

type TLSSettings struct {
	PreferServerCipherSuites bool          `json:",omitempty"`
	InsecureSkipVerify       bool          `json:",omitempty"`
	SessionTicketsDisabled   bool          `json:",omitempty"`
	SessionCache             *SessionCache `json:",omitempty"`
	CipherSuites             []string      `json:",omitempty"`
	MinVersion               string        `json:",omitempty"`
	MaxVersion               string        `json:",omitempty"`
}

type SessionCache struct {
	Type     string
	Settings *SessionCacheSettings
}

type SessionCacheSettings struct {
	Capacity int
}

// ServerMap is a map of IPs (string) -> Server
type ServerMap map[string]Server

// Server is a vulcand server
type Server struct {
	URL     *URL   `json:"URL"`
	Backend string `json:"-"`
}

// Frontend is a vulcand frontend
type Frontend struct {
	ID        string `json:"Id,omitempty"`
	Type      string
	BackendID string `json:"BackendId"`
	Route     string
	Settings  *FrontendSettings `json:",omitempty"`
}

// FrontendSettings is vulcand frontend settings
type FrontendSettings struct {
	FailoverPredicate  string                  `json:",omitempty"`
	Hostname           string                  `json:",omitempty"`
	TrustForwardHeader bool                    `json:",omitempty"`
	Limits             *FrontendSettingsLimits `json:",omitempty"`
}

// FrontendSettingsLimits is vulcand settings for frontend limits
type FrontendSettingsLimits struct {
	MaxMemBodyBytes int
	MaxBodyBytes    int
}

// NewBackend returns a ref to a Backend object
func NewBackend(id string) *Backend {
	return &Backend{
		ID: id,
	}
}

// NewFrontend returns a ref to a Frontend object
func NewFrontend(id, bid string) *Frontend {
	return &Frontend{
		ID:        id,
		BackendID: bid,
	}
}

// NewBackendSettings returns BackendSettings from raw JSON
func NewBackendSettings(p []byte) *BackendSettings {
	var ba BackendSettings
	b := bytes.NewBuffer(p)
	json.NewDecoder(b).Decode(&ba)
	return &ba
}

// NewFrontendSettings returns FrontendSettings from raw JSON
func NewFrontendSettings(p []byte) *FrontendSettings {
	var f FrontendSettings
	b := bytes.NewBuffer(p)
	json.NewDecoder(b).Decode(&f)
	return &f
}

func (b Backend) Key() string { return fmt.Sprintf(bckndFmt, b.ID) }
func (s Server) Key() string {
	return fmt.Sprintf(srvrFmt, s.Backend, s.URL.GetHost())
}
func (f Frontend) Key() string         { return fmt.Sprintf(frntndFmt, f.ID) }
func (f FrontendSettings) Key() string { return "" }
func (b BackendSettings) Key() string  { return "" }

func (b Backend) Val() (string, error)          { return encode(b) }
func (s Server) Val() (string, error)           { return encode(s) }
func (f Frontend) Val() (string, error)         { return encode(f) }
func (f FrontendSettings) Val() (string, error) { return "", nil }
func (b BackendSettings) Val() (string, error)  { return "", nil }

// DirKey returns the etcd directory key for this Backend
func (b Backend) DirKey() string { return fmt.Sprintf(bckndDirFmt, b.ID) }

// DirKey returns the etcd directory key for this Frontend
func (f Frontend) DirKey() string { return fmt.Sprintf(frntndDirFmt, f.ID) }

func (f *FrontendSettings) String() string {
	s, e := encode(f)
	if e != nil {
		return e.Error()
	}
	return s
}

func (b *BackendSettings) String() string {
	s, e := encode(b)
	if e != nil {
		return e.Error()
	}
	return s
}

// IPs returns the ServerMap IPs
func (s ServerMap) IPs() []string {
	st := []string{}
	for ip := range s {
		st = append(st, ip)
	}
	return st
}

func encode(v VulcanObject) (string, error) {
	b := new(bytes.Buffer)
	e := json.NewEncoder(b).Encode(v)
	return strings.TrimSpace(HTMLUnescape(b.String())), e
}

func buildRoute(ns string, a map[string]string) string {
	rt := []string{}
	if ns != "" {
		ns = fmt.Sprintf(".%s", ns)
	}
	for k, f := range rteConv {
		pk := fmt.Sprintf(annotationFmt, k, ns)
		if v, ok := a[pk]; ok {
			if k == "method" {
				v = strings.ToUpper(v)
			}
			rt = append(rt, fmt.Sprintf(f, v))
		}
	}
	if len(rt) < 1 {
		rt = []string{"Path('/')"}
	}
	return strings.Join(rt, " && ")
}
<|endoftext|>