<commit_before>package main

import (
	_ "embed"
	"fmt"
	"io"
	"sort"
	"strings"

	"github.com/influxdata/telegraf"
	"github.com/influxdata/telegraf/plugins/aggregators"
	"github.com/influxdata/telegraf/plugins/inputs"
	"github.com/influxdata/telegraf/plugins/outputs"
	"github.com/influxdata/telegraf/plugins/processors"
)

var (
	// Default sections
	sectionDefaults = []string{"global_tags", "agent", "outputs",
		"processors", "aggregators", "inputs"}

	// Default input plugins
	inputDefaults = []string{"cpu", "mem", "swap", "system", "kernel",
		"processes", "disk", "diskio"}

	// Default output plugins
	outputDefaults = []string{"influxdb"}
)

var header = `# Telegraf Configuration
#
# Telegraf is entirely plugin driven. All metrics are gathered from the
# declared inputs, and sent to the declared outputs.
#
# Plugins must be declared in here to be active.
# To deactivate a plugin, comment out the name and any variables.
#
# Use 'telegraf -config telegraf.conf -test' to see what metrics a config
# file would generate.
#
# Environment variables can be used anywhere in this config file, simply surround
# them with ${}. For strings the variable must be within quotes (ie, "${STR_VAR}"),
# for numbers and booleans they should be plain (ie, ${INT_VAR}, ${BOOL_VAR})

`
var globalTagsConfig = `
# Global tags can be specified here in key="value" format.
[global_tags]
  # dc = "us-east-1" # will tag all metrics with dc=us-east-1
  # rack = "1a"
  ## Environment variables can be used as tags, and throughout the config file
  # user = "$USER"

`

// DO NOT REMOVE THE NEXT TWO LINES! This is required to embed the agentConfig data.
//
//go:embed agent.conf
var agentConfig string

var outputHeader = `
###############################################################################
#                            OUTPUT PLUGINS                                   #
###############################################################################

`

var processorHeader = `
###############################################################################
#                            PROCESSOR PLUGINS                                #
###############################################################################

`

var aggregatorHeader = `
###############################################################################
#                            AGGREGATOR PLUGINS                               #
###############################################################################

`

var inputHeader = `
###############################################################################
#                            INPUT PLUGINS                                    #
###############################################################################

`

var serviceInputHeader = `
###############################################################################
#                            SERVICE INPUT PLUGINS                            #
###############################################################################

`

func sliceContains(name string, list []string) bool {
	for _, b := range list {
		if b == name {
			return true
		}
	}
	return false
}

// printSampleConfig prints the sample config
func printSampleConfig(
	outputBuffer io.Writer,
	sectionFilters []string,
	inputFilters []string,
	outputFilters []string,
	aggregatorFilters []string,
	processorFilters []string,
) {
	// print headers
	outputBuffer.Write([]byte(header))

	if len(sectionFilters) == 0 {
		sectionFilters = sectionDefaults
	}
	printFilteredGlobalSections(sectionFilters, outputBuffer)

	// print output plugins
	if sliceContains("outputs", sectionFilters) {
		if len(outputFilters) != 0 {
			if len(outputFilters) >= 3 && outputFilters[1] != "none" {
				outputBuffer.Write([]byte(outputHeader))
			}
			printFilteredOutputs(outputFilters, false, outputBuffer)
		} else {
			outputBuffer.Write([]byte(outputHeader))
			printFilteredOutputs(outputDefaults, false, outputBuffer)
			// Print non-default outputs, commented
			var pnames []string
			for pname := range outputs.Outputs {
				if !sliceContains(pname, outputDefaults) {
					pnames = append(pnames, pname)
				}
			}
			printFilteredOutputs(pnames, true, outputBuffer)
		}
	}

	// print processor plugins
	if sliceContains("processors", sectionFilters) {
		if len(processorFilters) != 0 {
			if len(processorFilters) >= 3 && processorFilters[1] != "none" {
				outputBuffer.Write([]byte(processorHeader))
			}
			printFilteredProcessors(processorFilters, false, outputBuffer)
		} else {
			outputBuffer.Write([]byte(processorHeader))
			pnames := []string{}
			for pname := range processors.Processors {
				pnames = append(pnames, pname)
			}
			printFilteredProcessors(pnames, true, outputBuffer)
		}
	}

	// print aggregator plugins
	if sliceContains("aggregators", sectionFilters) {
		if len(aggregatorFilters) != 0 {
			if len(aggregatorFilters) >= 3 && aggregatorFilters[1] != "none" {
				outputBuffer.Write([]byte(aggregatorHeader))
			}
			printFilteredAggregators(aggregatorFilters, false, outputBuffer)
		} else {
			outputBuffer.Write([]byte(aggregatorHeader))
			pnames := []string{}
			for pname := range aggregators.Aggregators {
				pnames = append(pnames, pname)
			}
			printFilteredAggregators(pnames, true, outputBuffer)
		}
	}

	// print input plugins
	if sliceContains("inputs", sectionFilters) {
		if len(inputFilters) != 0 {
			if len(inputFilters) >= 3 && inputFilters[1] != "none" {
				outputBuffer.Write([]byte(inputHeader))
			}
			printFilteredInputs(inputFilters, false, outputBuffer)
		} else {
			outputBuffer.Write([]byte(inputHeader))
			printFilteredInputs(inputDefaults, false, outputBuffer)
			// Print non-default inputs, commented
			var pnames []string
			for pname := range inputs.Inputs {
				if !sliceContains(pname, inputDefaults) {
					pnames = append(pnames, pname)
				}
			}
			printFilteredInputs(pnames, true, outputBuffer)
		}
	}
}

func printFilteredProcessors(processorFilters []string, commented bool, outputBuffer io.Writer) {
	// Filter processors
	var pnames []string
	for pname := range processors.Processors {
		if sliceContains(pname, processorFilters) {
			pnames = append(pnames, pname)
		}
	}
	sort.Strings(pnames)

	// Print Outputs
	for _, pname := range pnames {
		creator := processors.Processors[pname]
		output := creator()
		printConfig(pname, output, "processors", commented, processors.Deprecations[pname], outputBuffer)
	}
}

func printFilteredAggregators(aggregatorFilters []string, commented bool, outputBuffer io.Writer) {
	// Filter outputs
	var anames []string
	for aname := range aggregators.Aggregators {
		if sliceContains(aname, aggregatorFilters) {
			anames = append(anames, aname)
		}
	}
	sort.Strings(anames)

	// Print Outputs
	for _, aname := range anames {
		creator := aggregators.Aggregators[aname]
		output := creator()
		printConfig(aname, output, "aggregators", commented, aggregators.Deprecations[aname], outputBuffer)
	}
}

func printFilteredInputs(inputFilters []string, commented bool, outputBuffer io.Writer) {
	// Filter inputs
	var pnames []string
	for pname := range inputs.Inputs {
		if sliceContains(pname, inputFilters) {
			pnames = append(pnames, pname)
		}
	}
	sort.Strings(pnames)

	// cache service inputs to print them at the end
	servInputs := make(map[string]telegraf.ServiceInput)
	// for alphabetical looping:
	servInputNames := []string{}

	// Print Inputs
	for _, pname := range pnames {
		// Skip inputs that are registered twice for backward compatibility
		switch pname {
		case "cisco_telemetry_gnmi", "io", "KNXListener":
			continue
		}
		creator := inputs.Inputs[pname]
		input := creator()

		if p, ok := input.(telegraf.ServiceInput); ok {
			servInputs[pname] = p
			servInputNames = append(servInputNames, pname)
			continue
		}

		printConfig(pname, input, "inputs", commented, inputs.Deprecations[pname], outputBuffer)
	}

	// Print Service Inputs
	if len(servInputs) == 0 {
		return
	}
	sort.Strings(servInputNames)

	outputBuffer.Write([]byte(serviceInputHeader))
	for _, name := range servInputNames {
		printConfig(name, servInputs[name], "inputs", commented, inputs.Deprecations[name], outputBuffer)
	}
}

func printFilteredOutputs(outputFilters []string, commented bool, outputBuffer io.Writer) {
	// Filter outputs
	var onames []string
	for oname := range outputs.Outputs {
		if sliceContains(oname, outputFilters) {
			onames = append(onames, oname)
		}
	}
	sort.Strings(onames)

	// Print Outputs
	for _, oname := range onames {
		creator := outputs.Outputs[oname]
		output := creator()
		printConfig(oname, output, "outputs", commented, outputs.Deprecations[oname], outputBuffer)
	}
}

func printFilteredGlobalSections(sectionFilters []string, outputBuffer io.Writer) {
	if sliceContains("global_tags", sectionFilters) {
		outputBuffer.Write([]byte(globalTagsConfig))
	}

	if sliceContains("agent", sectionFilters) {
		outputBuffer.Write([]byte(agentConfig))
	}
}

func printConfig(name string, p telegraf.PluginDescriber, op string, commented bool, di telegraf.DeprecationInfo, outputBuffer io.Writer) {
	comment := ""
	if commented {
		comment = "# "
	}

	if di.Since != "" {
		removalNote := ""
		if di.RemovalIn != "" {
			removalNote = " and will be removed in " + di.RemovalIn
		}
		outputBuffer.Write([]byte(fmt.Sprintf("\n%s ## DEPRECATED: The '%s' plugin is deprecated in version %s%s, %s.", comment, name, di.Since, removalNote, di.Notice)))
	}

	sample := p.SampleConfig()
	if sample == "" {
		outputBuffer.Write([]byte(fmt.Sprintf("\n#[[%s.%s]]", op, name)))
		outputBuffer.Write([]byte(fmt.Sprintf("\n%s  # no configuration\n\n", comment)))
	} else {
		lines := strings.Split(sample, "\n")
		outputBuffer.Write([]byte("\n"))
		for i, line := range lines {
			if i == len(lines)-1 {
				outputBuffer.Write([]byte("\n"))
				continue
			}
			outputBuffer.Write([]byte(strings.TrimRight(comment+line, " ") + "\n"))
		}
	}
}

// PrintInputConfig prints the config usage of a single input.
func PrintInputConfig(name string, outputBuffer io.Writer) error {
	creator, ok := inputs.Inputs[name]
	if !ok {
		return fmt.Errorf("input %s not found", name)
	}

	printConfig(name, creator(), "inputs", false, inputs.Deprecations[name], outputBuffer)
	return nil
}

// PrintOutputConfig prints the config usage of a single output.
func PrintOutputConfig(name string, outputBuffer io.Writer) error {
	creator, ok := outputs.Outputs[name]
	if !ok {
		return fmt.Errorf("output %s not found", name)
	}

	printConfig(name, creator(), "outputs", false, outputs.Deprecations[name], outputBuffer)
	return nil
}
<commit_msg>feat!: Disable [[outputs.influxdb]] in sample config (#12158)<commit_after>package main

import (
	_ "embed"
	"fmt"
	"io"
	"sort"
	"strings"

	"github.com/influxdata/telegraf"
	"github.com/influxdata/telegraf/plugins/aggregators"
	"github.com/influxdata/telegraf/plugins/inputs"
	"github.com/influxdata/telegraf/plugins/outputs"
	"github.com/influxdata/telegraf/plugins/processors"
)

var (
	// Default sections
	sectionDefaults = []string{"global_tags", "agent", "outputs",
		"processors", "aggregators", "inputs"}

	// Default input plugins
	inputDefaults = []string{"cpu", "mem", "swap", "system", "kernel",
		"processes", "disk", "diskio"}

	// Default output plugins
	outputDefaults = []string{}
)

var header = `# Telegraf Configuration
#
# Telegraf is entirely plugin driven. All metrics are gathered from the
# declared inputs, and sent to the declared outputs.
#
# Plugins must be declared in here to be active.
# To deactivate a plugin, comment out the name and any variables.
#
# Use 'telegraf -config telegraf.conf -test' to see what metrics a config
# file would generate.
#
# Environment variables can be used anywhere in this config file, simply surround
# them with ${}. For strings the variable must be within quotes (ie, "${STR_VAR}"),
# for numbers and booleans they should be plain (ie, ${INT_VAR}, ${BOOL_VAR})

`
var globalTagsConfig = `
# Global tags can be specified here in key="value" format.
[global_tags]
  # dc = "us-east-1" # will tag all metrics with dc=us-east-1
  # rack = "1a"
  ## Environment variables can be used as tags, and throughout the config file
  # user = "$USER"

`

// DO NOT REMOVE THE NEXT TWO LINES! This is required to embed the agentConfig data.
//
//go:embed agent.conf
var agentConfig string

var outputHeader = `
###############################################################################
#                            OUTPUT PLUGINS                                   #
###############################################################################

`

var processorHeader = `
###############################################################################
#                            PROCESSOR PLUGINS                                #
###############################################################################

`

var aggregatorHeader = `
###############################################################################
#                            AGGREGATOR PLUGINS                               #
###############################################################################

`

var inputHeader = `
###############################################################################
#                            INPUT PLUGINS                                    #
###############################################################################

`

var serviceInputHeader = `
###############################################################################
#                            SERVICE INPUT PLUGINS                            #
###############################################################################

`

func sliceContains(name string, list []string) bool {
	for _, b := range list {
		if b == name {
			return true
		}
	}
	return false
}

// printSampleConfig prints the sample config
func printSampleConfig(
	outputBuffer io.Writer,
	sectionFilters []string,
	inputFilters []string,
	outputFilters []string,
	aggregatorFilters []string,
	processorFilters []string,
) {
	// print headers
	outputBuffer.Write([]byte(header))

	if len(sectionFilters) == 0 {
		sectionFilters = sectionDefaults
	}
	printFilteredGlobalSections(sectionFilters, outputBuffer)

	// print output plugins
	if sliceContains("outputs", sectionFilters) {
		if len(outputFilters) != 0 {
			if len(outputFilters) >= 3 && outputFilters[1] != "none" {
				outputBuffer.Write([]byte(outputHeader))
			}
			printFilteredOutputs(outputFilters, false, outputBuffer)
		} else {
			outputBuffer.Write([]byte(outputHeader))
			printFilteredOutputs(outputDefaults, false, outputBuffer)
			// Print non-default outputs, commented
			var pnames []string
			for pname := range outputs.Outputs {
				if !sliceContains(pname, outputDefaults) {
					pnames = append(pnames, pname)
				}
			}
			printFilteredOutputs(pnames, true, outputBuffer)
		}
	}

	// print processor plugins
	if sliceContains("processors", sectionFilters) {
		if len(processorFilters) != 0 {
			if len(processorFilters) >= 3 && processorFilters[1] != "none" {
				outputBuffer.Write([]byte(processorHeader))
			}
			printFilteredProcessors(processorFilters, false, outputBuffer)
		} else {
			outputBuffer.Write([]byte(processorHeader))
			pnames := []string{}
			for pname := range processors.Processors {
				pnames = append(pnames, pname)
			}
			printFilteredProcessors(pnames, true, outputBuffer)
		}
	}

	// print aggregator plugins
	if sliceContains("aggregators", sectionFilters) {
		if len(aggregatorFilters) != 0 {
			if len(aggregatorFilters) >= 3 && aggregatorFilters[1] != "none" {
				outputBuffer.Write([]byte(aggregatorHeader))
			}
			printFilteredAggregators(aggregatorFilters, false, outputBuffer)
		} else {
			outputBuffer.Write([]byte(aggregatorHeader))
			pnames := []string{}
			for pname := range aggregators.Aggregators {
				pnames = append(pnames, pname)
			}
			printFilteredAggregators(pnames, true, outputBuffer)
		}
	}

	// print input plugins
	if sliceContains("inputs", sectionFilters) {
		if len(inputFilters) != 0 {
			if len(inputFilters) >= 3 && inputFilters[1] != "none" {
				outputBuffer.Write([]byte(inputHeader))
			}
			printFilteredInputs(inputFilters, false, outputBuffer)
		} else {
			outputBuffer.Write([]byte(inputHeader))
			printFilteredInputs(inputDefaults, false, outputBuffer)
			// Print non-default inputs, commented
			var pnames []string
			for pname := range inputs.Inputs {
				if !sliceContains(pname, inputDefaults) {
					pnames = append(pnames, pname)
				}
			}
			printFilteredInputs(pnames, true, outputBuffer)
		}
	}
}

func printFilteredProcessors(processorFilters []string, commented bool, outputBuffer io.Writer) {
	// Filter processors
	var pnames []string
	for pname := range processors.Processors {
		if sliceContains(pname, processorFilters) {
			pnames = append(pnames, pname)
		}
	}
	sort.Strings(pnames)

	// Print Outputs
	for _, pname := range pnames {
		creator := processors.Processors[pname]
		output := creator()
		printConfig(pname, output, "processors", commented, processors.Deprecations[pname], outputBuffer)
	}
}

func printFilteredAggregators(aggregatorFilters []string, commented bool, outputBuffer io.Writer) {
	// Filter outputs
	var anames []string
	for aname := range aggregators.Aggregators {
		if sliceContains(aname, aggregatorFilters) {
			anames = append(anames, aname)
		}
	}
	sort.Strings(anames)

	// Print Outputs
	for _, aname := range anames {
		creator := aggregators.Aggregators[aname]
		output := creator()
		printConfig(aname, output, "aggregators", commented, aggregators.Deprecations[aname], outputBuffer)
	}
}

func printFilteredInputs(inputFilters []string, commented bool, outputBuffer io.Writer) {
	// Filter inputs
	var pnames []string
	for pname := range inputs.Inputs {
		if sliceContains(pname, inputFilters) {
			pnames = append(pnames, pname)
		}
	}
	sort.Strings(pnames)

	// cache service inputs to print them at the end
	servInputs := make(map[string]telegraf.ServiceInput)
	// for alphabetical looping:
	servInputNames := []string{}

	// Print Inputs
	for _, pname := range pnames {
		// Skip inputs that are registered twice for backward compatibility
		switch pname {
		case "cisco_telemetry_gnmi", "io", "KNXListener":
			continue
		}
		creator := inputs.Inputs[pname]
		input := creator()

		if p, ok := input.(telegraf.ServiceInput); ok {
			servInputs[pname] = p
			servInputNames = append(servInputNames, pname)
			continue
		}

		printConfig(pname, input, "inputs", commented, inputs.Deprecations[pname], outputBuffer)
	}

	// Print Service Inputs
	if len(servInputs) == 0 {
		return
	}
	sort.Strings(servInputNames)

	outputBuffer.Write([]byte(serviceInputHeader))
	for _, name := range servInputNames {
		printConfig(name, servInputs[name], "inputs", commented, inputs.Deprecations[name], outputBuffer)
	}
}

func printFilteredOutputs(outputFilters []string, commented bool, outputBuffer io.Writer) {
	// Filter outputs
	var onames []string
	for oname := range outputs.Outputs {
		if sliceContains(oname, outputFilters) {
			onames = append(onames, oname)
		}
	}
	sort.Strings(onames)

	// Print Outputs
	for _, oname := range onames {
		creator := outputs.Outputs[oname]
		output := creator()
		printConfig(oname, output, "outputs", commented, outputs.Deprecations[oname], outputBuffer)
	}
}

func printFilteredGlobalSections(sectionFilters []string, outputBuffer io.Writer) {
	if sliceContains("global_tags", sectionFilters) {
		outputBuffer.Write([]byte(globalTagsConfig))
	}

	if sliceContains("agent", sectionFilters) {
		outputBuffer.Write([]byte(agentConfig))
	}
}

func printConfig(name string, p telegraf.PluginDescriber, op string, commented bool, di telegraf.DeprecationInfo, outputBuffer io.Writer) {
	comment := ""
	if commented {
		comment = "# "
	}

	if di.Since != "" {
		removalNote := ""
		if di.RemovalIn != "" {
			removalNote = " and will be removed in " + di.RemovalIn
		}
		outputBuffer.Write([]byte(fmt.Sprintf("\n%s ## DEPRECATED: The '%s' plugin is deprecated in version %s%s, %s.", comment, name, di.Since, removalNote, di.Notice)))
	}

	sample := p.SampleConfig()
	if sample == "" {
		outputBuffer.Write([]byte(fmt.Sprintf("\n#[[%s.%s]]", op, name)))
		outputBuffer.Write([]byte(fmt.Sprintf("\n%s  # no configuration\n\n", comment)))
	} else {
		lines := strings.Split(sample, "\n")
		outputBuffer.Write([]byte("\n"))
		for i, line := range lines {
			if i == len(lines)-1 {
				outputBuffer.Write([]byte("\n"))
				continue
			}
			outputBuffer.Write([]byte(strings.TrimRight(comment+line, " ") + "\n"))
		}
	}
}

// PrintInputConfig prints the config usage of a single input.
func PrintInputConfig(name string, outputBuffer io.Writer) error {
	creator, ok := inputs.Inputs[name]
	if !ok {
		return fmt.Errorf("input %s not found", name)
	}

	printConfig(name, creator(), "inputs", false, inputs.Deprecations[name], outputBuffer)
	return nil
}

// PrintOutputConfig prints the config usage of a single output.
func PrintOutputConfig(name string, outputBuffer io.Writer) error {
	creator, ok := outputs.Outputs[name]
	if !ok {
		return fmt.Errorf("output %s not found", name)
	}

	printConfig(name, creator(), "outputs", false, outputs.Deprecations[name], outputBuffer)
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"strings"
	"text/tabwriter"

	"github.com/dlespiau/x86db"
)

func nasmOpcodeToPlan9(op string) string {
	/*
	 * SSE
	 */
	switch op {
	// The condition is encoded as an imm8 operand of CMPPS
	case "CMPEQPS", "CMPLTPS", "CMPLEPS", "CMPUNORDPS", "CMPNEQPS", "CMPNLTPS",
		"CMPNLEPS", "CMPORDPS":
		return "CMPPS"
	// The condition is encoded as an imm8 operand of CMPSS.
	case "CMPEQSS", "CMPLTSS", "CMPLESS", "CMPUNORDSS", "CMPNEQSS", "CMPNLTSS",
		"CMPNLESS", "CMPORDSS":
		return "CMPSS"
	case "CVTSI2SS":
		return "CVTSL2SS"
	case "CVTSS2SI":
		return "CVTSS2SL"
	case "CVTTSS2SI":
		return "CVTTSS2SL"
	}

	/*
	 * PCLMULQDQ
	 */
	switch op {
	case "PCLMULLQLQDQ", "PCLMULHQLQDQ", "PCLMULLQHQDQ", "PCLMULHQHQDQ":
		return "PCLMULQDQ"
	}

	/*
	 * SSE2
	 */
	switch op {
	// The condition is encoded as an imm8 operand of CMPPD
	case "CMPEQPD", "CMPLTPD", "CMPLEPD", "CMPUNORDPD", "CMPNEQPD", "CMPNLTPD",
		"CMPNLEPD", "CMPORDPD":
		return "CMPPD"
	// The condition is encoded as an imm8 operand of CMPSD.
	case "CMPEQSD", "CMPLTSD", "CMPLESD", "CMPUNORDSD", "CMPNEQSD", "CMPNLTSD",
		"CMPNLESD", "CMPORDSD":
		return "CMPSD"
	// D (double word) has been replaced by L (Long)
	case "PSUBD":
		return "PSUBL"
	}

	return op
}

func isAlreadyKnown(name string) bool {
	name = nasmOpcodeToPlan9(name)
	for _, opcode := range Anames {
		if name == opcode {
			return true
		}
	}
	return false
}

func isAlreadyTested(name string) bool {
	name = nasmOpcodeToPlan9(name)
	_, ok := testedMap[name]
	return ok
}

func doHelp(insns x86db.InstructionSlice) {
	usage()
}

func doList(insns x86db.InstructionSlice) {
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
	for _, insn := range insns {
		fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", insn.Name,
			strings.Join(insn.Operands, ","), insn.Pattern, insn.Flags)
	}
	w.Flush()
}

var (
	filterFlags = flag.NewFlagSet("filter", flag.ExitOnError)
	extension   = filterFlags.String("extension", "",
		"select instructions by extension")
	known = filterFlags.Bool("known", false,
		"select instructions already known by the go assembler")
	notKnown = filterFlags.Bool("not-known", false,
		"select instructions not already known by the go assembler")
	tested = filterFlags.Bool("tested", false,
		"select instructions with test cases in the go assembler")
	notTested = filterFlags.Bool("not-tested", false,
		"select instructions with no test case in the go assembler")
)

type command struct {
	name    string
	help    string
	handler func(x86db.InstructionSlice)
}

var commands = []command{
	{"help", "print this help", nil},
	{"list", "list x86 instructions", doList},
}

func usage() {
	fmt.Fprintf(os.Stderr, "Usage:\n\n")
	fmt.Fprintf(os.Stderr, "  x86db-gogen command [options]\n\n")
	fmt.Fprintf(os.Stderr, "List of commands:\n\n")
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 4, ' ', 0)
	for _, cmd := range commands {
		fmt.Fprintf(w, "  %s\t%s\n", cmd.name, cmd.help)
	}
	w.Flush()
	fmt.Fprintf(os.Stderr, "\n")
	fmt.Fprintf(os.Stderr, "Filtering options:\n\n")
	filterFlags.PrintDefaults()
}

func main() {
	db := x86db.NewDB()

	if err := filterFlags.Parse(os.Args[2:]); err != nil {
		log.Fatal(err)
	}

	err := db.Open()
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	insns := db.Instructions

	if *extension != "" {
		ext, err := x86db.ExtensionFromString(*extension)
		if err != nil {
			log.Fatal(err)
		}
		insns = insns.Where(func(insn x86db.Instruction) bool {
			return insn.Extension == ext
		})
	}

	if *known || *notKnown {
		insns = insns.Where(func(insn x86db.Instruction) bool {
			k := isAlreadyKnown(insn.Name)
			if *notKnown {
				return !k
			}
			return k
		})
	}

	if *tested || *notTested {
		insns = insns.Where(func(insn x86db.Instruction) bool {
			t := isAlreadyTested(insn.Name)
			if *notTested {
				return !t
			}
			return t
		})
	}

	cmdName := os.Args[1]
	handled := false
	for _, cmd := range commands {
		if cmd.name != cmdName {
			continue
		}
		if cmd.handler == nil {
			continue
		}

		handled = true
		cmd.handler(insns)
	}

	if !handled {
		fmt.Fprintf(os.Stderr, "unknown command '%s'\n\n", cmdName)
		usage()
		os.Exit(1)
	}
}
<commit_msg>gogen: Allow filtering out MMX instructions<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"strings"
	"text/tabwriter"

	"github.com/dlespiau/x86db"
)

func nasmOpcodeToPlan9(op string) string {
	/*
	 * SSE
	 */
	switch op {
	// The condition is encoded as an imm8 operand of CMPPS
	case "CMPEQPS", "CMPLTPS", "CMPLEPS", "CMPUNORDPS", "CMPNEQPS", "CMPNLTPS",
		"CMPNLEPS", "CMPORDPS":
		return "CMPPS"
	// The condition is encoded as an imm8 operand of CMPSS.
	case "CMPEQSS", "CMPLTSS", "CMPLESS", "CMPUNORDSS", "CMPNEQSS", "CMPNLTSS",
		"CMPNLESS", "CMPORDSS":
		return "CMPSS"
	case "CVTSI2SS":
		return "CVTSL2SS"
	case "CVTSS2SI":
		return "CVTSS2SL"
	case "CVTTSS2SI":
		return "CVTTSS2SL"
	}

	/*
	 * PCLMULQDQ
	 */
	switch op {
	case "PCLMULLQLQDQ", "PCLMULHQLQDQ", "PCLMULLQHQDQ", "PCLMULHQHQDQ":
		return "PCLMULQDQ"
	}

	/*
	 * SSE2
	 */
	switch op {
	// The condition is encoded as an imm8 operand of CMPPD
	case "CMPEQPD", "CMPLTPD", "CMPLEPD", "CMPUNORDPD", "CMPNEQPD", "CMPNLTPD",
		"CMPNLEPD", "CMPORDPD":
		return "CMPPD"
	// The condition is encoded as an imm8 operand of CMPSD.
	case "CMPEQSD", "CMPLTSD", "CMPLESD", "CMPUNORDSD", "CMPNEQSD", "CMPNLTSD",
		"CMPNLESD", "CMPORDSD":
		return "CMPSD"
	// D (double word) has been replaced by L (Long)
	case "PSUBD":
		return "PSUBL"
	}

	return op
}

func isAlreadyKnown(name string) bool {
	name = nasmOpcodeToPlan9(name)
	for _, opcode := range Anames {
		if name == opcode {
			return true
		}
	}
	return false
}

func isAlreadyTested(name string) bool {
	name = nasmOpcodeToPlan9(name)
	_, ok := testedMap[name]
	return ok
}

func isMMXOperand(op string) bool {
	if op == "mmxreg" || op == "mmxrm" || op == "mmxrm64" {
		return true
	}
	return false
}

func isMMX(insn *x86db.Instruction) bool {
	for _, op := range insn.Operands {
		if isMMXOperand(op) {
			return true
		}
	}
	return false
}

func doHelp(insns x86db.InstructionSlice) {
	usage()
}

func doList(insns x86db.InstructionSlice) {
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
	for _, insn := range insns {
		fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", insn.Name,
			strings.Join(insn.Operands, ","), insn.Pattern, insn.Flags)
	}
	w.Flush()
}

var (
	filterFlags = flag.NewFlagSet("filter", flag.ExitOnError)
	extension   = filterFlags.String("extension", "",
		"select instructions by extension")
	noMMX = filterFlags.Bool("no-mmx", false,
		"do not select instructions taking MMX operands")
	known = filterFlags.Bool("known", false,
		"select instructions already known by the go assembler")
	notKnown = filterFlags.Bool("not-known", false,
		"select instructions not already known by the go assembler")
	tested = filterFlags.Bool("tested", false,
		"select instructions with test cases in the go assembler")
	notTested = filterFlags.Bool("not-tested", false,
		"select instructions with no test case in the go assembler")
)

type command struct {
	name    string
	help    string
	handler func(x86db.InstructionSlice)
}

var commands = []command{
	{"help", "print this help", nil},
	{"list", "list x86 instructions", doList},
}

func usage() {
	fmt.Fprintf(os.Stderr, "Usage:\n\n")
	fmt.Fprintf(os.Stderr, "  x86db-gogen command [options]\n\n")
	fmt.Fprintf(os.Stderr, "List of commands:\n\n")
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 4, ' ', 0)
	for _, cmd := range commands {
		fmt.Fprintf(w, "  %s\t%s\n", cmd.name, cmd.help)
	}
	w.Flush()
	fmt.Fprintf(os.Stderr, "\n")
	fmt.Fprintf(os.Stderr, "Filtering options:\n\n")
	filterFlags.PrintDefaults()
}

func main() {
	db := x86db.NewDB()

	if err := filterFlags.Parse(os.Args[2:]); err != nil {
		log.Fatal(err)
	}

	err := db.Open()
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	insns := db.Instructions

	if *extension != "" {
		ext, err := x86db.ExtensionFromString(*extension)
		if err != nil {
			log.Fatal(err)
		}
		insns = insns.Where(func(insn x86db.Instruction) bool {
			return insn.Extension == ext
		})
	}

	if *noMMX {
		insns = insns.Where(func(insn x86db.Instruction) bool {
			return !isMMX(&insn)
		})
	}

	if *known || *notKnown {
		insns = insns.Where(func(insn x86db.Instruction) bool {
			k := isAlreadyKnown(insn.Name)
			if *notKnown {
				return !k
			}
			return k
		})
	}

	if *tested || *notTested {
		insns = insns.Where(func(insn x86db.Instruction) bool {
			t := isAlreadyTested(insn.Name)
			if *notTested {
				return !t
			}
			return t
		})
	}

	cmdName := os.Args[1]
	handled := false
	for _, cmd := range commands {
		if cmd.name != cmdName {
			continue
		}
		if cmd.handler == nil {
			continue
		}

		handled = true
		cmd.handler(insns)
	}

	if !handled {
		fmt.Fprintf(os.Stderr, "unknown command '%s'\n\n", cmdName)
		usage()
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package agent

import (
	"bytes"
	"crypto/tls"
	"errors"
	"fmt"
	"net/url"
	"strings"
	"sync"
	"time"

	mqtt "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git"
	"github.com/juju/loggo"
)

var AlreadyConfigured = errors.New("Already configured")
var AlreadyUnConfigured = errors.New("Already unconfigured")

//
// Acts as a bridge between local and cloud brokers, this includes reconnecting
// and emitting status changes.
//
// Once configured and started this will attempt to connect to connect to local
// and cloud brokers, if something dies it will reconnect based on the configured
// reconnect backoff.
//
type Bridge struct {
	conf   *Config
	local  *mqtt.MqttClient
	remote *mqtt.MqttClient
	log    loggo.Logger

	localTopics []replaceTopic
	cloudTopics []replaceTopic

	cloudUrl *url.URL
	token    string

	timer       *time.Timer
	reconnectCh chan bool
	shutdownCh  chan bool

	Configured bool
	Connected  bool
	Counter    int64

	IngressCounter int64
	EgressCounter  int64

	IngressBytes int64
	EgressBytes  int64

	LastError error

	bridgeLock sync.Mutex
}

type replaceTopic struct {
	on      string
	replace string
	with    string
}

func (r *replaceTopic) updated(originalTopic string) string {
	return strings.Replace(originalTopic, r.replace, r.with, 1)
}

var localTopics = []replaceTopic{
	// location related topics (TODO: move to cloud userspace RPC)
	{on: "$location/calibration", replace: "$location", with: "$cloud/location"},
	{on: "$location/delete", replace: "$location", with: "$cloud/location"},
	{on: "$device/+/+/rssi", replace: "$device", with: "$cloud/device"},

	// module health statistics
	//{on: "$node/+/module/status", replace: "$node", with: "$cloud/node"},

	// cloud userspace RPC requests
	{on: "$ninja/services/rpc/+/+", replace: "$ninja", with: "$cloud/ninja"},
	{on: "$ninja/services/+", replace: "$ninja", with: "$cloud/ninja"},

	// temporary alternate topic to distinguish remote device replies from local-destined ones
	// used by the phone app for remote actuations
	// the alternate remote_ topic is to prevent a loopback with the below rule in the other direction
	// TODO: use a tag like $mesh-source to prevent loops (never re-proxy msgs with your source)
	{on: "$device/+/channel/+/reply", replace: "$device", with: "$cloud/remote_device"},

	// push up all local RPC methods in case the cloud is responding,
	// this is currently used for the push notification channel
	{on: "$device/+/channel/+", replace: "$device", with: "$cloud/device"},

	// push up state changes to the cloud
	{on: "$device/+/channel/+/event/state", replace: "$device", with: "$cloud/device"},
}

var cloudTopics = []replaceTopic{
	// location related topics
	{on: "$cloud/location/calibration/progress", replace: "$cloud/location", with: "$location"},
	{on: "$cloud/device/+/+/location", replace: "$cloud/device", with: "$device"},

	// cloud userspace RPC replies
	{on: "$cloud/ninja/services/rpc/+/+/reply", replace: "$cloud/ninja", with: "$ninja"},

	// see comment for $device/+/channel/+/reply above
	{on: "$cloud/remote_device/+/channel/+", replace: "$cloud/remote_device", with: "$device"},

	// allow cloud to announce devices and channels (used for phone on 3G and notification subscription channel)
	{on: "$cloud/device/+/event/announce", replace: "$cloud/device", with: "$device"},
	{on: "$cloud/device/+/channel/+/event/announce", replace: "$cloud/device", with: "$device"},

	// retrieve RPC responses from the cloud,
	// this is currently used for the push notification channel
	{on: "$cloud/device/+/channel/+/reply", replace: "$cloud/device", with: "$device"},
}

func createBridge(conf *Config) *Bridge {
	return &Bridge{conf: conf, localTopics: localTopics, cloudTopics: cloudTopics, log: loggo.GetLogger("bridge")}
}

func (b *Bridge) start(cloudUrl string, token string) (err error) {

	if b.Configured {
		b.log.Warningf("Already configured.")
		return AlreadyConfigured
	}

	defer b.bridgeLock.Unlock()

	b.bridgeLock.Lock()

	b.log.Infof("Connecting the bridge")

	b.Configured = true

	url, err := url.Parse(cloudUrl)

	if err != nil {
		return err
	}

	b.cloudUrl = url
	b.token = token

	b.reconnectCh = make(chan bool, 1)
	b.shutdownCh = make(chan bool, 1)

	if err = b.connect(); err != nil {
		b.log.Errorf("Connect failed %s", err)
		b.scheduleReconnect(err)
	}

	go b.mainBridgeLoop()

	return err
}

func (b *Bridge) stop() error {

	if !b.Configured {
		b.log.Warningf("Already unconfigured.")
		return AlreadyUnConfigured
	}

	defer b.bridgeLock.Unlock()

	b.bridgeLock.Lock()

	b.log.Infof("Disconnecting bridge")

	if b.Configured {
		// tell the worker to shutdown
		b.shutdownCh <- true

		b.Configured = false
	}

	b.resetTimer()

	b.disconnectAll()

	return nil
}

func (b *Bridge) connect() (err error) {

	if b.local, err = b.buildClient(b.conf.LocalUrl, ""); err != nil {
		b.Connected = false
		return err
	}

	if b.remote, err = b.buildClient(b.cloudUrl.String(), b.token); err != nil {
		b.Connected = false
		return err
	}

	if err = b.subscriptions(); err != nil {
		return err
	}

	// we are now connected
	b.Connected = true

	return nil
}

func (b *Bridge) reconnect() (err error) {

	if b.local, err = b.buildClient(b.conf.LocalUrl, ""); err != nil {
		b.Connected = false
		return err
	}

	if b.remote, err = b.buildClient(b.cloudUrl.String(), b.token); err != nil {
		b.Connected = false
		return err
	}

	if err = b.subscriptions(); err != nil {
		return err
	}

	// we are now connected
	b.Connected = true
	b.LastError = nil

	return nil
}

func (b *Bridge) subscriptions() (err error) {

	if err = b.subscribe(b.local, b.remote, b.localTopics, "local"); err != nil {
		return err
	}

	if err = b.subscribe(b.remote, b.local, b.cloudTopics, "cloud"); err != nil {
		return err
	}
	return nil

}

func (b *Bridge) disconnectAll() {
	b.log.Infof("disconnectAll")
	// we are now disconnected
	b.Connected = false
	if b.local != nil && b.local.IsConnected() {
		b.local.Disconnect(100)
	}
	if b.remote != nil && b.remote.IsConnected() {
		b.remote.Disconnect(100)
	}
}

func (b *Bridge) mainBridgeLoop() {

	for {
		select {
		case <-b.reconnectCh:
			b.log.Infof("reconnecting")
			if err := b.reconnect(); err != nil {
				b.log.Errorf("Reconnect failed %s", err)
				b.scheduleReconnect(err)
			}
		case <-b.shutdownCh:
			b.log.Infof("shutting down bridge")
			return
		}

	}

}

func (b *Bridge) buildClient(server string, token string) (*mqtt.MqttClient, error) {

	b.log.Infof("building client for %s", server)

	opts := mqtt.NewClientOptions().AddBroker(server).SetTlsConfig(&tls.Config{InsecureSkipVerify: true})

	if token != "" {
		opts.SetUsername(token)
	}

	opts.SetClientId(fmt.Sprintf("%d", time.Now().Unix()))

	opts.SetKeepAlive(15) // set a 15 second ping time for ELB

	// pretty much log the reason and quit
	opts.SetOnConnectionLost(b.onConnectionLoss)

	client := mqtt.NewClient(opts)
	_, err := client.Start()

	return client, err
}

func (b *Bridge) subscribe(src *mqtt.MqttClient, dst *mqtt.MqttClient, topics []replaceTopic, tag string) (err error) {

	for _, topic := range topics {

		topicFilter, _ := mqtt.NewTopicFilter(topic.on, 0)
		b.log.Infof("(%s) subscribed to %s", tag, topic.on)

		if receipt, err := src.StartSubscription(b.buildHandler(topic, tag, dst), topicFilter); err != nil {
			return err
		} else {
			<-receipt
			b.log.Infof("(%s) subscribed to %+v", tag, topicFilter)
		}
	}

	return nil
}

func (b *Bridge) unsubscribe(client *mqtt.MqttClient, topics []replaceTopic, tag string) {

	topicNames := []string{}

	for _, topic := range topics {
		topicNames = append(topicNames, topic.on)
	}

	b.log.Infof("(%s) unsubscribed to %s", tag, topicNames)
	client.EndSubscription(topicNames...)
}

func (b *Bridge) buildHandler(topic replaceTopic, tag string, dst *mqtt.MqttClient) mqtt.MessageHandler {
	return func(src *mqtt.MqttClient, msg mqtt.Message) {
		if b.log.IsDebugEnabled() {
			b.log.Debugf("(%s) topic: %s updated: %s len: %d", tag, msg.Topic(), topic.updated(msg.Topic()), len(msg.Payload()))
		}
		b.updateCounters(tag, msg)
		payload := b.updateSource(msg.Payload(), b.buildSource(tag))
		dst.PublishMessage(topic.updated(msg.Topic()), mqtt.NewMessage(payload))
	}
}

func (b *Bridge) scheduleReconnect(reason error) {
	b.LastError = reason
	b.disconnectAll()
	b.resetTimer()

	switch reason {
	case mqtt.ErrBadCredentials:
		b.log.Warningf("Reconnect failed trying again in 30s")

		b.timer = time.AfterFunc(30*time.Second, func() {
			b.reconnectCh <- true
		})

	default:
		b.log.Warningf("Reconnect failed trying again in 5s")
		// TODO add exponential backoff
		b.timer = time.AfterFunc(5*time.Second, func() {
			b.reconnectCh <- true
		})
	}

}

func (b *Bridge) resetTimer() {
	if b.timer != nil {
		b.timer.Stop()
	}
}

func (b *Bridge) onConnectionLoss(client *mqtt.MqttClient, reason error) {
	b.log.Errorf("Connection failed %s", reason)

	// we are now disconnected
	b.Connected = false

	b.scheduleReconnect(reason)

}

func (b *Bridge) IsConnected() bool {
	if b.remote == nil || b.local == nil {
		return false
	}
	return (b.remote.IsConnected() && b.local.IsConnected())
}

func (b *Bridge) buildSource(tag string) string {

	switch tag {
	case "local":
		return b.conf.SerialNo
	case "cloud":
		return "cloud-" + strings.Replace(b.cloudUrl.Host, ".", "_", -1) // encoded to look less wierd
	}

	return ""
}

func (b *Bridge) updateSource(payload []byte, source string) []byte {

	if !bytes.Contains(payload, []byte("$mesh-source")) {
		payload = bytes.Replace(payload, []byte("{"), []byte(`{"$mesh-source":"`+source+`", `), 1)
	}

	b.log.Debugf("msg %s", string(payload))

	return payload
}

func (b *Bridge) updateCounters(tag string, msg mqtt.Message) {
	switch tag {
	case "local":
		b.EgressCounter++
		b.EgressBytes += int64(len(msg.Bytes())) // message size not payload size
	case "cloud":
		b.IngressCounter++
		b.IngressBytes += int64(len(msg.Bytes())) // message size not payload size
	}

}
<commit_msg>Add $ninja/client-services topics to support inbound RPCs from the clouds to sphere-hosted services.<commit_after>package agent

import (
	"bytes"
	"crypto/tls"
	"errors"
	"fmt"
	"net/url"
	"strings"
	"sync"
	"time"

	mqtt "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git"
	"github.com/juju/loggo"
)

var AlreadyConfigured = errors.New("Already configured")
var AlreadyUnConfigured = errors.New("Already unconfigured")

//
// Acts as a bridge between local and cloud brokers, this includes reconnecting
// and emitting status changes.
//
// Once configured and started this will attempt to connect to connect to local
// and cloud brokers, if something dies it will reconnect based on the configured
// reconnect backoff.
//
type Bridge struct {
	conf   *Config
	local  *mqtt.MqttClient
	remote *mqtt.MqttClient
	log    loggo.Logger

	localTopics []replaceTopic
	cloudTopics []replaceTopic

	cloudUrl *url.URL
	token    string

	timer       *time.Timer
	reconnectCh chan bool
	shutdownCh  chan bool

	Configured bool
	Connected  bool
	Counter    int64

	IngressCounter int64
	EgressCounter  int64

	IngressBytes int64
	EgressBytes  int64

	LastError error

	bridgeLock sync.Mutex
}

type replaceTopic struct {
	on      string
	replace string
	with    string
}

func (r *replaceTopic) updated(originalTopic string) string {
	return strings.Replace(originalTopic, r.replace, r.with, 1)
}

var localTopics = []replaceTopic{
	// location related topics (TODO: move to cloud userspace RPC)
	{on: "$location/calibration", replace: "$location", with: "$cloud/location"},
	{on: "$location/delete", replace: "$location", with: "$cloud/location"},
	{on: "$device/+/+/rssi", replace: "$device", with: "$cloud/device"},

	// module health statistics
	//{on: "$node/+/module/status", replace: "$node", with: "$cloud/node"},

	// cloud userspace RPC requests
	{on: "$ninja/services/rpc/+/+", replace: "$ninja", with: "$cloud/ninja"},
	{on: "$ninja/services/+", replace: "$ninja", with: "$cloud/ninja"},

	// temporary alternate topic to distinguish remote device replies from local-destined ones
	// used by the phone app for remote actuations
	// the alternate remote_ topic is to prevent a loopback with the below rule in the other direction
	// TODO: use a tag like $mesh-source to prevent loops (never re-proxy msgs with your source)
	{on: "$device/+/channel/+/reply", replace: "$device", with: "$cloud/remote_device"},

	// push up all local RPC methods in case the cloud is responding,
	// this is currently used for the push notification channel
	{on: "$device/+/channel/+", replace: "$device", with: "$cloud/device"},

	// push up state changes to the cloud
	{on: "$device/+/channel/+/event/state", replace: "$device", with: "$cloud/device"},

	// topic used to listen to replies from client-hosted services
	{on: "$ninja/client-services/+/reply", replace: "$ninja", with: "$cloud/ninja"},
}

var cloudTopics = []replaceTopic{
	// location related topics
	{on: "$cloud/location/calibration/progress", replace: "$cloud/location", with: "$location"},
	{on: "$cloud/device/+/+/location", replace: "$cloud/device", with: "$device"},

	// cloud userspace RPC replies
	{on: "$cloud/ninja/services/rpc/+/+/reply", replace: "$cloud/ninja", with: "$ninja"},

	// see comment for $device/+/channel/+/reply above
	{on: "$cloud/remote_device/+/channel/+", replace: "$cloud/remote_device", with: "$device"},

	// allow cloud to announce devices and channels (used for phone on 3G and notification subscription channel)
	{on: "$cloud/device/+/event/announce", replace: "$cloud/device", with: "$device"},
	{on: "$cloud/device/+/channel/+/event/announce", replace: "$cloud/device", with: "$device"},

	// retrieve RPC responses from the cloud,
	// this is currently used for the push notification channel
	{on: "$cloud/device/+/channel/+/reply", replace: "$cloud/device", with: "$device"},

	// topic used to listen to services published by clients to the cloud
	{on: "$ninja/client-services/+", replace: "$ninja", with: "$cloud/ninja"},
}

func createBridge(conf *Config) *Bridge {
	return &Bridge{conf: conf, localTopics: localTopics, cloudTopics: cloudTopics, log: loggo.GetLogger("bridge")}
}

func (b *Bridge) start(cloudUrl string, token string) (err error) {

	if b.Configured {
		b.log.Warningf("Already configured.")
		return AlreadyConfigured
	}

	defer b.bridgeLock.Unlock()

	b.bridgeLock.Lock()

	b.log.Infof("Connecting the bridge")

	b.Configured = true

	url, err := url.Parse(cloudUrl)

	if err != nil {
		return err
	}

	b.cloudUrl = url
	b.token = token

	b.reconnectCh = make(chan bool, 1)
	b.shutdownCh = make(chan bool, 1)

	if err = b.connect(); err != nil {
		b.log.Errorf("Connect failed %s", err)
		b.scheduleReconnect(err)
	}

	go b.mainBridgeLoop()

	return err
}

func (b *Bridge) stop() error {

	if !b.Configured {
		b.log.Warningf("Already unconfigured.")
		return AlreadyUnConfigured
	}

	defer b.bridgeLock.Unlock()

	b.bridgeLock.Lock()

	b.log.Infof("Disconnecting bridge")

	if b.Configured {
		// tell the worker to shutdown
		b.shutdownCh <- true

		b.Configured = false
	}

	b.resetTimer()

	b.disconnectAll()

	return nil
}

func (b *Bridge) connect() (err error) {

	if b.local, err = b.buildClient(b.conf.LocalUrl, ""); err != nil {
		b.Connected = false
		return err
	}

	if b.remote, err = b.buildClient(b.cloudUrl.String(), b.token); err != nil {
		b.Connected = false
		return err
	}

	if err = b.subscriptions(); err != nil {
		return err
	}

	// we are now connected
	b.Connected = true

	return nil
}

func (b *Bridge) reconnect() (err error) {

	if b.local, err = b.buildClient(b.conf.LocalUrl, ""); err != nil {
		b.Connected = false
		return err
	}

	if b.remote, err = b.buildClient(b.cloudUrl.String(), b.token); err != nil {
		b.Connected = false
		return err
	}

	if err = b.subscriptions(); err != nil {
		return err
	}

	// we are now connected
	b.Connected = true
	b.LastError = nil

	return nil
}

func (b *Bridge) subscriptions() (err error) {

	if err = b.subscribe(b.local, b.remote, b.localTopics, "local"); err != nil {
		return err
	}

	if err = b.subscribe(b.remote, b.local, b.cloudTopics, "cloud"); err != nil {
		return err
	}
	return nil

}

func (b *Bridge) disconnectAll() {
	b.log.Infof("disconnectAll")
	// we are now disconnected
	b.Connected = false
	if b.local != nil && b.local.IsConnected() {
		b.local.Disconnect(100)
	}
	if b.remote != nil && b.remote.IsConnected() {
		b.remote.Disconnect(100)
	}
}

func (b *Bridge) mainBridgeLoop() {

	for {
		select {
		case <-b.reconnectCh:
			b.log.Infof("reconnecting")
			if err := b.reconnect(); err != nil {
				b.log.Errorf("Reconnect failed %s", err)
				b.scheduleReconnect(err)
			}
		case <-b.shutdownCh:
			b.log.Infof("shutting down bridge")
			return
		}

	}

}

func (b *Bridge) buildClient(server string, token string) (*mqtt.MqttClient, error) {

	b.log.Infof("building client for %s", server)

	opts := mqtt.NewClientOptions().AddBroker(server).SetTlsConfig(&tls.Config{InsecureSkipVerify: true})

	if token != "" {
		opts.SetUsername(token)
	}

	opts.SetClientId(fmt.Sprintf("%d", time.Now().Unix()))

	opts.SetKeepAlive(15) // set a 15 second ping time for ELB

	// pretty much log the reason and quit
	opts.SetOnConnectionLost(b.onConnectionLoss)

	client := mqtt.NewClient(opts)
	_, err := client.Start()

	return client, err
}

func (b *Bridge) subscribe(src *mqtt.MqttClient, dst *mqtt.MqttClient, topics []replaceTopic, tag string) (err error) {

	for _, topic := range topics {

		topicFilter, _ := mqtt.NewTopicFilter(topic.on, 0)
		b.log.Infof("(%s) subscribed to %s", tag, topic.on)

		if receipt, err := src.StartSubscription(b.buildHandler(topic, tag, dst), topicFilter); err != nil {
			return err
		} else {
			<-receipt
			b.log.Infof("(%s) subscribed to %+v", tag, topicFilter)
		}
	}

	return nil
}

func (b *Bridge) unsubscribe(client *mqtt.MqttClient, topics []replaceTopic, tag string) {

	topicNames := []string{}

	for _, topic := range topics {
		topicNames = append(topicNames, topic.on)
	}

	b.log.Infof("(%s) unsubscribed to %s", tag, topicNames)
	client.EndSubscription(topicNames...)
}

func (b *Bridge) buildHandler(topic replaceTopic, tag string, dst *mqtt.MqttClient) mqtt.MessageHandler {
	return func(src *mqtt.MqttClient, msg mqtt.Message) {
		if b.log.IsDebugEnabled() {
			b.log.Debugf("(%s) topic: %s updated: %s len: %d", tag, msg.Topic(), topic.updated(msg.Topic()), len(msg.Payload()))
		}
		b.updateCounters(tag, msg)
		payload := b.updateSource(msg.Payload(), b.buildSource(tag))
		dst.PublishMessage(topic.updated(msg.Topic()), mqtt.NewMessage(payload))
	}
}

func (b *Bridge) scheduleReconnect(reason error) {
	b.LastError = reason
	b.disconnectAll()
	b.resetTimer()

	switch reason {
	case mqtt.ErrBadCredentials:
		b.log.Warningf("Reconnect failed trying again in 30s")

		b.timer = time.AfterFunc(30*time.Second, func() {
			b.reconnectCh <- true
		})

	default:
		b.log.Warningf("Reconnect failed trying again in 5s")
		// TODO add exponential backoff
		b.timer = time.AfterFunc(5*time.Second, func() {
			b.reconnectCh <- true
		})
	}

}

func (b *Bridge) resetTimer() {
	if b.timer != nil {
		b.timer.Stop()
	}
}

func (b *Bridge) onConnectionLoss(client *mqtt.MqttClient, reason error) {
	b.log.Errorf("Connection failed %s", reason)

	// we are now disconnected
	b.Connected = false

	b.scheduleReconnect(reason)

}

func (b *Bridge) IsConnected() bool {
	if b.remote == nil || b.local == nil {
		return false
	}
	return (b.remote.IsConnected() && b.local.IsConnected())
}

func (b *Bridge) buildSource(tag string) string {

	switch tag {
	case "local":
		return b.conf.SerialNo
	case "cloud":
		return "cloud-" + strings.Replace(b.cloudUrl.Host, ".", "_", -1) // encoded to look less wierd
	}

	return ""
}

func (b *Bridge) updateSource(payload []byte, source string) []byte {

	if !bytes.Contains(payload, []byte("$mesh-source")) {
		payload = bytes.Replace(payload, []byte("{"), []byte(`{"$mesh-source":"`+source+`", `), 1)
	}

	b.log.Debugf("msg %s", string(payload))

	return payload
}

func (b *Bridge) updateCounters(tag string, msg mqtt.Message) {
	switch tag {
	case "local":
		b.EgressCounter++
		b.EgressBytes += int64(len(msg.Bytes())) // message size not payload size
	case "cloud":
		b.IngressCounter++
		b.IngressBytes += int64(len(msg.Bytes())) // message size not payload size
	}

}
<|endoftext|>


<commit_before>package commands

import (
	"os"

	"github.com/github/git-lfs/git"
	"github.com/github/git-lfs/lfs"
	"github.com/spf13/cobra"
)

var (
	getCmd = &cobra.Command{
		Use:   "get",
		Short: "get",
		Run:   getCommand,
	}
)

func getCommand(cmd *cobra.Command, args []string) {
	var ref string
	var err error

	if len(args) == 1 {
		ref = args[0]
	} else {
		ref, err = git.CurrentRef()
		if err != nil {
			Panic(err, "Could not get")
		}
	}

	pointers, err := lfs.ScanRefs(ref, "")
	if err != nil {
		Panic(err, "Could not scan for Git LFS files")
	}

	q := lfs.NewDownloadQueue(lfs.Config.ConcurrentTransfers(), len(pointers))

	for _, p := range pointers {
		q.Add(lfs.NewDownloadable(p))
	}

	q.Process()

	target, err := git.ResolveRef(ref)
	if err != nil {
	}

	current, err := git.CurrentRef()
	if err != nil {
	}

	if target == current {
		// We just downloaded the files for the current ref, we can copy them into
		// the working directory and update the git index
		for _, pointer := range pointers {
			file, err := os.Create(pointer.Name)
			if err != nil {
				Panic(err, "Could not create working directory file")
			}

			if err := lfs.PointerSmudge(file, pointer.Pointer, pointer.Name, nil); err != nil {
				Panic(err, "Could not write working directory file")
			}

			if err := git.UpdateIndex(pointer.Name); err != nil {
				Panic(err, "Could not update index")
			}
		}
	}
}

func init() {
	RootCmd.AddCommand(getCmd)
}
<commit_msg>ンンンンン ンンンン<commit_after>package commands

import (
	"os"
	"os/exec"
	"time"

	"github.com/github/git-lfs/git"
	"github.com/github/git-lfs/lfs"
	"github.com/rubyist/tracerx"
	"github.com/spf13/cobra"
)

var (
	getCmd = &cobra.Command{
		Use:   "get",
		Short: "get",
		Run:   getCommand,
	}
)

func getCommand(cmd *cobra.Command, args []string) {
	var ref string
	var err error

	if len(args) == 1 {
		ref = args[0]
	} else {
		ref, err = git.CurrentRef()
		if err != nil {
			Panic(err, "Could not get")
		}
	}

	pointers, err := lfs.ScanRefs(ref, "")
	if err != nil {
		Panic(err, "Could not scan for Git LFS files")
	}

	q := lfs.NewDownloadQueue(lfs.Config.ConcurrentTransfers(), len(pointers))

	for _, p := range pointers {
		q.Add(lfs.NewDownloadable(p))
	}

	processQueue := time.Now()
	q.Process()
	tracerx.PerformanceSince("process queue", processQueue)

	target, err := git.ResolveRef(ref)
	if err != nil {
	}

	current, err := git.CurrentRef()
	if err != nil {
	}

	if target == current {
		// We just downloaded the files for the current ref, we can copy them into
		// the working directory and update the git index
		updateWd := time.Now()
		for _, pointer := range pointers {
			file, err := os.Create(pointer.Name)
			if err != nil {
				Panic(err, "Could not create working directory file")
			}

			if err := lfs.PointerSmudge(file, pointer.Pointer, pointer.Name, nil); err != nil {
				Panic(err, "Could not write working directory file")
			}
		}
		tracerx.PerformanceSince("update working directory", updateWd)

		updateIndex := time.Now()
		cmd := exec.Command("git", "update-index", "-q", "--refresh", "--stdin")
		stdin, err := cmd.StdinPipe()
		if err != nil {
			Panic(err, "Could not update the index")
		}

		if err := cmd.Start(); err != nil {
			Panic(err, "Could not update the index")
		}

		for _, pointer := range pointers {
			stdin.Write([]byte(pointer.Name + "\n"))
		}
		stdin.Close()
		cmd.Wait()
		tracerx.PerformanceSince("update index", updateIndex)
	}

}

func init() {
	RootCmd.AddCommand(getCmd)
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"errors"
	"fmt"
	"log"
	"strconv"

	"github.com/satori/go.uuid"
)

type somaOncallRequest struct {
	action string
	oncall somaproto.ProtoOncall
	reply  chan []somaOncallResult
}

type somaOncallResult struct {
	rErr   error
	lErr   error
	oncall somaproto.ProtoOncall
}

/* Read Access
 *
 */
type somaOncallReadHandler struct {
	input     chan somaOncallRequest
	shutdown  chan bool
	conn      *sql.DB
	list_stmt *sql.Stmt
	show_stmt *sql.Stmt
}

func (r *somaOncallReadHandler) run() {
	var err error

	r.list_stmt, err = r.conn.Prepare(`
SELECT oncall_duty_id, oncall_duty_name
FROM inventory.oncall_duty_teams;`)
	if err != nil {
		log.Fatal(err)
	}

	r.show_stmt, err = r.conn.Prepare(`
SELECT oncall_duty_id, oncall_duty_name, oncall_duty_phone_number
FROM inventory.oncall_duty_teams
WHERE oncall_duty_id = $1;`)
	if err != nil {
		log.Fatal(err)
	}

runloop:
	for {
		select {
		case <-r.shutdown:
			break runloop
		case req := <-r.input:
			go func() {
				r.process(&req)
			}()
		}
	}
}

func (r *somaOncallReadHandler) process(q *somaOncallRequest) {
	var oncallId, oncallName string
	var oncallNumber int
	var rows *sql.Rows
	var err error
	result := make([]somaOncallResult, 0)

	switch q.action {
	case "list":
		log.Printf("R: oncall/list")
		rows, err = r.list_stmt.Query()
		defer rows.Close()
		if err != nil {
			result = append(result, somaOncallResult{
				rErr: err,
			})
			q.reply <- result
			return
		}

		for rows.Next() {
			err := rows.Scan(&oncallId, &oncallName)
			if err != nil {
				result = append(result, somaOncallResult{
					lErr: err,
				})
				err = nil
				continue
			}
			result = append(result, somaOncallResult{
				oncall: somaproto.ProtoOncall{
					Id:   oncallId,
					Name: oncallName,
				},
			})
		}
	case "show":
		log.Printf("R: oncall/show for %s", q.oncall.Id)
		err = r.show_stmt.QueryRow(q.oncall.Id).Scan(&oncallId, &oncallName, &oncallNumber)
		if err != nil {
			if err.Error() != "sql: no rows in result set" {
				result = append(result, somaOncallResult{
					rErr: err,
				})
			}
			q.reply <- result
			return
		}

		result = append(result, somaOncallResult{
			oncall: somaproto.ProtoOncall{
				Id:     oncallId,
				Name:   oncallName,
				Number: strconv.Itoa(oncallNumber),
			},
		})
	default:
		result = append(result, somaOncallResult{
			rErr: errors.New("not implemented"),
		})
	}
	q.reply <- result
}

/* Write Access
 *
 */
type somaOncallWriteHandler struct {
	input    chan somaOncallRequest
	shutdown chan bool
	conn     *sql.DB
	add_stmt *sql.Stmt
	upd_stmt *sql.Stmt
	del_stmt *sql.Stmt
}

func (w *somaOncallWriteHandler) run() {
	var err error

	log.Println("Prepare: oncall/add")
	w.add_stmt, err = w.conn.Prepare(`
INSERT INTO inventory.oncall_duty_teams (
	oncall_duty_id,
	oncall_duty_name,
	oncall_duty_phone_number)
SELECT $1, $2, $3 WHERE NOT EXISTS (
	SELECT oncall_duty_id
	FROM inventory.oncall_duty_teams
	WHERE oncall_duty_id = $4
	OR oncall_duty_name = $5
	OR oncall_duty_phone_number = $6);`)
	if err != nil {
		log.Fatal(err)
	}
	defer w.add_stmt.Close()

	log.Println("Prepare: oncall/upd")
	w.upd_stmt, err = w.conn.Prepare(`
UPDATE inventory.oncall_duty_teams
SET oncall_duty_name = CASE WHEN $1::varchar IS NOT NULL THEN $2::varchar ELSE oncall_duty_name END,
    oncall_duty_phone_number = CASE WHEN $3::numeric IS NOT NULL THEN $4::numeric ELSE oncall_duty_phone_number END
WHERE oncall_duty_id = $5;`)
	if err != nil {
		log.Fatal(err)
	}
	defer w.upd_stmt.Close()

	log.Println("Prepare: oncall/del")
	w.del_stmt, err = w.conn.Prepare(`
DELETE FROM inventory.oncall_duty_teams
WHERE oncall_duty_id = $1;`)
	if err != nil {
		log.Fatal(err)
	}
	defer w.del_stmt.Close()

runloop:
	for {
		select {
		case <-w.shutdown:
			break runloop
		case req := <-w.input:
			w.process(&req)
		}
	}
}

func (w *somaOncallWriteHandler) process(q *somaOncallRequest) {
	var res sql.Result
	var err error
	result := make([]somaOncallResult, 0)

	switch q.action {
	case "add":
		log.Printf("R: oncall/add for %s", q.oncall.Name)
		id := uuid.NewV4()
		res, err = w.add_stmt.Exec(
			id.String(),
			q.oncall.Name,
			q.oncall.Number,
			id.String(),
			q.oncall.Name,
			q.oncall.Number,
		)
	case "update":
		log.Printf("R: oncall/update for %s", q.oncall.Id)
		// our update statement uses NULL to check which of the values
		// should be updated
		var name sql.NullString
		if q.oncall.Name == "" {
			name = sql.NullString{String: "", Valid: false}
		} else {
			name = sql.NullString{String: q.oncall.Name, Valid: true}
		}

		var n int // ensure err not redeclared in if block
		var number sql.NullInt64
		if q.oncall.Number != "" {
			n, err = strconv.Atoi(q.oncall.Number)
			if err != nil {
				break
			}
			number = sql.NullInt64{Int64: int64(n), Valid: true}
		} else {
			number = sql.NullInt64{Int64: 0, Valid: false}
		}
		res, err = w.upd_stmt.Exec(
			name,
			name,
			number,
			number,
			q.oncall.Id,
		)
	case "delete":
		log.Printf("R: oncall/del for %s", q.oncall.Id)
		res, err = w.del_stmt.Exec(
			q.oncall.Id,
		)
	default:
		log.Printf("R: unimplemented oncall/%s", q.action)
		result = append(result, somaOncallResult{
			rErr: errors.New("not implemented"),
		})
		q.reply <- result
		return
	}
	if err != nil {
		result = append(result, somaOncallResult{
			rErr: err,
		})
		q.reply <- result
		return
	}

	rowCnt, _ := res.RowsAffected()
	switch {
	case rowCnt == 0:
		result = append(result, somaOncallResult{
			lErr: errors.New("No rows affected"),
		})
	case rowCnt > 1:
		result = append(result, somaOncallResult{
			lErr: fmt.Errorf("Too many rows affected: %d", rowCnt),
		})
	default:
		result = append(result, somaOncallResult{
			oncall: q.oncall,
		})
	}
	q.reply <- result
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>oncall/add: return id of team<commit_after>package main

import (
	"database/sql"
	"errors"
	"fmt"
	"log"
	"strconv"

	"github.com/satori/go.uuid"
)

type somaOncallRequest struct {
	action string
	oncall somaproto.ProtoOncall
	reply  chan []somaOncallResult
}

type somaOncallResult struct {
	rErr   error
	lErr   error
	oncall somaproto.ProtoOncall
}

/* Read Access
 *
 */
type somaOncallReadHandler struct {
	input     chan somaOncallRequest
	shutdown  chan bool
	conn      *sql.DB
	list_stmt *sql.Stmt
	show_stmt *sql.Stmt
}

func (r *somaOncallReadHandler) run() {
	var err error

	r.list_stmt, err = r.conn.Prepare(`
SELECT oncall_duty_id, oncall_duty_name
FROM inventory.oncall_duty_teams;`)
	if err != nil {
		log.Fatal(err)
	}

	r.show_stmt, err = r.conn.Prepare(`
SELECT oncall_duty_id, oncall_duty_name, oncall_duty_phone_number
FROM inventory.oncall_duty_teams
WHERE oncall_duty_id = $1;`)
	if err != nil {
		log.Fatal(err)
	}

runloop:
	for {
		select {
		case <-r.shutdown:
			break runloop
		case req := <-r.input:
			go func() {
				r.process(&req)
			}()
		}
	}
}

func (r *somaOncallReadHandler) process(q *somaOncallRequest) {
	var oncallId, oncallName string
	var oncallNumber int
	var rows *sql.Rows
	var err error
	result := make([]somaOncallResult, 0)

	switch q.action {
	case "list":
		log.Printf("R: oncall/list")
		rows, err = r.list_stmt.Query()
		defer rows.Close()
		if err != nil {
			result = append(result, somaOncallResult{
				rErr: err,
			})
			q.reply <- result
			return
		}

		for rows.Next() {
			err := rows.Scan(&oncallId, &oncallName)
			if err != nil {
				result = append(result, somaOncallResult{
					lErr: err,
				})
				err = nil
				continue
			}
			result = append(result, somaOncallResult{
				oncall: somaproto.ProtoOncall{
					Id:   oncallId,
					Name: oncallName,
				},
			})
		}
	case "show":
		log.Printf("R: oncall/show for %s", q.oncall.Id)
		err = r.show_stmt.QueryRow(q.oncall.Id).Scan(&oncallId, &oncallName, &oncallNumber)
		if err != nil {
			if err.Error() != "sql: no rows in result set" {
				result = append(result, somaOncallResult{
					rErr: err,
				})
			}
			q.reply <- result
			return
		}

		result = append(result, somaOncallResult{
			oncall: somaproto.ProtoOncall{
				Id:     oncallId,
				Name:   oncallName,
				Number: strconv.Itoa(oncallNumber),
			},
		})
	default:
		result = append(result, somaOncallResult{
			rErr: errors.New("not implemented"),
		})
	}
	q.reply <- result
}

/* Write Access
 *
 */
type somaOncallWriteHandler struct {
	input    chan somaOncallRequest
	shutdown chan bool
	conn     *sql.DB
	add_stmt *sql.Stmt
	upd_stmt *sql.Stmt
	del_stmt *sql.Stmt
}

func (w *somaOncallWriteHandler) run() {
	var err error

	log.Println("Prepare: oncall/add")
	w.add_stmt, err = w.conn.Prepare(`
INSERT INTO inventory.oncall_duty_teams (
	oncall_duty_id,
	oncall_duty_name,
	oncall_duty_phone_number)
SELECT $1, $2, $3 WHERE NOT EXISTS (
	SELECT oncall_duty_id
	FROM inventory.oncall_duty_teams
	WHERE oncall_duty_id = $4
	OR oncall_duty_name = $5
	OR oncall_duty_phone_number = $6);`)
	if err != nil {
		log.Fatal(err)
	}
	defer w.add_stmt.Close()

	log.Println("Prepare: oncall/upd")
	w.upd_stmt, err = w.conn.Prepare(`
UPDATE inventory.oncall_duty_teams
SET oncall_duty_name = CASE WHEN $1::varchar IS NOT NULL THEN $2::varchar ELSE oncall_duty_name END,
    oncall_duty_phone_number = CASE WHEN $3::numeric IS NOT NULL THEN $4::numeric ELSE oncall_duty_phone_number END
WHERE oncall_duty_id = $5;`)
	if err != nil {
		log.Fatal(err)
	}
	defer w.upd_stmt.Close()

	log.Println("Prepare: oncall/del")
	w.del_stmt, err = w.conn.Prepare(`
DELETE FROM inventory.oncall_duty_teams
WHERE oncall_duty_id = $1;`)
	if err != nil {
		log.Fatal(err)
	}
	defer w.del_stmt.Close()

runloop:
	for {
		select {
		case <-w.shutdown:
			break runloop
		case req := <-w.input:
			w.process(&req)
		}
	}
}

func (w *somaOncallWriteHandler) process(q *somaOncallRequest) {
	var res sql.Result
	var err error
	result := make([]somaOncallResult, 0)

	switch q.action {
	case "add":
		log.Printf("R: oncall/add for %s", q.oncall.Name)
		id := uuid.NewV4()
		res, err = w.add_stmt.Exec(
			id.String(),
			q.oncall.Name,
			q.oncall.Number,
			id.String(),
			q.oncall.Name,
			q.oncall.Number,
		)
		q.oncall.Id = id.String()
	case "update":
		log.Printf("R: oncall/update for %s", q.oncall.Id)
		// our update statement uses NULL to check which of the values
		// should be updated
		var name sql.NullString
		if q.oncall.Name == "" {
			name = sql.NullString{String: "", Valid: false}
		} else {
			name = sql.NullString{String: q.oncall.Name, Valid: true}
		}

		var n int // ensure err not redeclared in if block
		var number sql.NullInt64
		if q.oncall.Number != "" {
			n, err = strconv.Atoi(q.oncall.Number)
			if err != nil {
				break
			}
			number = sql.NullInt64{Int64: int64(n), Valid: true}
		} else {
			number = sql.NullInt64{Int64: 0, Valid: false}
		}
		res, err = w.upd_stmt.Exec(
			name,
			name,
			number,
			number,
			q.oncall.Id,
		)
	case "delete":
		log.Printf("R: oncall/del for %s", q.oncall.Id)
		res, err = w.del_stmt.Exec(
			q.oncall.Id,
		)
	default:
		log.Printf("R: unimplemented oncall/%s", q.action)
		result = append(result, somaOncallResult{
			rErr: errors.New("not implemented"),
		})
		q.reply <- result
		return
	}
	if err != nil {
		result = append(result, somaOncallResult{
			rErr: err,
		})
		q.reply <- result
		return
	}

	rowCnt, _ := res.RowsAffected()
	switch {
	case rowCnt == 0:
		result = append(result, somaOncallResult{
			lErr: errors.New("No rows affected"),
		})
	case rowCnt > 1:
		result = append(result, somaOncallResult{
			lErr: fmt.Errorf("Too many rows affected: %d", rowCnt),
		})
	default:
		result = append(result, somaOncallResult{
			oncall: q.oncall,
		})
	}
	q.reply <- result
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>


<commit_before>package cbft

import (
	"encoding/json"
)

// FtsSort represents an FTS sorting for a search query.
type FtsSort interface {
}

type ftsSortBase struct {
	options map[string]interface{}
}

func newFtsSortBase() ftsSortBase {
	return ftsSortBase{
		options: make(map[string]interface{}),
	}
}

// MarshalJSON marshal's this query to JSON for the FTS REST API.
func (q ftsSortBase) MarshalJSON() ([]byte, error) {
	return json.Marshal(q.options)
}

// SearchSortScore represents a FTS score sort.
type SearchSortScore struct {
	ftsSortBase
}

// NewSearchSortScore creates a new SearchSortScore.
func NewSearchSortScore() *SearchSortScore {
	q := &SearchSortScore{newFtsSortBase()}
	q.options["by"] = "score"
	return q
}

// Descending specifies the ordering of the results.
func (q *SearchSortScore) Descending(descending bool) *SearchSortScore {
	q.options["descending"] = descending
	return q
}

// SearchSortId represents a FTS Document ID sort.
type SearchSortId struct {
	ftsSortBase
}

// NewSearchSortId creates a new SearchSortScore.
func NewSearchSortId() *SearchSortId {
	q := &SearchSortId{newFtsSortBase()}
	q.options["by"] = "id"
	return q
}

// Descending specifies the ordering of the results.
func (q *SearchSortId) Descending(descending bool) *SearchSortId {
	q.options["descending"] = descending
	return q
}

// SearchSortField represents a FTS field sort.
type SearchSortField struct {
	ftsSortBase
}

// NewSearchSortField creates a new SearchSortField.
func NewSearchSortField(field string) *SearchSortField {
	q := &SearchSortField{newFtsSortBase()}
	q.options["by"] = "field"
	q.options["field"] = field
	return q
}

// Type allows you to specify the FTS field sort type.
func (q *SearchSortField) Type(value string) *SearchSortField {
	q.options["type"] = value
	return q
}

// Mode allows you to specify the FTS field sort mode.
func (q *SearchSortField) Mode(mode string) *SearchSortField {
	q.options["mode"] = mode
	return q
}

// Missing allows you to specify the FTS field sort missing behaviour.
func (q *SearchSortField) Missing(missing string) *SearchSortField {
	q.options["missing"] = missing
	return q
}

// Descending specifies the ordering of the results.
func (q *SearchSortField) Descending(descending bool) *SearchSortField {
	q.options["descending"] = descending
	return q
}

// SearchSortGeoDistance represents a FTS geo sort.
type SearchSortGeoDistance struct {
	ftsSortBase
}

// NewSearchSortGeoDistance creates a new SearchSortGeoDistance.
func NewSearchSortGeoDistance(field string, lat, lon float64) *SearchSortGeoDistance {
	q := &SearchSortGeoDistance{newFtsSortBase()}
	q.options["by"] = "geo_distance"
	q.options["field"] = field
	q.options["location"] = []float64{lon, lat}
	return q
}

// Unit specifies the unit used for sorting
func (q *SearchSortGeoDistance) Unit(unit string) *SearchSortGeoDistance {
	q.options["unit"] = unit
	return q
}

// Descending specifies the ordering of the results.
func (q *SearchSortGeoDistance) Descending(descending bool) *SearchSortGeoDistance {
	q.options["descending"] = descending
	return q
}
<commit_msg>GOCB-235: Change Search query sorting order from descending to desc<commit_after>package cbft

import (
	"encoding/json"
)

// FtsSort represents an FTS sorting for a search query.
type FtsSort interface {
}

type ftsSortBase struct {
	options map[string]interface{}
}

func newFtsSortBase() ftsSortBase {
	return ftsSortBase{
		options: make(map[string]interface{}),
	}
}

// MarshalJSON marshal's this query to JSON for the FTS REST API.
func (q ftsSortBase) MarshalJSON() ([]byte, error) {
	return json.Marshal(q.options)
}

// SearchSortScore represents a FTS score sort.
type SearchSortScore struct {
	ftsSortBase
}

// NewSearchSortScore creates a new SearchSortScore.
func NewSearchSortScore() *SearchSortScore {
	q := &SearchSortScore{newFtsSortBase()}
	q.options["by"] = "score"
	return q
}

// Descending specifies the ordering of the results.
func (q *SearchSortScore) Descending(descending bool) *SearchSortScore {
	q.options["desc"] = descending
	return q
}

// SearchSortId represents a FTS Document ID sort.
type SearchSortId struct {
	ftsSortBase
}

// NewSearchSortId creates a new SearchSortScore.
func NewSearchSortId() *SearchSortId {
	q := &SearchSortId{newFtsSortBase()}
	q.options["by"] = "id"
	return q
}

// Descending specifies the ordering of the results.
func (q *SearchSortId) Descending(descending bool) *SearchSortId {
	q.options["desc"] = descending
	return q
}

// SearchSortField represents a FTS field sort.
type SearchSortField struct {
	ftsSortBase
}

// NewSearchSortField creates a new SearchSortField.
func NewSearchSortField(field string) *SearchSortField {
	q := &SearchSortField{newFtsSortBase()}
	q.options["by"] = "field"
	q.options["field"] = field
	return q
}

// Type allows you to specify the FTS field sort type.
func (q *SearchSortField) Type(value string) *SearchSortField {
	q.options["type"] = value
	return q
}

// Mode allows you to specify the FTS field sort mode.
func (q *SearchSortField) Mode(mode string) *SearchSortField {
	q.options["mode"] = mode
	return q
}

// Missing allows you to specify the FTS field sort missing behaviour.
func (q *SearchSortField) Missing(missing string) *SearchSortField {
	q.options["missing"] = missing
	return q
}

// Descending specifies the ordering of the results.
func (q *SearchSortField) Descending(descending bool) *SearchSortField {
	q.options["desc"] = descending
	return q
}

// SearchSortGeoDistance represents a FTS geo sort.
type SearchSortGeoDistance struct {
	ftsSortBase
}

// NewSearchSortGeoDistance creates a new SearchSortGeoDistance.
func NewSearchSortGeoDistance(field string, lat, lon float64) *SearchSortGeoDistance {
	q := &SearchSortGeoDistance{newFtsSortBase()}
	q.options["by"] = "geo_distance"
	q.options["field"] = field
	q.options["location"] = []float64{lon, lat}
	return q
}

// Unit specifies the unit used for sorting
func (q *SearchSortGeoDistance) Unit(unit string) *SearchSortGeoDistance {
	q.options["unit"] = unit
	return q
}

// Descending specifies the ordering of the results.
func (q *SearchSortGeoDistance) Descending(descending bool) *SearchSortGeoDistance {
	q.options["desc"] = descending
	return q
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"strconv"

	"github.com/hashicorp/terraform/flatmap"
	"github.com/hashicorp/terraform/helper/config"
	"github.com/hashicorp/terraform/helper/diff"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/goamz/elb"
)

func resource_aws_elb_create(
	s *terraform.InstanceState,
	d *terraform.InstanceDiff,
	meta interface{}) (*terraform.InstanceState, error) {
	p := meta.(*ResourceProvider)
	elbconn := p.elbconn

	// Merge the diff into the state so that we have all the attributes
	// properly.
	rs := s.MergeDiff(d)

	// The name specified for the ELB. This is also our unique ID
	// we save to state if the creation is successful (amazon verifies
	// it is unique)
	elbName := rs.Attributes["name"]

	// Expand the "listener" array to goamz compat []elb.Listener
	v := flatmap.Expand(rs.Attributes, "listener").([]interface{})
	listeners, err := expandListeners(v)
	if err != nil {
		return nil, err
	}

	// Provision the elb
	elbOpts := &elb.CreateLoadBalancer{
		LoadBalancerName: elbName,
		Listeners:        listeners,
	}

	if rs.Attributes["internal"] == "true" {
		elbOpts.Internal = true
	}

	if _, ok := rs.Attributes["availability_zones.#"]; ok {
		v = flatmap.Expand(rs.Attributes, "availability_zones").([]interface{})
		elbOpts.AvailZone = expandStringList(v)
	}

	if _, ok := rs.Attributes["security_groups.#"]; ok {
		v = flatmap.Expand(rs.Attributes, "security_groups").([]interface{})
		elbOpts.SecurityGroups = expandStringList(v)
	}

	if _, ok := rs.Attributes["subnets.#"]; ok {
		v = flatmap.Expand(rs.Attributes, "subnets").([]interface{})
		elbOpts.Subnets = expandStringList(v)
	}

	log.Printf("[DEBUG] ELB create configuration: %#v", elbOpts)

	_, err = elbconn.CreateLoadBalancer(elbOpts)
	if err != nil {
		return nil, fmt.Errorf("Error creating ELB: %s", err)
	}

	// Assign the elb's unique identifier for use later
	rs.ID = elbName
	log.Printf("[INFO] ELB ID: %s", elbName)

	if _, ok := rs.Attributes["instances.#"]; ok {
		// If we have any instances, we need to register them
		v = flatmap.Expand(rs.Attributes, "instances").([]interface{})
		instances := expandStringList(v)

		if len(instances) > 0 {
			registerInstancesOpts := elb.RegisterInstancesWithLoadBalancer{
				LoadBalancerName: elbName,
				Instances:        instances,
			}

			_, err := elbconn.RegisterInstancesWithLoadBalancer(&registerInstancesOpts)

			if err != nil {
				return rs, fmt.Errorf("Failure registering instances: %s", err)
			}
		}
	}

	if _, ok := rs.Attributes["health_check.#"]; ok {
		v := flatmap.Expand(rs.Attributes, "health_check").([]interface{})
		health_check := v[0].(map[string]interface{})
		healthyThreshold, err := strconv.ParseInt(health_check["healthy_threshold"].(string), 0, 0)
		unhealthyThreshold, err := strconv.ParseInt(health_check["unhealthy_threshold"].(string), 0, 0)
		interval, err := strconv.ParseInt(health_check["interval"].(string), 0, 0)
		timeout, err := strconv.ParseInt(health_check["timeout"].(string), 0, 0)

		if err != nil {
			return nil, err
		}

		configureHealthCheckOpts := elb.ConfigureHealthCheck{
			LoadBalancerName: elbName,
			Check: elb.HealthCheck{
				HealthyThreshold:   healthyThreshold,
				UnhealthyThreshold: unhealthyThreshold,
				Interval:           interval,
				Target:             health_check["target"].(string),
				Timeout:            timeout,
			},
		}

		_, err = elbconn.ConfigureHealthCheck(&configureHealthCheckOpts)
		if err != nil {
			return rs, fmt.Errorf("Failure configuring health check: %s", err)
		}
	}

	loadBalancer, err := resource_aws_elb_retrieve_balancer(rs.ID, elbconn)
	if err != nil {
		return rs, err
	}

	return resource_aws_elb_update_state(rs, loadBalancer)
}

func resource_aws_elb_update(
	s *terraform.InstanceState,
	d *terraform.InstanceDiff,
	meta interface{}) (*terraform.InstanceState, error) {
	p := meta.(*ResourceProvider)
	elbconn := p.elbconn

	rs := s.MergeDiff(d)

	// If we currently have instances, or did have instances,
	// we want to figure out what to add and remove from the load
	// balancer
	if attr, ok := d.Attributes["instances.#"]; ok && attr.Old != "" {
		// The new state of instances merged with the diff
		mergedInstances := expandStringList(flatmap.Expand(
			rs.Attributes, "instances").([]interface{}))

		// The state before the diff merge
		previousInstances := expandStringList(flatmap.Expand(
			s.Attributes, "instances").([]interface{}))

		// keep track of what instances we are removing, and which
		// we are adding
		var toRemove []string
		var toAdd []string

		for _, instanceId := range mergedInstances {
			for _, prevId := range previousInstances {
				// If the merged instance ID existed
				// previously, we don't have to do anything
				if instanceId == prevId {
					continue
					// Otherwise, we need to add it to the load balancer
				} else {
					toAdd = append(toAdd, instanceId)
				}
			}
		}

		for i, instanceId := range toAdd {
			for _, prevId := range previousInstances {
				// If the instance ID we are adding existed
				// previously, we want to not add it, but rather remove
				// it
				if instanceId == prevId {
					toRemove = append(toRemove, instanceId)
					toAdd = append(toAdd[:i], toAdd[i+1:]...)
					// Otherwise, we continue adding it to the ELB
				} else {
					continue
				}
			}
		}

		if len(toAdd) > 0 {
			registerInstancesOpts := elb.RegisterInstancesWithLoadBalancer{
				LoadBalancerName: rs.ID,
				Instances:        toAdd,
			}

			_, err := elbconn.RegisterInstancesWithLoadBalancer(&registerInstancesOpts)

			if err != nil {
				return s, fmt.Errorf("Failure registering instances: %s", err)
			}
		}

		if len(toRemove) > 0 {
			deRegisterInstancesOpts := elb.DeregisterInstancesFromLoadBalancer{
				LoadBalancerName: rs.ID,
				Instances:        toRemove,
			}

			_, err := elbconn.DeregisterInstancesFromLoadBalancer(&deRegisterInstancesOpts)

			if err != nil {
				return s, fmt.Errorf("Failure deregistering instances: %s", err)
			}
		}
	}

	loadBalancer, err := resource_aws_elb_retrieve_balancer(rs.ID, elbconn)

	if err != nil {
		return s, err
	}

	return resource_aws_elb_update_state(rs, loadBalancer)
}

func resource_aws_elb_destroy(
	s *terraform.InstanceState,
	meta interface{}) error {
	p := meta.(*ResourceProvider)
	elbconn := p.elbconn

	log.Printf("[INFO] Deleting ELB: %s", s.ID)

	// Destroy the load balancer
	deleteElbOpts := elb.DeleteLoadBalancer{
		LoadBalancerName: s.ID,
	}
	_, err := elbconn.DeleteLoadBalancer(&deleteElbOpts)

	if err != nil {
		return fmt.Errorf("Error deleting ELB: %s", err)
	}

	return nil
}

func resource_aws_elb_refresh(
	s *terraform.InstanceState,
	meta interface{}) (*terraform.InstanceState, error) {
	p := meta.(*ResourceProvider)
	elbconn := p.elbconn

	loadBalancer, err := resource_aws_elb_retrieve_balancer(s.ID, elbconn)
	if err != nil {
		return nil, err
	}

	return resource_aws_elb_update_state(s, loadBalancer)
}

func resource_aws_elb_diff(
	s *terraform.InstanceState,
	c *terraform.ResourceConfig,
	meta interface{}) (*terraform.InstanceDiff, error) {

	b := &diff.ResourceBuilder{
		Attrs: map[string]diff.AttrType{
			"name":              diff.AttrTypeCreate,
			"availability_zone": diff.AttrTypeCreate,
			"security_groups":   diff.AttrTypeCreate, // TODO could be AttrTypeUpdate
			"subnets":           diff.AttrTypeCreate, // TODO could be AttrTypeUpdate
			"listener":          diff.AttrTypeCreate,
			"instances":         diff.AttrTypeUpdate,
			"health_check":      diff.AttrTypeCreate,
			"internal":          diff.AttrTypeCreate,
		},

		ComputedAttrs: []string{
			"dns_name",
		},
	}

	return b.Diff(s, c)
}

func resource_aws_elb_update_state(
	s *terraform.InstanceState,
	balancer *elb.LoadBalancer) (*terraform.InstanceState, error) {

	s.Attributes["name"] = balancer.LoadBalancerName
	s.Attributes["dns_name"] = balancer.DNSName

	// Flatten our group values
	toFlatten := make(map[string]interface{})

	if len(balancer.Instances) > 0 && balancer.Instances[0].InstanceId != "" {
		toFlatten["instances"] = flattenInstances(balancer.Instances)
	}

	if len(balancer.SecurityGroups) > 0 && balancer.SecurityGroups[0] != "" {
		toFlatten["security_groups"] = balancer.SecurityGroups
	}

	if len(balancer.Subnets) > 0 && balancer.Subnets[0] != "" {
		toFlatten["subnets"] = balancer.Subnets
	}

	// There's only one health check, so save that to state as we
	// currently can
	if balancer.HealthCheck.Target != "" {
		toFlatten["health_check"] = flattenHealthCheck(balancer.HealthCheck)
	}

	for k, v := range flatmap.Flatten(toFlatten) {
		s.Attributes[k] = v
	}

	return s, nil
}

// retrieves an ELB by its ID
func resource_aws_elb_retrieve_balancer(id string, elbconn *elb.ELB) (*elb.LoadBalancer, error) {
	describeElbOpts := &elb.DescribeLoadBalancer{
		Names: []string{id},
	}

	// Retrieve the ELB properties for updating the state
	describeResp, err := elbconn.DescribeLoadBalancers(describeElbOpts)
	if err != nil {
		return nil, fmt.Errorf("Error retrieving ELB: %s", err)
	}

	loadBalancer := describeResp.LoadBalancers[0]

	// Verify AWS returned our ELB
	if len(describeResp.LoadBalancers) != 1 ||
		describeResp.LoadBalancers[0].LoadBalancerName != id {
		if err != nil {
			return nil, fmt.Errorf("Unable to find ELB: %#v", describeResp.LoadBalancers)
		}
	}

	return &loadBalancer, nil
}

func resource_aws_elb_validation() *config.Validator {
	return &config.Validator{
		Required: []string{
			"name",
			"listener.*",
			"listener.*.instance_port",
			"listener.*.instance_protocol",
			"listener.*.lb_port",
			"listener.*.lb_protocol",
		},
		Optional: []string{
			"instances.*",
			"internal",
			"availability_zones.*",
			"security_groups.*",
			"subnets.*",
			"health_check.#",
			"health_check.0.healthy_threshold",
			"health_check.0.unhealthy_threshold",
			"health_check.0.interval",
			"health_check.0.target",
			"health_check.0.timeout",
		},
	}
}
<commit_msg>providers/aws: read internal for ELB<commit_after>package aws

import (
	"fmt"
	"log"
	"strconv"

	"github.com/hashicorp/terraform/flatmap"
	"github.com/hashicorp/terraform/helper/config"
	"github.com/hashicorp/terraform/helper/diff"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/goamz/elb"
)

func resource_aws_elb_create(
	s *terraform.InstanceState,
	d *terraform.InstanceDiff,
	meta interface{}) (*terraform.InstanceState, error) {
	p := meta.(*ResourceProvider)
	elbconn := p.elbconn

	// Merge the diff into the state so that we have all the attributes
	// properly.
	rs := s.MergeDiff(d)

	// The name specified for the ELB. This is also our unique ID
	// we save to state if the creation is successful (amazon verifies
	// it is unique)
	elbName := rs.Attributes["name"]

	// Expand the "listener" array to goamz compat []elb.Listener
	v := flatmap.Expand(rs.Attributes, "listener").([]interface{})
	listeners, err := expandListeners(v)
	if err != nil {
		return nil, err
	}

	// Provision the elb
	elbOpts := &elb.CreateLoadBalancer{
		LoadBalancerName: elbName,
		Listeners:        listeners,
	}

	if rs.Attributes["internal"] == "true" {
		elbOpts.Internal = true
	}

	if _, ok := rs.Attributes["availability_zones.#"]; ok {
		v = flatmap.Expand(rs.Attributes, "availability_zones").([]interface{})
		elbOpts.AvailZone = expandStringList(v)
	}

	if _, ok := rs.Attributes["security_groups.#"]; ok {
		v = flatmap.Expand(rs.Attributes, "security_groups").([]interface{})
		elbOpts.SecurityGroups = expandStringList(v)
	}

	if _, ok := rs.Attributes["subnets.#"]; ok {
		v = flatmap.Expand(rs.Attributes, "subnets").([]interface{})
		elbOpts.Subnets = expandStringList(v)
	}

	log.Printf("[DEBUG] ELB create configuration: %#v", elbOpts)

	_, err = elbconn.CreateLoadBalancer(elbOpts)
	if err != nil {
		return nil, fmt.Errorf("Error creating ELB: %s", err)
	}

	// Assign the elb's unique identifier for use later
	rs.ID = elbName
	log.Printf("[INFO] ELB ID: %s", elbName)

	if _, ok := rs.Attributes["instances.#"]; ok {
		// If we have any instances, we need to register them
		v = flatmap.Expand(rs.Attributes, "instances").([]interface{})
		instances := expandStringList(v)

		if len(instances) > 0 {
			registerInstancesOpts := elb.RegisterInstancesWithLoadBalancer{
				LoadBalancerName: elbName,
				Instances:        instances,
			}

			_, err := elbconn.RegisterInstancesWithLoadBalancer(&registerInstancesOpts)

			if err != nil {
				return rs, fmt.Errorf("Failure registering instances: %s", err)
			}
		}
	}

	if _, ok := rs.Attributes["health_check.#"]; ok {
		v := flatmap.Expand(rs.Attributes, "health_check").([]interface{})
		health_check := v[0].(map[string]interface{})
		healthyThreshold, err := strconv.ParseInt(health_check["healthy_threshold"].(string), 0, 0)
		unhealthyThreshold, err := strconv.ParseInt(health_check["unhealthy_threshold"].(string), 0, 0)
		interval, err := strconv.ParseInt(health_check["interval"].(string), 0, 0)
		timeout, err := strconv.ParseInt(health_check["timeout"].(string), 0, 0)

		if err != nil {
			return nil, err
		}

		configureHealthCheckOpts := elb.ConfigureHealthCheck{
			LoadBalancerName: elbName,
			Check: elb.HealthCheck{
				HealthyThreshold:   healthyThreshold,
				UnhealthyThreshold: unhealthyThreshold,
				Interval:           interval,
				Target:             health_check["target"].(string),
				Timeout:            timeout,
			},
		}

		_, err = elbconn.ConfigureHealthCheck(&configureHealthCheckOpts)
		if err != nil {
			return rs, fmt.Errorf("Failure configuring health check: %s", err)
		}
	}

	loadBalancer, err := resource_aws_elb_retrieve_balancer(rs.ID, elbconn)
	if err != nil {
		return rs, err
	}

	return resource_aws_elb_update_state(rs, loadBalancer)
}

func resource_aws_elb_update(
	s *terraform.InstanceState,
	d *terraform.InstanceDiff,
	meta interface{}) (*terraform.InstanceState, error) {
	p := meta.(*ResourceProvider)
	elbconn := p.elbconn

	rs := s.MergeDiff(d)

	// If we currently have instances, or did have instances,
	// we want to figure out what to add and remove from the load
	// balancer
	if attr, ok := d.Attributes["instances.#"]; ok && attr.Old != "" {
		// The new state of instances merged with the diff
		mergedInstances := expandStringList(flatmap.Expand(
			rs.Attributes, "instances").([]interface{}))

		// The state before the diff merge
		previousInstances := expandStringList(flatmap.Expand(
			s.Attributes, "instances").([]interface{}))

		// keep track of what instances we are removing, and which
		// we are adding
		var toRemove []string
		var toAdd []string

		for _, instanceId := range mergedInstances {
			for _, prevId := range previousInstances {
				// If the merged instance ID existed
				// previously, we don't have to do anything
				if instanceId == prevId {
					continue
					// Otherwise, we need to add it to the load balancer
				} else {
					toAdd = append(toAdd, instanceId)
				}
			}
		}

		for i, instanceId := range toAdd {
			for _, prevId := range previousInstances {
				// If the instance ID we are adding existed
				// previously, we want to not add it, but rather remove
				// it
				if instanceId == prevId {
					toRemove = append(toRemove, instanceId)
					toAdd = append(toAdd[:i], toAdd[i+1:]...)
					// Otherwise, we continue adding it to the ELB
				} else {
					continue
				}
			}
		}

		if len(toAdd) > 0 {
			registerInstancesOpts := elb.RegisterInstancesWithLoadBalancer{
				LoadBalancerName: rs.ID,
				Instances:        toAdd,
			}

			_, err := elbconn.RegisterInstancesWithLoadBalancer(&registerInstancesOpts)

			if err != nil {
				return s, fmt.Errorf("Failure registering instances: %s", err)
			}
		}

		if len(toRemove) > 0 {
			deRegisterInstancesOpts := elb.DeregisterInstancesFromLoadBalancer{
				LoadBalancerName: rs.ID,
				Instances:        toRemove,
			}

			_, err := elbconn.DeregisterInstancesFromLoadBalancer(&deRegisterInstancesOpts)

			if err != nil {
				return s, fmt.Errorf("Failure deregistering instances: %s", err)
			}
		}
	}

	loadBalancer, err := resource_aws_elb_retrieve_balancer(rs.ID, elbconn)

	if err != nil {
		return s, err
	}

	return resource_aws_elb_update_state(rs, loadBalancer)
}

func resource_aws_elb_destroy(
	s *terraform.InstanceState,
	meta interface{}) error {
	p := meta.(*ResourceProvider)
	elbconn := p.elbconn

	log.Printf("[INFO] Deleting ELB: %s", s.ID)

	// Destroy the load balancer
	deleteElbOpts := elb.DeleteLoadBalancer{
		LoadBalancerName: s.ID,
	}
	_, err := elbconn.DeleteLoadBalancer(&deleteElbOpts)

	if err != nil {
		return fmt.Errorf("Error deleting ELB: %s", err)
	}

	return nil
}

func resource_aws_elb_refresh(
	s *terraform.InstanceState,
	meta interface{}) (*terraform.InstanceState, error) {
	p := meta.(*ResourceProvider)
	elbconn := p.elbconn

	loadBalancer, err := resource_aws_elb_retrieve_balancer(s.ID, elbconn)
	if err != nil {
		return nil, err
	}

	return resource_aws_elb_update_state(s, loadBalancer)
}

func resource_aws_elb_diff(
	s *terraform.InstanceState,
	c *terraform.ResourceConfig,
	meta interface{}) (*terraform.InstanceDiff, error) {

	b := &diff.ResourceBuilder{
		Attrs: map[string]diff.AttrType{
			"name":              diff.AttrTypeCreate,
			"availability_zone": diff.AttrTypeCreate,
			"security_groups":   diff.AttrTypeCreate, // TODO could be AttrTypeUpdate
			"subnets":           diff.AttrTypeCreate, // TODO could be AttrTypeUpdate
			"listener":          diff.AttrTypeCreate,
			"instances":         diff.AttrTypeUpdate,
			"health_check":      diff.AttrTypeCreate,
			"internal":          diff.AttrTypeCreate,
		},

		ComputedAttrs: []string{
			"dns_name",
		},
	}

	return b.Diff(s, c)
}

func resource_aws_elb_update_state(
	s *terraform.InstanceState,
	balancer *elb.LoadBalancer) (*terraform.InstanceState, error) {

	s.Attributes["name"] = balancer.LoadBalancerName
	s.Attributes["dns_name"] = balancer.DNSName

	if balancer.Scheme == "internal" {
		s.Attributes["internal"] = "true"
	}

	// Flatten our group values
	toFlatten := make(map[string]interface{})

	if len(balancer.Instances) > 0 && balancer.Instances[0].InstanceId != "" {
		toFlatten["instances"] = flattenInstances(balancer.Instances)
	}

	if len(balancer.SecurityGroups) > 0 && balancer.SecurityGroups[0] != "" {
		toFlatten["security_groups"] = balancer.SecurityGroups
	}

	if len(balancer.Subnets) > 0 && balancer.Subnets[0] != "" {
		toFlatten["subnets"] = balancer.Subnets
	}

	// There's only one health check, so save that to state as we
	// currently can
	if balancer.HealthCheck.Target != "" {
		toFlatten["health_check"] = flattenHealthCheck(balancer.HealthCheck)
	}

	for k, v := range flatmap.Flatten(toFlatten) {
		s.Attributes[k] = v
	}

	return s, nil
}

// retrieves an ELB by its ID
func resource_aws_elb_retrieve_balancer(id string, elbconn *elb.ELB) (*elb.LoadBalancer, error) {
	describeElbOpts := &elb.DescribeLoadBalancer{
		Names: []string{id},
	}

	// Retrieve the ELB properties for updating the state
	describeResp, err := elbconn.DescribeLoadBalancers(describeElbOpts)
	if err != nil {
		return nil, fmt.Errorf("Error retrieving ELB: %s", err)
	}

	loadBalancer := describeResp.LoadBalancers[0]

	// Verify AWS returned our ELB
	if len(describeResp.LoadBalancers) != 1 ||
		describeResp.LoadBalancers[0].LoadBalancerName != id {
		if err != nil {
			return nil, fmt.Errorf("Unable to find ELB: %#v", describeResp.LoadBalancers)
		}
	}

	return &loadBalancer, nil
}

func resource_aws_elb_validation() *config.Validator {
	return &config.Validator{
		Required: []string{
			"name",
			"listener.*",
			"listener.*.instance_port",
			"listener.*.instance_protocol",
			"listener.*.lb_port",
			"listener.*.lb_protocol",
		},
		Optional: []string{
			"instances.*",
			"internal",
			"availability_zones.*",
			"security_groups.*",
			"subnets.*",
			"health_check.#",
			"health_check.0.healthy_threshold",
			"health_check.0.unhealthy_threshold",
			"health_check.0.interval",
			"health_check.0.target",
			"health_check.0.timeout",
		},
	}
}
<|endoftext|>