<commit_before>package aws

import (
	"log"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/servicediscovery"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/helper/validation"
)

func resourceAwsServiceDiscoveryService() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsServiceDiscoveryServiceCreate,
		Read:   resourceAwsServiceDiscoveryServiceRead,
		Update: resourceAwsServiceDiscoveryServiceUpdate,
		Delete: resourceAwsServiceDiscoveryServiceDelete,

		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"description": {
				Type:     schema.TypeString,
				Optional: true,
			},
			"dns_config": {
				Type:     schema.TypeList,
				Required: true,
				MaxItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"namespace_id": {
							Type:     schema.TypeString,
							Required: true,
							ForceNew: true,
						},
						"dns_records": {
							Type:     schema.TypeList,
							Required: true,
							Elem: &schema.Resource{
								Schema: map[string]*schema.Schema{
									"ttl": {
										Type:     schema.TypeInt,
										Required: true,
									},
									"type": {
										Type:     schema.TypeString,
										Required: true,
										ForceNew: true,
										ValidateFunc: validation.StringInSlice([]string{
											servicediscovery.RecordTypeSrv,
											servicediscovery.RecordTypeA,
											servicediscovery.RecordTypeAaaa,
											servicediscovery.RecordTypeCname,
										}, false),
									},
								},
							},
						},
						"routing_policy": {
							Type:     schema.TypeString,
							Optional: true,
							ForceNew: true,
							Default:  servicediscovery.RoutingPolicyMultivalue,
							ValidateFunc: validation.StringInSlice([]string{
								servicediscovery.RoutingPolicyMultivalue,
								servicediscovery.RoutingPolicyWeighted,
							}, false),
						},
					},
				},
			},
			"health_check_config": {
				Type:     schema.TypeList,
				Optional: true,
				MaxItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"failure_threshold": {
							Type:     schema.TypeInt,
							Optional: true,
						},
						"resource_path": {
							Type:     schema.TypeString,
							Optional: true,
						},
						"type": {
							Type:     schema.TypeString,
							Optional: true,
							ForceNew: true,
							ValidateFunc: validation.StringInSlice([]string{
								servicediscovery.HealthCheckTypeHttp,
								servicediscovery.HealthCheckTypeHttps,
								servicediscovery.HealthCheckTypeTcp,
							}, false),
						},
					},
				},
			},
			"health_check_custom_config": {
				Type:     schema.TypeList,
				Optional: true,
				ForceNew: true,
				MaxItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"failure_threshold": {
							Type:     schema.TypeInt,
							Optional: true,
							ForceNew: true,
						},
					},
				},
			},
			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func resourceAwsServiceDiscoveryServiceCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sdconn

	input := &servicediscovery.CreateServiceInput{
		Name:      aws.String(d.Get("name").(string)),
		DnsConfig: expandServiceDiscoveryDnsConfig(d.Get("dns_config").([]interface{})[0].(map[string]interface{})),
	}

	if v, ok := d.GetOk("description"); ok {
		input.Description = aws.String(v.(string))
	}

	hcconfig := d.Get("health_check_config").([]interface{})
	if len(hcconfig) > 0 {
		input.HealthCheckConfig = expandServiceDiscoveryHealthCheckConfig(hcconfig[0].(map[string]interface{}))
	}

	healthCustomConfig := d.Get("health_check_custom_config").([]interface{})
	if len(healthCustomConfig) > 0 {
		input.HealthCheckCustomConfig = expandServiceDiscoveryHealthCheckCustomConfig(healthCustomConfig[0].(map[string]interface{}))
	}

	resp, err := conn.CreateService(input)
	if err != nil {
		return err
	}

	d.SetId(*resp.Service.Id)
	d.Set("arn", resp.Service.Arn)
	return nil
}

func resourceAwsServiceDiscoveryServiceRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sdconn

	input := &servicediscovery.GetServiceInput{
		Id: aws.String(d.Id()),
	}

	resp, err := conn.GetService(input)
	if err != nil {
		if isAWSErr(err, servicediscovery.ErrCodeServiceNotFound, "") {
			log.Printf("[WARN] Service Discovery Service (%s) not found, removing from state", d.Id())
			d.SetId("")
			return nil
		}
		return err
	}

	service := resp.Service
	d.Set("arn", service.Arn)
	d.Set("name", service.Name)
	d.Set("description", service.Description)
	d.Set("dns_config", flattenServiceDiscoveryDnsConfig(service.DnsConfig))
	d.Set("health_check_config", flattenServiceDiscoveryHealthCheckConfig(service.HealthCheckConfig))
	d.Set("health_check_custom_config", flattenServiceDiscoveryHealthCheckCustomConfig(service.HealthCheckCustomConfig))
	return nil
}

func resourceAwsServiceDiscoveryServiceUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sdconn

	input := &servicediscovery.UpdateServiceInput{
		Id: aws.String(d.Id()),
	}

	sc := &servicediscovery.ServiceChange{
		DnsConfig: expandServiceDiscoveryDnsConfigChange(d.Get("dns_config").([]interface{})[0].(map[string]interface{})),
	}

	if d.HasChange("description") {
		sc.Description = aws.String(d.Get("description").(string))
	}
	if d.HasChange("health_check_config") {
		hcconfig := d.Get("health_check_config").([]interface{})
		sc.HealthCheckConfig = expandServiceDiscoveryHealthCheckConfig(hcconfig[0].(map[string]interface{}))
	}

	input.Service = sc

	resp, err := conn.UpdateService(input)
	if err != nil {
		return err
	}

	stateConf := &resource.StateChangeConf{
		Pending:    []string{servicediscovery.OperationStatusSubmitted, servicediscovery.OperationStatusPending},
		Target:     []string{servicediscovery.OperationStatusSuccess},
		Refresh:    servicediscoveryOperationRefreshStatusFunc(conn, *resp.OperationId),
		Timeout:    5 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, err = stateConf.WaitForState()
	if err != nil {
		return err
	}

	return resourceAwsServiceDiscoveryServiceRead(d, meta)
}

func resourceAwsServiceDiscoveryServiceDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sdconn

	input := &servicediscovery.DeleteServiceInput{
		Id: aws.String(d.Id()),
	}

	_, err := conn.DeleteService(input)
	return err
}

func expandServiceDiscoveryDnsConfig(configured map[string]interface{}) *servicediscovery.DnsConfig {
	result := &servicediscovery.DnsConfig{}

	result.NamespaceId = aws.String(configured["namespace_id"].(string))
	dnsRecords := configured["dns_records"].([]interface{})
	drs := make([]*servicediscovery.DnsRecord, len(dnsRecords))
	for i := range drs {
		raw := dnsRecords[i].(map[string]interface{})
		dr := &servicediscovery.DnsRecord{
			TTL:  aws.Int64(int64(raw["ttl"].(int))),
			Type: aws.String(raw["type"].(string)),
		}
		drs[i] = dr
	}
	result.DnsRecords = drs
	if v, ok := configured["routing_policy"]; ok && v != "" {
		result.RoutingPolicy = aws.String(v.(string))
	}

	return result
}

func flattenServiceDiscoveryDnsConfig(config *servicediscovery.DnsConfig) []map[string]interface{} {
	result := map[string]interface{}{}

	result["namespace_id"] = *config.NamespaceId
	result["routing_policy"] = *config.RoutingPolicy
	drs := make([]map[string]interface{}, 0)
	for _, v := range config.DnsRecords {
		dr := map[string]interface{}{}
		dr["ttl"] = *v.TTL
		dr["type"] = *v.Type
		drs = append(drs, dr)
	}
	result["dns_records"] = drs

	return []map[string]interface{}{result}
}

func expandServiceDiscoveryDnsConfigChange(configured map[string]interface{}) *servicediscovery.DnsConfigChange {
	result := &servicediscovery.DnsConfigChange{}

	dnsRecords := configured["dns_records"].([]interface{})
	drs := make([]*servicediscovery.DnsRecord, len(dnsRecords))
	for i := range drs {
		raw := dnsRecords[i].(map[string]interface{})
		dr := &servicediscovery.DnsRecord{
			TTL:  aws.Int64(int64(raw["ttl"].(int))),
			Type: aws.String(raw["type"].(string)),
		}
		drs[i] = dr
	}
	result.DnsRecords = drs

	return result
}

func expandServiceDiscoveryHealthCheckConfig(configured map[string]interface{}) *servicediscovery.HealthCheckConfig {
	if len(configured) < 1 {
		return nil
	}
	result := &servicediscovery.HealthCheckConfig{}

	if v, ok := configured["failure_threshold"]; ok && v.(int) != 0 {
		result.FailureThreshold = aws.Int64(int64(v.(int)))
	}
	if v, ok := configured["resource_path"]; ok && v.(string) != "" {
		result.ResourcePath = aws.String(v.(string))
	}
	if v, ok := configured["type"]; ok && v.(string) != "" {
		result.Type = aws.String(v.(string))
	}

	return result
}

func flattenServiceDiscoveryHealthCheckConfig(config *servicediscovery.HealthCheckConfig) []map[string]interface{} {
	if config == nil {
		return nil
	}
	result := map[string]interface{}{}

	if config.FailureThreshold != nil {
		result["failure_threshold"] = *config.FailureThreshold
	}
	if config.ResourcePath != nil {
		result["resource_path"] = *config.ResourcePath
	}
	if config.Type != nil {
		result["type"] = *config.Type
	}

	if len(result) < 1 {
		return nil
	}

	return []map[string]interface{}{result}
}

func expandServiceDiscoveryHealthCheckCustomConfig(configured map[string]interface{}) *servicediscovery.HealthCheckCustomConfig {
	if len(configured) < 1 {
		return nil
	}
	result := &servicediscovery.HealthCheckCustomConfig{}

	if v, ok := configured["failure_threshold"]; ok && v.(int) != 0 {
		result.FailureThreshold = aws.Int64(int64(v.(int)))
	}

	return result
}

func flattenServiceDiscoveryHealthCheckCustomConfig(config *servicediscovery.HealthCheckCustomConfig) []map[string]interface{} {
	if config == nil {
		return nil
	}
	result := map[string]interface{}{}

	if config.FailureThreshold != nil {
		result["failure_threshold"] = *config.FailureThreshold
	}

	if len(result) < 1 {
		return nil
	}

	return []map[string]interface{}{result}
}
<commit_msg>issue #7016 support http namespaces in service discovery<commit_after>package aws

import (
	"log"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/servicediscovery"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/helper/validation"
)

func resourceAwsServiceDiscoveryService() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsServiceDiscoveryServiceCreate,
		Read:   resourceAwsServiceDiscoveryServiceRead,
		Update: resourceAwsServiceDiscoveryServiceUpdate,
		Delete: resourceAwsServiceDiscoveryServiceDelete,

		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"description": {
				Type:     schema.TypeString,
				Optional: true,
			},
			"namespace_id": {
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},
			"dns_config": {
				Type:     schema.TypeList,
				Optional: true,
				MaxItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"namespace_id": {
							Type:     schema.TypeString,
							Required: true,
							ForceNew: true,
						},
						"dns_records": {
							Type:     schema.TypeList,
							Required: true,
							Elem: &schema.Resource{
								Schema: map[string]*schema.Schema{
									"ttl": {
										Type:     schema.TypeInt,
										Required: true,
									},
									"type": {
										Type:     schema.TypeString,
										Required: true,
										ForceNew: true,
										ValidateFunc: validation.StringInSlice([]string{
											servicediscovery.RecordTypeSrv,
											servicediscovery.RecordTypeA,
											servicediscovery.RecordTypeAaaa,
											servicediscovery.RecordTypeCname,
										}, false),
									},
								},
							},
						},
						"routing_policy": {
							Type:     schema.TypeString,
							Optional: true,
							ForceNew: true,
							Default:  servicediscovery.RoutingPolicyMultivalue,
							ValidateFunc: validation.StringInSlice([]string{
								servicediscovery.RoutingPolicyMultivalue,
								servicediscovery.RoutingPolicyWeighted,
							}, false),
						},
					},
				},
			},
			"health_check_config": {
				Type:     schema.TypeList,
				Optional: true,
				MaxItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"failure_threshold": {
							Type:     schema.TypeInt,
							Optional: true,
						},
						"resource_path": {
							Type:     schema.TypeString,
							Optional: true,
						},
						"type": {
							Type:     schema.TypeString,
							Optional: true,
							ForceNew: true,
							ValidateFunc: validation.StringInSlice([]string{
								servicediscovery.HealthCheckTypeHttp,
								servicediscovery.HealthCheckTypeHttps,
								servicediscovery.HealthCheckTypeTcp,
							}, false),
						},
					},
				},
			},
			"health_check_custom_config": {
				Type:     schema.TypeList,
				Optional: true,
				ForceNew: true,
				MaxItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"failure_threshold": {
							Type:     schema.TypeInt,
							Optional: true,
							ForceNew: true,
						},
					},
				},
			},
			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func resourceAwsServiceDiscoveryServiceCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sdconn

	input := &servicediscovery.CreateServiceInput{
		Name: aws.String(d.Get("name").(string)),
	}

	dnsConfig := d.Get("dns_config").([]interface{})
	if len(dnsConfig) > 0 {
		input.DnsConfig = expandServiceDiscoveryDnsConfig(dnsConfig[0].(map[string]interface{}))
	}

	if v, ok := d.GetOk("description"); ok {
		input.Description = aws.String(v.(string))
	}

	if v, ok := d.GetOk("namespace_id"); ok {
		input.NamespaceId = aws.String(v.(string))
	}

	hcconfig := d.Get("health_check_config").([]interface{})
	if len(hcconfig) > 0 {
		input.HealthCheckConfig = expandServiceDiscoveryHealthCheckConfig(hcconfig[0].(map[string]interface{}))
	}

	healthCustomConfig := d.Get("health_check_custom_config").([]interface{})
	if len(healthCustomConfig) > 0 {
		input.HealthCheckCustomConfig = expandServiceDiscoveryHealthCheckCustomConfig(healthCustomConfig[0].(map[string]interface{}))
	}

	resp, err := conn.CreateService(input)
	if err != nil {
		return err
	}

	d.SetId(*resp.Service.Id)
	d.Set("arn", resp.Service.Arn)
	return nil
}

func resourceAwsServiceDiscoveryServiceRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sdconn

	input := &servicediscovery.GetServiceInput{
		Id: aws.String(d.Id()),
	}

	resp, err := conn.GetService(input)
	if err != nil {
		if isAWSErr(err, servicediscovery.ErrCodeServiceNotFound, "") {
			log.Printf("[WARN] Service Discovery Service (%s) not found, removing from state", d.Id())
			d.SetId("")
			return nil
		}
		return err
	}

	service := resp.Service
	d.Set("arn", service.Arn)
	d.Set("name", service.Name)
	d.Set("description", service.Description)
	d.Set("namespace_id", service.NamespaceId)
	d.Set("dns_config", flattenServiceDiscoveryDnsConfig(service.DnsConfig))
	d.Set("health_check_config", flattenServiceDiscoveryHealthCheckConfig(service.HealthCheckConfig))
	d.Set("health_check_custom_config", flattenServiceDiscoveryHealthCheckCustomConfig(service.HealthCheckCustomConfig))
	return nil
}

func resourceAwsServiceDiscoveryServiceUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sdconn

	input := &servicediscovery.UpdateServiceInput{
		Id: aws.String(d.Id()),
	}

	sc := &servicediscovery.ServiceChange{}

	if d.HasChange("dns_config") {
		dnsConfig := d.Get("dns_config").([]interface{})
		sc.DnsConfig = expandServiceDiscoveryDnsConfigChange(dnsConfig[0].(map[string]interface{}))
	}

	if d.HasChange("description") {
		sc.Description = aws.String(d.Get("description").(string))
	}

	if d.HasChange("health_check_config") {
		hcconfig := d.Get("health_check_config").([]interface{})
		sc.HealthCheckConfig = expandServiceDiscoveryHealthCheckConfig(hcconfig[0].(map[string]interface{}))
	}

	input.Service = sc

	resp, err := conn.UpdateService(input)
	if err != nil {
		return err
	}

	stateConf := &resource.StateChangeConf{
		Pending:    []string{servicediscovery.OperationStatusSubmitted, servicediscovery.OperationStatusPending},
		Target:     []string{servicediscovery.OperationStatusSuccess},
		Refresh:    servicediscoveryOperationRefreshStatusFunc(conn, *resp.OperationId),
		Timeout:    5 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, err = stateConf.WaitForState()
	if err != nil {
		return err
	}

	return resourceAwsServiceDiscoveryServiceRead(d, meta)
}

func resourceAwsServiceDiscoveryServiceDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).sdconn

	input := &servicediscovery.DeleteServiceInput{
		Id: aws.String(d.Id()),
	}

	_, err := conn.DeleteService(input)
	return err
}

func expandServiceDiscoveryDnsConfig(configured map[string]interface{}) *servicediscovery.DnsConfig {
	result := &servicediscovery.DnsConfig{}

	result.NamespaceId = aws.String(configured["namespace_id"].(string))
	dnsRecords := configured["dns_records"].([]interface{})
	drs := make([]*servicediscovery.DnsRecord, len(dnsRecords))
	for i := range drs {
		raw := dnsRecords[i].(map[string]interface{})
		dr := &servicediscovery.DnsRecord{
			TTL:  aws.Int64(int64(raw["ttl"].(int))),
			Type: aws.String(raw["type"].(string)),
		}
		drs[i] = dr
	}
	result.DnsRecords = drs
	if v, ok := configured["routing_policy"]; ok && v != "" {
		result.RoutingPolicy = aws.String(v.(string))
	}

	return result
}

func flattenServiceDiscoveryDnsConfig(config *servicediscovery.DnsConfig) []map[string]interface{} {
	if config == nil {
		return nil
	}

	result := map[string]interface{}{}

	if config.NamespaceId != nil {
		result["namespace_id"] = *config.NamespaceId
	}
	if config.RoutingPolicy != nil {
		result["routing_policy"] = *config.RoutingPolicy
	}
	if config.DnsRecords != nil {
		drs := make([]map[string]interface{}, 0)
		for _, v := range config.DnsRecords {
			dr := map[string]interface{}{}
			dr["ttl"] = *v.TTL
			dr["type"] = *v.Type
			drs = append(drs, dr)
		}
		result["dns_records"] = drs
	}

	if len(result) < 1 {
		return nil
	}

	return []map[string]interface{}{result}
}

func expandServiceDiscoveryDnsConfigChange(configured map[string]interface{}) *servicediscovery.DnsConfigChange {
	result := &servicediscovery.DnsConfigChange{}

	dnsRecords := configured["dns_records"].([]interface{})
	drs := make([]*servicediscovery.DnsRecord, len(dnsRecords))
	for i := range drs {
		raw := dnsRecords[i].(map[string]interface{})
		dr := &servicediscovery.DnsRecord{
			TTL:  aws.Int64(int64(raw["ttl"].(int))),
			Type: aws.String(raw["type"].(string)),
		}
		drs[i] = dr
	}
	result.DnsRecords = drs

	return result
}

func expandServiceDiscoveryHealthCheckConfig(configured map[string]interface{}) *servicediscovery.HealthCheckConfig {
	if len(configured) < 1 {
		return nil
	}
	result := &servicediscovery.HealthCheckConfig{}

	if v, ok := configured["failure_threshold"]; ok && v.(int) != 0 {
		result.FailureThreshold = aws.Int64(int64(v.(int)))
	}
	if v, ok := configured["resource_path"]; ok && v.(string) != "" {
		result.ResourcePath = aws.String(v.(string))
	}
	if v, ok := configured["type"]; ok && v.(string) != "" {
		result.Type = aws.String(v.(string))
	}

	return result
}

func flattenServiceDiscoveryHealthCheckConfig(config *servicediscovery.HealthCheckConfig) []map[string]interface{} {
	if config == nil {
		return nil
	}
	result := map[string]interface{}{}

	if config.FailureThreshold != nil {
		result["failure_threshold"] = *config.FailureThreshold
	}
	if config.ResourcePath != nil {
		result["resource_path"] = *config.ResourcePath
	}
	if config.Type != nil {
		result["type"] = *config.Type
	}

	if len(result) < 1 {
		return nil
	}

	return []map[string]interface{}{result}
}

func expandServiceDiscoveryHealthCheckCustomConfig(configured map[string]interface{}) *servicediscovery.HealthCheckCustomConfig {
	if len(configured) < 1 {
		return nil
	}
	result := &servicediscovery.HealthCheckCustomConfig{}

	if v, ok := configured["failure_threshold"]; ok && v.(int) != 0 {
		result.FailureThreshold = aws.Int64(int64(v.(int)))
	}

	return result
}

func flattenServiceDiscoveryHealthCheckCustomConfig(config *servicediscovery.HealthCheckCustomConfig) []map[string]interface{} {
	if config == nil {
		return nil
	}
	result := map[string]interface{}{}

	if config.FailureThreshold != nil {
		result["failure_threshold"] = *config.FailureThreshold
	}

	if len(result) < 1 {
		return nil
	}

	return []map[string]interface{}{result}
}
<|endoftext|>


<commit_before>package main

import "github.com/krasoffski/goplts/gopl/ch08/ftp"

func main() {
	s := ftp.NewServer("localhost:9999", "/tmp")
	s.Serve()
}
<commit_msg>[8.2] add flags for cli<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"

	"github.com/krasoffski/goplts/gopl/ch08/ftp"
)

func main() {
	host := flag.String("host", "0.0.0.0", "host to connect")
	port := flag.String("port", "10021", "port to connect")
	path := flag.String("path", ".", "initial working directory")
	flag.Parse()

	wd, err := filepath.Abs(*path)
	if err != nil {
		log.Fatalln(err)
	}
	_, err = os.Stat(wd)
	if os.IsNotExist(err) {
		log.Fatalln(err)
	}

	addr := fmt.Sprintf("%s:%s", *host, *port)
	fmt.Printf("running at %s in %s\n", addr, wd)
	s := ftp.NewServer(addr, wd)
	s.Serve()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"

	"github.com/bgv/workerpool"
)

func main() {
	// Number of workers, and Size of the job queue
	pool := workerpool.New(10, 50)
    // Release the resources after we finish
	defer pool.Stop()

	// create and submit 10 jobs to the pool
	for i := 0; i < 100; i++ {
		count := i

		pool.JobQueue <- func() {
			fmt.Printf("I am job! Number %d\n", count)
		}
	}

	// dummy wait until jobs are finished
	time.Sleep(1 * time.Second)

	// release resources used by workerpool
	pool.Stop()

}
<commit_msg>go fmt<commit_after>package main

import (
	"fmt"
	"time"

	"github.com/bgv/workerpool"
)

func main() {
	// Number of workers, and Size of the job queue
	pool := workerpool.New(10, 50)
	// Release the resources after we finish
	defer pool.Stop()

	// create and submit 10 jobs to the pool
	for i := 0; i < 100; i++ {
		count := i

		pool.JobQueue <- func() {
			fmt.Printf("I am job! Number %d\n", count)
		}
	}

	// dummy wait until jobs are finished
	time.Sleep(1 * time.Second)

	// release resources used by workerpool
	pool.Stop()

}
<|endoftext|>


<commit_before>package containerdrunner

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/burntsushi/toml"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
)

type Config struct {
	Root            string      `toml:"root"`
	State           string      `toml:"state"`
	Subreaper       bool        `toml:"subreaper"`
	OomScore        int         `toml:"oom_score"`
	GRPC            GRPCConfig  `toml:"grpc"`
	Debug           DebugConfig `toml:"debug"`
	DisabledPlugins []string    `toml:"disabled_plugins"`

	RunDir string
}

type GRPCConfig struct {
	Address string `toml:"address"`
}

type DebugConfig struct {
	Address string `toml:"address"`
	Level   string `toml:"level"`
}

func ContainerdConfig(containerdDataDir string) Config {
	return Config{
		Root:      filepath.Join(containerdDataDir, "root"),
		State:     filepath.Join(containerdDataDir, "state"),
		Subreaper: true,
		OomScore:  -999,
		GRPC: GRPCConfig{
			Address: filepath.Join(containerdDataDir, "containerd.sock"),
		},
		Debug: DebugConfig{
			Address: filepath.Join(containerdDataDir, "debug.sock"),
			Level:   "debug",
		},
		DisabledPlugins: []string{
			"aufs",
			"overlayfs",
			"zfs",
			"walking",
			"scheduler",
			"content-service",
			"diff-service",
			"images-service",
			"namespaces-service",
			"snapshots-service",
			"content",
			"diff",
			"events",
			"healthcheck",
			"images",
			"namespaces",
			"snapshots",
			"version",
			"cri",
		},
	}
}

func NewSession(runDir string, config Config) *gexec.Session {
	configFile, err := os.OpenFile(filepath.Join(runDir, "containerd.toml"), os.O_TRUNC|os.O_WRONLY|os.O_CREATE, os.ModePerm)
	Expect(err).NotTo(HaveOccurred())
	Expect(toml.NewEncoder(configFile).Encode(&config)).To(Succeed())
	Expect(configFile.Close()).To(Succeed())

	cmd := exec.Command("containerd", "--config", configFile.Name())
	cmd.Env = append(os.Environ(), fmt.Sprintf("PATH=%s", fmt.Sprintf("%s:%s", os.Getenv("PATH"), "/usr/local/bin")))
	session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
	Expect(err).NotTo(HaveOccurred())
	return session
}
<commit_msg>Enable shim's debug mode<commit_after>package containerdrunner

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/burntsushi/toml"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
)

type Config struct {
	Root            string      `toml:"root"`
	State           string      `toml:"state"`
	Subreaper       bool        `toml:"subreaper"`
	OomScore        int         `toml:"oom_score"`
	GRPC            GRPCConfig  `toml:"grpc"`
	Debug           DebugConfig `toml:"debug"`
	DisabledPlugins []string    `toml:"disabled_plugins"`
	Plugins         Plugins     `toml:"plugins"`

	RunDir string
}

type GRPCConfig struct {
	Address string `toml:"address"`
}

type DebugConfig struct {
	Address string `toml:"address"`
	Level   string `toml:"level"`
}

type Plugins struct {
	Linux Linux `toml:"linux"`
}

type Linux struct {
	ShimDebug bool `toml:"shim_debug"`
}

func ContainerdConfig(containerdDataDir string) Config {
	return Config{
		Root:      filepath.Join(containerdDataDir, "root"),
		State:     filepath.Join(containerdDataDir, "state"),
		Subreaper: true,
		OomScore:  -999,
		GRPC: GRPCConfig{
			Address: filepath.Join(containerdDataDir, "containerd.sock"),
		},
		Debug: DebugConfig{
			Address: filepath.Join(containerdDataDir, "debug.sock"),
			Level:   "debug",
		},
		DisabledPlugins: []string{
			"aufs",
			"overlayfs",
			"zfs",
			"walking",
			"scheduler",
			"content-service",
			"diff-service",
			"images-service",
			"namespaces-service",
			"snapshots-service",
			"content",
			"diff",
			"events",
			"healthcheck",
			"images",
			"namespaces",
			"snapshots",
			"version",
			"cri",
		},
		Plugins: Plugins{
			Linux: Linux{
				ShimDebug: true,
			},
		},
	}
}

func NewSession(runDir string, config Config) *gexec.Session {
	configFile, err := os.OpenFile(filepath.Join(runDir, "containerd.toml"), os.O_TRUNC|os.O_WRONLY|os.O_CREATE, os.ModePerm)
	Expect(err).NotTo(HaveOccurred())
	Expect(toml.NewEncoder(configFile).Encode(&config)).To(Succeed())
	Expect(configFile.Close()).To(Succeed())

	cmd := exec.Command("containerd", "--config", configFile.Name())
	cmd.Env = append(os.Environ(), fmt.Sprintf("PATH=%s", fmt.Sprintf("%s:%s", os.Getenv("PATH"), "/usr/local/bin")))
	session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
	Expect(err).NotTo(HaveOccurred())
	return session
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"os"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/moul/tictactoe"
)

func init() {
	rand.Seed(time.Now().UTC().UnixNano())
}

type QuestionMessage struct {
	GameID      string
	Action      string
	Game        string
	Players     int
	Board       map[string]string
	You         string
	PlayerIndex int
}

func main() {
	logrus.Warnf("%s << %v", os.Args[0], os.Args[1])

	var question QuestionMessage
	if err := json.Unmarshal([]byte(os.Args[1]), &question); err != nil {
		logrus.Fatalf("%s XX err: %v", err)
	}

	switch question.Action {
	case "init":
		logrus.Warnf("init: %v", question)
		fmt.Println("{\"name\":\"moul-tictactoe\"}")
	case "play-turn":
		ttt := tictactoe.NewTicTacToe()
		ttt.Set(0, 0, question.Board["0-0"])
		ttt.Set(0, 1, question.Board["0-1"])
		ttt.Set(0, 2, question.Board["0-2"])
		ttt.Set(1, 0, question.Board["1-0"])
		ttt.Set(1, 1, question.Board["1-1"])
		ttt.Set(1, 2, question.Board["1-2"])
		ttt.Set(2, 0, question.Board["2-0"])
		ttt.Set(2, 1, question.Board["2-1"])
		ttt.Set(2, 2, question.Board["2-2"])
		ttt.SetPlayer(question.You)

		logrus.Debugf("map: %q", ttt.ShowMap())

		next, err := ttt.Next()
		if err != nil {
			logrus.Fatalf("Error while getting the next piece: %v", err)
		}

		fmt.Printf("{\"play\":\"%d-%d\"}", next.Y, next.X)
	default:
		logrus.Fatalf("Unknown action: %q", question.Action)
	}
}
<commit_msg>Refactored bot as a struct<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"os"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/moul/bolosseum/bots"
	"github.com/moul/tictactoe"
)

func init() {
	rand.Seed(time.Now().UTC().UnixNano())
}

func NewTictactoeBot() *TictactoeBot {
	return &TictactoeBot{}
}

type TictactoeBot struct{}

func (b *TictactoeBot) Init(message bots.QuestionMessage) *bots.ReplyMessage {
	// FIXME: init ttt here
	return &bots.ReplyMessage{
		Name: "moul-tictactoe",
	}
}

func (b *TictactoeBot) PlayTurn(question bots.QuestionMessage) *bots.ReplyMessage {
	ttt := tictactoe.NewTicTacToe()

	board := question.Board.(map[string]interface{})

	ttt.Set(0, 0, board["0-0"].(string))
	ttt.Set(0, 1, board["0-1"].(string))
	ttt.Set(0, 2, board["0-2"].(string))
	ttt.Set(1, 0, board["1-0"].(string))
	ttt.Set(1, 1, board["1-1"].(string))
	ttt.Set(1, 2, board["1-2"].(string))
	ttt.Set(2, 0, board["2-0"].(string))
	ttt.Set(2, 1, board["2-1"].(string))
	ttt.Set(2, 2, board["2-2"].(string))
	ttt.SetPlayer(question.You.(string))

	logrus.Debugf("map: %q", ttt.ShowMap())

	next, err := ttt.Next()
	if err != nil {
		logrus.Fatalf("Error while getting the next piece: %v", err)
	}

	return &bots.ReplyMessage{
		Play: fmt.Sprintf("%d-%d", next.Y, next.X),
	}
}

func main() {
	logrus.Warnf("%s << %v", os.Args[0], os.Args[1])

	var question bots.QuestionMessage
	if err := json.Unmarshal([]byte(os.Args[1]), &question); err != nil {
		logrus.Fatalf("%s XX err: %v", err)
	}

	bot := NewTictactoeBot()

	reply := &bots.ReplyMessage{}

	switch question.Action {
	case "init":
		reply = bot.Init(question)
	case "play-turn":
		reply = bot.PlayTurn(question)
	default:
		// FIXME: reply message error
		logrus.Fatalf("Unknown action: %q", question.Action)
	}

	jsonString, err := json.Marshal(reply)
	if err != nil {
		logrus.Fatalf("Failed to marshal json: %v", err)
	}

	fmt.Println(string(jsonString))
}
<|endoftext|>


<commit_before>// Copyright 2012-2017 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This is a basic init script.
package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"syscall"
)

var (
	host             = flag.Bool("h", false, "Help")
	version          = flag.Bool("V", false, "Version")
	DEFAULT_ROOT_DEV = "/dev/mmcblk0p1"
	DEVICE_PARAM     = "uroot.rootdevice"
)

func usage() string {
	// Return the usage string
	return ""
}

func littleDoctor(path string, fs *syscall.Statfs_t) error {
	// Recursively deletes everything at slash
	// Does not continue down other filesystems i.e.
	// new_root, devtmpfs, profs and sysfs

	pathFS := syscall.Statfs_t{}

	if err := syscall.Statfs(path, &pathFS); err != nil {
		return err
	}

	if pathFS.Type != fs.Type {
		return nil
	}

	file, err := os.Open(path)

	if err != nil {
		return fmt.Errorf("Could not open %s: %v", path, err)
	}

	if fileStat, _ := file.Stat(); fileStat.IsDir() {

		names, err := file.Readdirnames(-1)
		file.Close()

		if err != nil {
			return err
		}

		for _, fileName := range names {

			if fileName == "." || fileName == ".." {
				return nil
			}

			littleDoctor(filepath.Join(path, fileName), fs)
			os.Remove(path)
		}

	} else {
		os.Remove(path)
	}

	return nil
}

func exec_command(path string) error {
	// Will exec and dup a command at path
	cmd := exec.Command(path)
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	var fd int
	cmd.SysProcAttr = &syscall.SysProcAttr{Ctty: fd, Setctty: true, Setsid: true, Cloneflags: uintptr(0)}
	log.Printf("Run %v", cmd)

	if err := cmd.Run(); err != nil {
		return err
	}

	return nil
}

func start(new_root string, init string) {
	// This getpid adds a bit of cost to each invocation (not much really)
	// but it allows us to merge init and sh. The 600K we save is worth it.
	// Figure out which init to run. We must always do this.

	// log.Printf("init: os is %v, initMap %v", filepath.Base(os.Args[0]), initMap)
	// we use filepath.Base in case they type something like ./cmd
	log.Printf("switch_root: Changing directory")

	syscall.Chdir(new_root)

	rootFS := syscall.Statfs_t{}

	if err := syscall.Statfs("/", &rootFS); err != nil {
		log.Fatalf("switch_root: failed Stat %v", err)
	}

	if err := littleDoctor("/", &rootFS); err != nil {
		log.Fatalf("switch_root: failed Deletion of rootfs: %v", err)
	}

	log.Printf("switch_root: Overmounting on /")

	if err := syscall.Mount(".", "/", "ext4", syscall.MS_MOVE, ""); err != nil {
		log.Fatalf("switch_root: fatal mount error %v", err)
	}

	log.Printf("switch_root: Changing root!")

	if err := syscall.Chroot("."); err != nil {
		log.Fatalf("switch_root: fatal chroot error %v", err)
	}

	log.Printf("switch_root: returning to slash")
	syscall.Chdir("/")

	log.Printf("switch_root: creating Uroot filesystem")

	if err := exec_command(init); err != nil {
		log.Printf("switch_root: returning to ramfs")
	}

}

func main() {
	flag.Parse()

	if len(flag.Args()) == 0 {
		os.Exit(0)
	}

	if *host {
		fmt.Print(usage())
	}

	if *version {
		fmt.Println("Version XX")
	}

	new_root := flag.Args()[0]
	init := flag.Args()[1]

	start(new_root, init)
	log.Printf("switch_root failed")

}
<commit_msg>Create special filesystems in new root<commit_after>// Copyright 2012-2017 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This is a basic init script.
package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"syscall"
)

var (
	help             = flag.Bool("h", false, "Help")
	version          = flag.Bool("V", false, "Version")
	DEFAULT_ROOT_DEV = "/dev/mmcblk0p1"
	DEVICE_PARAM     = "uroot.rootdevice"
)

func usage() string {
	// Return the usage string
	return "switch_root [-h] [-V]\nswitch_root newroot init"
}

func littleDoctor(path string, fs *syscall.Statfs_t) error {
	// Recursively deletes everything at slash
	// Does not continue down other filesystems i.e.
	// new_root, devtmpfs, profs and sysfs

	pathFS := syscall.Statfs_t{}

	if err := syscall.Statfs(path, &pathFS); err != nil {
		return err
	}

	if pathFS.Type != fs.Type {
		return nil
	}

	file, err := os.Open(path)

	if err != nil {
		return fmt.Errorf("Could not open %s: %v", path, err)
	}

	if fileStat, _ := file.Stat(); fileStat.IsDir() {

		names, err := file.Readdirnames(-1)
		file.Close()

		if err != nil {
			return err
		}

		for _, fileName := range names {

			if fileName == "." || fileName == ".." {
				return nil
			}

			littleDoctor(filepath.Join(path, fileName), fs)
			os.Remove(path)
		}

	} else {
		os.Remove(path)
	}

	return nil
}

func execCommand(path string) error {
	// Will exec and dup a command at path
	var fd int
	cmd := exec.Command(path)
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	cmd.SysProcAttr = &syscall.SysProcAttr{Ctty: fd, Setctty: true, Setsid: true, Cloneflags: uintptr(0)}
	log.Printf("Run %v", cmd)

	if err := cmd.Run(); err != nil {
		return err
	}

	return nil
}

func specialFS() {

	syscall.Mkdir("/path", 0)
	syscall.Mkdir("/sys", 0)
	syscall.Mkdir("/dev", 0)

	syscall.Mount("proc", "/proc", "proc", syscall.MS_MGC_VAL, "")
	syscall.Mount("sys", "/sys", "sysfs", syscall.MS_MGC_VAL, "")
	syscall.Mount("none", "/dev", "devtmpfs", syscall.MS_MGC_VAL, "")
}

func start(new_root string, init string) {
	// This getpid adds a bit of cost to each invocation (not much really)
	// but it allows us to merge init and sh. The 600K we save is worth it.
	// Figure out which init to run. We must always do this.

	// log.Printf("init: os is %v, initMap %v", filepath.Base(os.Args[0]), initMap)
	// we use filepath.Base in case they type something like ./cmd
	log.Printf("switch_root: Changing directory")

	syscall.Chdir(new_root)

	rootFS := syscall.Statfs_t{}

	if err := syscall.Statfs("/", &rootFS); err != nil {
		log.Fatalf("switch_root: failed Stat %v", err)
	}

	if err := littleDoctor("/", &rootFS); err != nil {
		log.Fatalf("switch_root: failed Deletion of rootfs: %v", err)
	}

	log.Printf("switch_root: Overmounting on /")

	if err := syscall.Mount(".", "/", "ext4", syscall.MS_MOVE, ""); err != nil {
		log.Fatalf("switch_root: fatal mount error %v", err)
	}

	log.Printf("switch_root: Changing root!")

	if err := syscall.Chroot("."); err != nil {
		log.Fatalf("switch_root: fatal chroot error %v", err)
	}

	log.Printf("switch_root: returning to slash")
	syscall.Chdir("/")

	log.Printf("switch_root: creating proc, dev and sys")

	specialFS()

	log.Printf("switch_root: executing init")
	if err := execCommand(init); err != nil {
		log.Printf("switch_root: returning to ramfs")
	}

}

func main() {
	flag.Parse()

	if len(flag.Args()) == 0 {
		fmt.Println(usage())
		os.Exit(0)
	}

	if *help {
		fmt.Println(usage())
		os.Exit(0)
	}

	if *version {
		fmt.Println("Version XX")
		os.Exit(0)
	}

	new_root := flag.Args()[0]
	init := flag.Args()[1]

	start(new_root, init)
	log.Printf("switch_root failed")

}
<|endoftext|>


<commit_before>package provider

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/BurntSushi/toml"
	"github.com/Nitro/sidecar/catalog"
	"github.com/Nitro/sidecar/service"
	"github.com/containous/flaeg"
	"github.com/containous/traefik/log"
	"github.com/containous/traefik/safe"
	"github.com/containous/traefik/types"
	fsnotify "gopkg.in/fsnotify.v1"
)

const (
	method               = "wrr"
	weight               = 0
	sticky               = false
	maxConnExtractorFunc = "request.host"
)

var (
	// Disable all timeouts for watcher requests
	watcherHTTPTransport = &http.Transport{ResponseHeaderTimeout: 0}
	watcherHTTPClient    = &http.Client{
		Timeout:   0,
		Transport: watcherHTTPTransport,
	}

	sidecarHTTPClient = &http.Client{
		Timeout: 5 * time.Second,
	}
)

var _ Provider = (*Sidecar)(nil)

// Sidecar holds configurations of the Sidecar provider
type Sidecar struct {
	BaseProvider      `mapstructure:",squash"`
	Endpoint          string `description:"Sidecar URL"`
	configurationChan chan<- types.ConfigMessage
	RefreshConn       flaeg.Duration `description:"How often to refresh the connection to Sidecar backend"`
	connTimer         *time.Timer
	MaxConns          int64 `description:"Maximum number of connections allowed for each backend"`
}

type callback func(map[string][]*service.Service, error)

// Provide allows the provider to provide configurations to traefik
// using the given configuration channel.
func (provider *Sidecar) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
	provider.configurationChan = configurationChan

	if provider.Watch {
		pool.Go(
			func(stop chan bool) {
				provider.sidecarWatcher(stop, pool)
			},
		)

		watcher, err := fsnotify.NewWatcher()
		if err != nil {
			log.Errorln("Error creating file watcher", err)
			return err
		}

		file, err := os.Open(provider.Filename)
		if err != nil {
			log.Errorln("Error opening file", err)
			return err
		}
		defer file.Close()
		pool.Go(func(stop chan bool) {
			defer watcher.Close()
			for {
				select {
				case <-stop:
					return
				case event := <-watcher.Events:
					if strings.Contains(event.Name, file.Name()) {
						log.Debug("Sidecar Frontend File event:", event)
						states, errState := provider.fetchState()
						if errState != nil {
							log.Errorln("Error reloading Sidecar config", errState)
						}
						errLoadConfig := provider.loadSidecarConfig(states)
						if errLoadConfig != nil {
							log.Errorf("Error loading Sidecar config: %s", errLoadConfig)
						}
					}
				case errWatcher := <-watcher.Errors:
					log.Errorln("Watcher event error", errWatcher)
				}
			}
		})
		err = watcher.Add(filepath.Dir(file.Name()))
		if err != nil {
			log.Error("Error adding file watcher", err)
			return err
		}
	}
	states, err := provider.fetchState()
	if err != nil {
		log.Fatalln("Error reloading Sidecar config", err)
	}

	return provider.loadSidecarConfig(states)
}

func (provider *Sidecar) constructConfig(sidecarStates *catalog.ServicesState) (*types.Configuration, error) {
	log.Infoln("loading sidecar config")
	sidecarConfig := types.Configuration{Backends: provider.makeBackends(sidecarStates)}
	var err error
	sidecarConfig.Frontends, err = provider.makeFrontends()
	if err != nil {
		return nil, err
	}
	return &sidecarConfig, nil
}

func (provider *Sidecar) loadSidecarConfig(sidecarStates *catalog.ServicesState) error {
	conf, err := provider.constructConfig(sidecarStates)
	if err != nil {
		return err
	}

	provider.configurationChan <- types.ConfigMessage{
		ProviderName:  "sidecar",
		Configuration: conf,
	}
	return nil
}

func (provider *Sidecar) sidecarWatcher(stop chan bool, pool *safe.Pool) {
	//set timeout to be just a bit more than connection refresh interval
	provider.connTimer = time.NewTimer(time.Duration(provider.RefreshConn))

	log.Debugf("Using %s Sidecar connection refresh interval", provider.RefreshConn)
	provider.recycleConn(stop, pool)
}

func (provider *Sidecar) recycleConn(stop chan bool, pool *safe.Pool) {
	var err error
	var resp *http.Response
	var req *http.Request
	for {
		select {
		case <-stop:
			return
		default:
			//use refresh interval to occasionally reconnect to Sidecar in case the stream connection is lost
			req, err = http.NewRequest("GET", provider.Endpoint+"/watch?by_service=false", nil)
			if err != nil {
				log.Errorf("Error creating http request to Sidecar: %s, Error: %s", provider.Endpoint, err)
				continue
			}
			resp, err = watcherHTTPClient.Do(req)
			if err != nil {
				log.Errorf("Error connecting to Sidecar: %s, Error: %s", provider.Endpoint, err)
				time.Sleep(5 * time.Second)
				continue
			}

			pool.Go(
				func(stop chan bool) {
					decodeStream(resp.Body, provider.callbackLoader, stop)
				},
			)

			//wait on refresh connection timer.  If this expires we haven't seen an update in a
			//while and should cancel the request, reset the time, and reconnect just in case
			<-provider.connTimer.C
			provider.connTimer.Reset(time.Duration(provider.RefreshConn))

			//TODO: Deprecated method. Refactor this to use a context.
			watcherHTTPTransport.CancelRequest(req)
		}
	}
}

func (provider *Sidecar) callbackLoader(sidecarStates *catalog.ServicesState, err error) {
	//load config regardless
	errLoadConfig := provider.loadSidecarConfig(sidecarStates)
	if errLoadConfig != nil {
		log.Error("Error reloading config: %s", errLoadConfig)
	}

	if err != nil {
		return
	}

	//else reset connection timer
	if !provider.connTimer.Stop() {
		<-provider.connTimer.C
	}

	provider.connTimer.Reset(time.Duration(provider.RefreshConn))
}

func (provider *Sidecar) makeFrontends() (map[string]*types.Frontend, error) {
	configuration := new(types.Configuration)
	if _, err := toml.DecodeFile(provider.Filename, configuration); err != nil {
		log.Errorf("Error reading file: %s", err)
		return nil, err
	}
	return configuration.Frontends, nil
}

func (provider *Sidecar) makeBackends(sidecarStates *catalog.ServicesState) map[string]*types.Backend {
	sidecarBacks := make(map[string]*types.Backend)

	sidecarStates.EachService(
		func(hostname *string, serviceId *string, svc *service.Service) {
			var backend *types.Backend
			var ok bool
			if backend, ok = sidecarBacks[svc.Name]; !ok {
				backend = &types.Backend{
					LoadBalancer: &types.LoadBalancer{Method: method, Sticky: sticky},
					Servers:      make(map[string]types.Server),
					MaxConn: &types.MaxConn{
						Amount:        provider.MaxConns,
						ExtractorFunc: maxConnExtractorFunc,
					},
				}

				sidecarBacks[svc.Name] = backend
			}

			if svc.IsAlive() {
				for i := 0; i < len(svc.Ports); i++ {
					ipAddr, err := net.LookupIP(svc.Hostname)
					if err != nil {
						log.Errorln("Error resolving Ip address, ", err)
						backend.Servers[svc.Hostname] = types.Server{
							URL: "http://" + svc.Hostname + ":" + strconv.FormatInt(svc.Ports[i].Port, 10),
						}
					} else {
						backend.Servers[svc.Hostname] = types.Server{
							URL: "http://" + ipAddr[0].String() + ":" + strconv.FormatInt(svc.Ports[i].Port, 10),
						}
					}
				}
			}
		},
	)

	return sidecarBacks
}

func (provider *Sidecar) fetchState() (*catalog.ServicesState, error) {
	resp, err := sidecarHTTPClient.Get(provider.Endpoint + "/state.json")
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	bytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	state, err := catalog.Decode(bytes)
	if err != nil {
		return nil, err
	}
	return state, nil
}

func decodeStream(input io.Reader, callback func(*catalog.ServicesState, error), stop chan bool) error {
	dec := json.NewDecoder(input)
	for dec.More() {
		select {
		case <-stop:
			return nil
		default:
			var conf catalog.ServicesState
			err := dec.Decode(&conf)

			callback(&conf, err)

			if err != nil {
				log.Errorf("Error decoding stream: %s", err)
				return err
			}
		}
	}
	return nil
}
<commit_msg>Revert using the goroutine pool for decodeStream<commit_after>package provider

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/BurntSushi/toml"
	"github.com/Nitro/sidecar/catalog"
	"github.com/Nitro/sidecar/service"
	"github.com/containous/flaeg"
	"github.com/containous/traefik/log"
	"github.com/containous/traefik/safe"
	"github.com/containous/traefik/types"
	fsnotify "gopkg.in/fsnotify.v1"
)

const (
	method               = "wrr"
	weight               = 0
	sticky               = false
	maxConnExtractorFunc = "request.host"
)

var (
	// Disable all timeouts for watcher requests
	watcherHTTPTransport = &http.Transport{ResponseHeaderTimeout: 0}
	watcherHTTPClient    = &http.Client{
		Timeout:   0,
		Transport: watcherHTTPTransport,
	}

	sidecarHTTPClient = &http.Client{
		Timeout: 5 * time.Second,
	}
)

var _ Provider = (*Sidecar)(nil)

// Sidecar holds configurations of the Sidecar provider
type Sidecar struct {
	BaseProvider      `mapstructure:",squash"`
	Endpoint          string `description:"Sidecar URL"`
	configurationChan chan<- types.ConfigMessage
	RefreshConn       flaeg.Duration `description:"How often to refresh the connection to Sidecar backend"`
	connTimer         *time.Timer
	MaxConns          int64 `description:"Maximum number of connections allowed for each backend"`
}

type callback func(map[string][]*service.Service, error)

// Provide allows the provider to provide configurations to traefik
// using the given configuration channel.
func (provider *Sidecar) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
	provider.configurationChan = configurationChan

	if provider.Watch {
		pool.Go(
			func(stop chan bool) {
				provider.sidecarWatcher(stop, pool)
			},
		)

		watcher, err := fsnotify.NewWatcher()
		if err != nil {
			log.Errorln("Error creating file watcher", err)
			return err
		}

		file, err := os.Open(provider.Filename)
		if err != nil {
			log.Errorln("Error opening file", err)
			return err
		}
		defer file.Close()
		pool.Go(func(stop chan bool) {
			defer watcher.Close()
			for {
				select {
				case <-stop:
					return
				case event := <-watcher.Events:
					if strings.Contains(event.Name, file.Name()) {
						log.Debug("Sidecar Frontend File event:", event)
						states, errState := provider.fetchState()
						if errState != nil {
							log.Errorln("Error reloading Sidecar config", errState)
						}
						errLoadConfig := provider.loadSidecarConfig(states)
						if errLoadConfig != nil {
							log.Errorf("Error loading Sidecar config: %s", errLoadConfig)
						}
					}
				case errWatcher := <-watcher.Errors:
					log.Errorln("Watcher event error", errWatcher)
				}
			}
		})
		err = watcher.Add(filepath.Dir(file.Name()))
		if err != nil {
			log.Error("Error adding file watcher", err)
			return err
		}
	}
	states, err := provider.fetchState()
	if err != nil {
		log.Fatalln("Error reloading Sidecar config", err)
	}

	return provider.loadSidecarConfig(states)
}

func (provider *Sidecar) constructConfig(sidecarStates *catalog.ServicesState) (*types.Configuration, error) {
	log.Infoln("loading sidecar config")
	sidecarConfig := types.Configuration{Backends: provider.makeBackends(sidecarStates)}
	var err error
	sidecarConfig.Frontends, err = provider.makeFrontends()
	if err != nil {
		return nil, err
	}
	return &sidecarConfig, nil
}

func (provider *Sidecar) loadSidecarConfig(sidecarStates *catalog.ServicesState) error {
	conf, err := provider.constructConfig(sidecarStates)
	if err != nil {
		return err
	}

	provider.configurationChan <- types.ConfigMessage{
		ProviderName:  "sidecar",
		Configuration: conf,
	}
	return nil
}

func (provider *Sidecar) sidecarWatcher(stop chan bool, pool *safe.Pool) {
	//set timeout to be just a bit more than connection refresh interval
	provider.connTimer = time.NewTimer(time.Duration(provider.RefreshConn))

	log.Debugf("Using %s Sidecar connection refresh interval", provider.RefreshConn)
	provider.recycleConn(stop, pool)
}

func (provider *Sidecar) recycleConn(stop chan bool, pool *safe.Pool) {
	var err error
	var resp *http.Response
	var req *http.Request
	for {
		select {
		case <-stop:
			return
		default:
			//use refresh interval to occasionally reconnect to Sidecar in case the stream connection is lost
			req, err = http.NewRequest("GET", provider.Endpoint+"/watch?by_service=false", nil)
			if err != nil {
				log.Errorf("Error creating http request to Sidecar: %s, Error: %s", provider.Endpoint, err)
				continue
			}
			resp, err = watcherHTTPClient.Do(req)
			if err != nil {
				log.Errorf("Error connecting to Sidecar: %s, Error: %s", provider.Endpoint, err)
				time.Sleep(5 * time.Second)
				continue
			}

			safe.Go(func() { decodeStream(resp.Body, provider.callbackLoader) })

			//wait on refresh connection timer.  If this expires we haven't seen an update in a
			//while and should cancel the request, reset the time, and reconnect just in case
			<-provider.connTimer.C
			provider.connTimer.Reset(time.Duration(provider.RefreshConn))

			//TODO: Deprecated method. Refactor this to use a context.
			watcherHTTPTransport.CancelRequest(req)
		}
	}
}

func (provider *Sidecar) callbackLoader(sidecarStates *catalog.ServicesState, err error) {
	//load config regardless
	errLoadConfig := provider.loadSidecarConfig(sidecarStates)
	if errLoadConfig != nil {
		log.Error("Error reloading config: %s", errLoadConfig)
	}

	if err != nil {
		return
	}

	//else reset connection timer
	if !provider.connTimer.Stop() {
		<-provider.connTimer.C
	}

	provider.connTimer.Reset(time.Duration(provider.RefreshConn))
}

func (provider *Sidecar) makeFrontends() (map[string]*types.Frontend, error) {
	configuration := new(types.Configuration)
	if _, err := toml.DecodeFile(provider.Filename, configuration); err != nil {
		log.Errorf("Error reading file: %s", err)
		return nil, err
	}
	return configuration.Frontends, nil
}

func (provider *Sidecar) makeBackends(sidecarStates *catalog.ServicesState) map[string]*types.Backend {
	sidecarBacks := make(map[string]*types.Backend)

	sidecarStates.EachService(
		func(hostname *string, serviceId *string, svc *service.Service) {
			var backend *types.Backend
			var ok bool
			if backend, ok = sidecarBacks[svc.Name]; !ok {
				backend = &types.Backend{
					LoadBalancer: &types.LoadBalancer{Method: method, Sticky: sticky},
					Servers:      make(map[string]types.Server),
					MaxConn: &types.MaxConn{
						Amount:        provider.MaxConns,
						ExtractorFunc: maxConnExtractorFunc,
					},
				}

				sidecarBacks[svc.Name] = backend
			}

			if svc.IsAlive() {
				for i := 0; i < len(svc.Ports); i++ {
					ipAddr, err := net.LookupIP(svc.Hostname)
					if err != nil {
						log.Errorln("Error resolving Ip address, ", err)
						backend.Servers[svc.Hostname] = types.Server{
							URL: "http://" + svc.Hostname + ":" + strconv.FormatInt(svc.Ports[i].Port, 10),
						}
					} else {
						backend.Servers[svc.Hostname] = types.Server{
							URL: "http://" + ipAddr[0].String() + ":" + strconv.FormatInt(svc.Ports[i].Port, 10),
						}
					}
				}
			}
		},
	)

	return sidecarBacks
}

func (provider *Sidecar) fetchState() (*catalog.ServicesState, error) {
	resp, err := sidecarHTTPClient.Get(provider.Endpoint + "/state.json")
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	bytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	state, err := catalog.Decode(bytes)
	if err != nil {
		return nil, err
	}
	return state, nil
}

func decodeStream(input io.Reader, callback func(*catalog.ServicesState, error)) error {
	dec := json.NewDecoder(input)
	for dec.More() {
		var conf catalog.ServicesState
		err := dec.Decode(&conf)

		callback(&conf, err)

		if err != nil {
			log.Errorf("Error decoding stream: %s", err)
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package proxy_test

import (
	"os"

	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/juju/osenv"
	"launchpad.net/juju-core/testing"
	"launchpad.net/juju-core/utils/proxy"
)

type proxySuite struct {
	testing.BaseSuite
}

var _ = gc.Suite(&proxySuite{})

func (s *proxySuite) TestDetectNoSettings(c *gc.C) {
	// Patch all of the environment variables we check out just in case the
	// user has one set.
	s.PatchEnvironment("http_proxy", "")
	s.PatchEnvironment("HTTP_PROXY", "")
	s.PatchEnvironment("https_proxy", "")
	s.PatchEnvironment("HTTPS_PROXY", "")
	s.PatchEnvironment("ftp_proxy", "")
	s.PatchEnvironment("FTP_PROXY", "")
	s.PatchEnvironment("no_proxy", "")
	s.PatchEnvironment("NO_PROXY", "")

	proxies := osenv.DetectProxies()

	c.Assert(proxies, gc.DeepEquals, proxy.Settings{})
}

func (s *proxySuite) TestDetectPrimary(c *gc.C) {
	// Patch all of the environment variables we check out just in case the
	// user has one set.
	s.PatchEnvironment("http_proxy", "http://user@10.0.0.1")
	s.PatchEnvironment("HTTP_PROXY", "")
	s.PatchEnvironment("https_proxy", "https://user@10.0.0.1")
	s.PatchEnvironment("HTTPS_PROXY", "")
	s.PatchEnvironment("ftp_proxy", "ftp://user@10.0.0.1")
	s.PatchEnvironment("FTP_PROXY", "")
	s.PatchEnvironment("no_proxy", "10.0.3.1,localhost")
	s.PatchEnvironment("NO_PROXY", "")

	proxies := osenv.DetectProxies()

	c.Assert(proxies, gc.DeepEquals, proxy.Settings{
		Http:    "http://user@10.0.0.1",
		Https:   "https://user@10.0.0.1",
		Ftp:     "ftp://user@10.0.0.1",
		NoProxy: "10.0.3.1,localhost",
	})
}

func (s *proxySuite) TestDetectFallback(c *gc.C) {
	// Patch all of the environment variables we check out just in case the
	// user has one set.
	s.PatchEnvironment("http_proxy", "")
	s.PatchEnvironment("HTTP_PROXY", "http://user@10.0.0.2")
	s.PatchEnvironment("https_proxy", "")
	s.PatchEnvironment("HTTPS_PROXY", "https://user@10.0.0.2")
	s.PatchEnvironment("ftp_proxy", "")
	s.PatchEnvironment("FTP_PROXY", "ftp://user@10.0.0.2")
	s.PatchEnvironment("no_proxy", "")
	s.PatchEnvironment("NO_PROXY", "10.0.3.1,localhost")

	proxies := osenv.DetectProxies()

	c.Assert(proxies, gc.DeepEquals, proxy.Settings{
		Http:    "http://user@10.0.0.2",
		Https:   "https://user@10.0.0.2",
		Ftp:     "ftp://user@10.0.0.2",
		NoProxy: "10.0.3.1,localhost",
	})
}

func (s *proxySuite) TestDetectPrimaryPreference(c *gc.C) {
	// Patch all of the environment variables we check out just in case the
	// user has one set.
	s.PatchEnvironment("http_proxy", "http://user@10.0.0.1")
	s.PatchEnvironment("https_proxy", "https://user@10.0.0.1")
	s.PatchEnvironment("ftp_proxy", "ftp://user@10.0.0.1")
	s.PatchEnvironment("no_proxy", "10.0.3.1,localhost")
	s.PatchEnvironment("HTTP_PROXY", "http://user@10.0.0.2")
	s.PatchEnvironment("HTTPS_PROXY", "https://user@10.0.0.2")
	s.PatchEnvironment("FTP_PROXY", "ftp://user@10.0.0.2")
	s.PatchEnvironment("NO_PROXY", "localhost")

	proxies := osenv.DetectProxies()

	c.Assert(proxies, gc.DeepEquals, proxy.Settings{
		Http:    "http://user@10.0.0.1",
		Https:   "https://user@10.0.0.1",
		Ftp:     "ftp://user@10.0.0.1",
		NoProxy: "10.0.3.1,localhost",
	})
}

func (s *proxySuite) TestAsScriptEnvironmentEmpty(c *gc.C) {
	proxies := proxy.Settings{}
	c.Assert(proxies.AsScriptEnvironment(), gc.Equals, "")
}

func (s *proxySuite) TestAsScriptEnvironmentOneValue(c *gc.C) {
	proxies := proxy.Settings{
		Http: "some-value",
	}
	expected := `
export http_proxy=some-value
export HTTP_PROXY=some-value`[1:]
	c.Assert(proxies.AsScriptEnvironment(), gc.Equals, expected)
}

func (s *proxySuite) TestAsScriptEnvironmentAllValue(c *gc.C) {
	proxies := proxy.Settings{
		Http:    "some-value",
		Https:   "special",
		Ftp:     "who uses this?",
		NoProxy: "10.0.3.1,localhost",
	}
	expected := `
export http_proxy=some-value
export HTTP_PROXY=some-value
export https_proxy=special
export HTTPS_PROXY=special
export ftp_proxy=who uses this?
export FTP_PROXY=who uses this?
export no_proxy=10.0.3.1,localhost
export NO_PROXY=10.0.3.1,localhost`[1:]
	c.Assert(proxies.AsScriptEnvironment(), gc.Equals, expected)
}

func (s *proxySuite) TestAsEnvironmentValuesEmpty(c *gc.C) {
	proxies := proxy.Settings{}
	c.Assert(proxies.AsEnvironmentValues(), gc.HasLen, 0)
}

func (s *proxySuite) TestAsEnvironmentValuesOneValue(c *gc.C) {
	proxies := proxy.Settings{
		Http: "some-value",
	}
	expected := []string{
		"http_proxy=some-value",
		"HTTP_PROXY=some-value",
	}
	c.Assert(proxies.AsEnvironmentValues(), gc.DeepEquals, expected)
}

func (s *proxySuite) TestAsEnvironmentValuesAllValue(c *gc.C) {
	proxies := proxy.Settings{
		Http:    "some-value",
		Https:   "special",
		Ftp:     "who uses this?",
		NoProxy: "10.0.3.1,localhost",
	}
	expected := []string{
		"http_proxy=some-value",
		"HTTP_PROXY=some-value",
		"https_proxy=special",
		"HTTPS_PROXY=special",
		"ftp_proxy=who uses this?",
		"FTP_PROXY=who uses this?",
		"no_proxy=10.0.3.1,localhost",
		"NO_PROXY=10.0.3.1,localhost",
	}
	c.Assert(proxies.AsEnvironmentValues(), gc.DeepEquals, expected)
}

func (s *proxySuite) TestSetEnvironmentValues(c *gc.C) {
	s.PatchEnvironment("http_proxy", "initial")
	s.PatchEnvironment("HTTP_PROXY", "initial")
	s.PatchEnvironment("https_proxy", "initial")
	s.PatchEnvironment("HTTPS_PROXY", "initial")
	s.PatchEnvironment("ftp_proxy", "initial")
	s.PatchEnvironment("FTP_PROXY", "initial")
	s.PatchEnvironment("no_proxy", "initial")
	s.PatchEnvironment("NO_PROXY", "initial")

	proxy := proxy.Settings{
		Http:  "http proxy",
		Https: "https proxy",
		// Ftp left blank to show clearing env.
		NoProxy: "10.0.3.1,localhost",
	}
	proxy.SetEnvironmentValues()

	obtained := osenv.DetectProxies()

	c.Assert(obtained, gc.DeepEquals, proxy)

	c.Assert(os.Getenv("http_proxy"), gc.Equals, "http proxy")
	c.Assert(os.Getenv("HTTP_PROXY"), gc.Equals, "http proxy")
	c.Assert(os.Getenv("https_proxy"), gc.Equals, "https proxy")
	c.Assert(os.Getenv("HTTPS_PROXY"), gc.Equals, "https proxy")
	c.Assert(os.Getenv("ftp_proxy"), gc.Equals, "")
	c.Assert(os.Getenv("FTP_PROXY"), gc.Equals, "")
	c.Assert(os.Getenv("no_proxy"), gc.Equals, "10.0.3.1,localhost")
	c.Assert(os.Getenv("NO_PROXY"), gc.Equals, "10.0.3.1,localhost")
}
<commit_msg>Replace DetectProxies.<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package proxy_test

import (
	"os"

	gc "launchpad.net/gocheck"

	"launchpad.net/juju-core/testing"
	"launchpad.net/juju-core/utils/proxy"
)

type proxySuite struct {
	testing.BaseSuite
}

var _ = gc.Suite(&proxySuite{})

func (s *proxySuite) TestDetectNoSettings(c *gc.C) {
	// Patch all of the environment variables we check out just in case the
	// user has one set.
	s.PatchEnvironment("http_proxy", "")
	s.PatchEnvironment("HTTP_PROXY", "")
	s.PatchEnvironment("https_proxy", "")
	s.PatchEnvironment("HTTPS_PROXY", "")
	s.PatchEnvironment("ftp_proxy", "")
	s.PatchEnvironment("FTP_PROXY", "")
	s.PatchEnvironment("no_proxy", "")
	s.PatchEnvironment("NO_PROXY", "")

	proxies := proxy.DetectProxies()

	c.Assert(proxies, gc.DeepEquals, proxy.Settings{})
}

func (s *proxySuite) TestDetectPrimary(c *gc.C) {
	// Patch all of the environment variables we check out just in case the
	// user has one set.
	s.PatchEnvironment("http_proxy", "http://user@10.0.0.1")
	s.PatchEnvironment("HTTP_PROXY", "")
	s.PatchEnvironment("https_proxy", "https://user@10.0.0.1")
	s.PatchEnvironment("HTTPS_PROXY", "")
	s.PatchEnvironment("ftp_proxy", "ftp://user@10.0.0.1")
	s.PatchEnvironment("FTP_PROXY", "")
	s.PatchEnvironment("no_proxy", "10.0.3.1,localhost")
	s.PatchEnvironment("NO_PROXY", "")

	proxies := proxy.DetectProxies()

	c.Assert(proxies, gc.DeepEquals, proxy.Settings{
		Http:    "http://user@10.0.0.1",
		Https:   "https://user@10.0.0.1",
		Ftp:     "ftp://user@10.0.0.1",
		NoProxy: "10.0.3.1,localhost",
	})
}

func (s *proxySuite) TestDetectFallback(c *gc.C) {
	// Patch all of the environment variables we check out just in case the
	// user has one set.
	s.PatchEnvironment("http_proxy", "")
	s.PatchEnvironment("HTTP_PROXY", "http://user@10.0.0.2")
	s.PatchEnvironment("https_proxy", "")
	s.PatchEnvironment("HTTPS_PROXY", "https://user@10.0.0.2")
	s.PatchEnvironment("ftp_proxy", "")
	s.PatchEnvironment("FTP_PROXY", "ftp://user@10.0.0.2")
	s.PatchEnvironment("no_proxy", "")
	s.PatchEnvironment("NO_PROXY", "10.0.3.1,localhost")

	proxies := proxy.DetectProxies()

	c.Assert(proxies, gc.DeepEquals, proxy.Settings{
		Http:    "http://user@10.0.0.2",
		Https:   "https://user@10.0.0.2",
		Ftp:     "ftp://user@10.0.0.2",
		NoProxy: "10.0.3.1,localhost",
	})
}

func (s *proxySuite) TestDetectPrimaryPreference(c *gc.C) {
	// Patch all of the environment variables we check out just in case the
	// user has one set.
	s.PatchEnvironment("http_proxy", "http://user@10.0.0.1")
	s.PatchEnvironment("https_proxy", "https://user@10.0.0.1")
	s.PatchEnvironment("ftp_proxy", "ftp://user@10.0.0.1")
	s.PatchEnvironment("no_proxy", "10.0.3.1,localhost")
	s.PatchEnvironment("HTTP_PROXY", "http://user@10.0.0.2")
	s.PatchEnvironment("HTTPS_PROXY", "https://user@10.0.0.2")
	s.PatchEnvironment("FTP_PROXY", "ftp://user@10.0.0.2")
	s.PatchEnvironment("NO_PROXY", "localhost")

	proxies := proxy.DetectProxies()

	c.Assert(proxies, gc.DeepEquals, proxy.Settings{
		Http:    "http://user@10.0.0.1",
		Https:   "https://user@10.0.0.1",
		Ftp:     "ftp://user@10.0.0.1",
		NoProxy: "10.0.3.1,localhost",
	})
}

func (s *proxySuite) TestAsScriptEnvironmentEmpty(c *gc.C) {
	proxies := proxy.Settings{}
	c.Assert(proxies.AsScriptEnvironment(), gc.Equals, "")
}

func (s *proxySuite) TestAsScriptEnvironmentOneValue(c *gc.C) {
	proxies := proxy.Settings{
		Http: "some-value",
	}
	expected := `
export http_proxy=some-value
export HTTP_PROXY=some-value`[1:]
	c.Assert(proxies.AsScriptEnvironment(), gc.Equals, expected)
}

func (s *proxySuite) TestAsScriptEnvironmentAllValue(c *gc.C) {
	proxies := proxy.Settings{
		Http:    "some-value",
		Https:   "special",
		Ftp:     "who uses this?",
		NoProxy: "10.0.3.1,localhost",
	}
	expected := `
export http_proxy=some-value
export HTTP_PROXY=some-value
export https_proxy=special
export HTTPS_PROXY=special
export ftp_proxy=who uses this?
export FTP_PROXY=who uses this?
export no_proxy=10.0.3.1,localhost
export NO_PROXY=10.0.3.1,localhost`[1:]
	c.Assert(proxies.AsScriptEnvironment(), gc.Equals, expected)
}

func (s *proxySuite) TestAsEnvironmentValuesEmpty(c *gc.C) {
	proxies := proxy.Settings{}
	c.Assert(proxies.AsEnvironmentValues(), gc.HasLen, 0)
}

func (s *proxySuite) TestAsEnvironmentValuesOneValue(c *gc.C) {
	proxies := proxy.Settings{
		Http: "some-value",
	}
	expected := []string{
		"http_proxy=some-value",
		"HTTP_PROXY=some-value",
	}
	c.Assert(proxies.AsEnvironmentValues(), gc.DeepEquals, expected)
}

func (s *proxySuite) TestAsEnvironmentValuesAllValue(c *gc.C) {
	proxies := proxy.Settings{
		Http:    "some-value",
		Https:   "special",
		Ftp:     "who uses this?",
		NoProxy: "10.0.3.1,localhost",
	}
	expected := []string{
		"http_proxy=some-value",
		"HTTP_PROXY=some-value",
		"https_proxy=special",
		"HTTPS_PROXY=special",
		"ftp_proxy=who uses this?",
		"FTP_PROXY=who uses this?",
		"no_proxy=10.0.3.1,localhost",
		"NO_PROXY=10.0.3.1,localhost",
	}
	c.Assert(proxies.AsEnvironmentValues(), gc.DeepEquals, expected)
}

func (s *proxySuite) TestSetEnvironmentValues(c *gc.C) {
	s.PatchEnvironment("http_proxy", "initial")
	s.PatchEnvironment("HTTP_PROXY", "initial")
	s.PatchEnvironment("https_proxy", "initial")
	s.PatchEnvironment("HTTPS_PROXY", "initial")
	s.PatchEnvironment("ftp_proxy", "initial")
	s.PatchEnvironment("FTP_PROXY", "initial")
	s.PatchEnvironment("no_proxy", "initial")
	s.PatchEnvironment("NO_PROXY", "initial")

	proxy := proxy.Settings{
		Http:  "http proxy",
		Https: "https proxy",
		// Ftp left blank to show clearing env.
		NoProxy: "10.0.3.1,localhost",
	}
	proxy.SetEnvironmentValues()

	obtained := proxy.DetectProxies()

	c.Assert(obtained, gc.DeepEquals, proxy)

	c.Assert(os.Getenv("http_proxy"), gc.Equals, "http proxy")
	c.Assert(os.Getenv("HTTP_PROXY"), gc.Equals, "http proxy")
	c.Assert(os.Getenv("https_proxy"), gc.Equals, "https proxy")
	c.Assert(os.Getenv("HTTPS_PROXY"), gc.Equals, "https proxy")
	c.Assert(os.Getenv("ftp_proxy"), gc.Equals, "")
	c.Assert(os.Getenv("FTP_PROXY"), gc.Equals, "")
	c.Assert(os.Getenv("no_proxy"), gc.Equals, "10.0.3.1,localhost")
	c.Assert(os.Getenv("NO_PROXY"), gc.Equals, "10.0.3.1,localhost")
}
<|endoftext|>


<commit_before>package monitoring

func GetDefaultThresholdValues() (plugins []Plugin) {
	return []Plugin{
		{
			Name:        "df",
			Description: "Mount Point Utilization",
			Enable:      true,
			Configs: []PluginConfig{
				{Category: THRESHOLD, Type: CRITICAL, Value: "90"},
				{Category: THRESHOLD, Type: WARNING, Value: "80"},
			},
		},
		{
			Name:        "memory",
			Description: "Memory",
			Enable:      true,
			Configs: []PluginConfig{
				{Category: THRESHOLD, Type: CRITICAL, Value: "90"},
				{Category: THRESHOLD, Type: WARNING, Value: "80"},
			},
		},
		{
			Name:        "cpu",
			Description: "CPU",
			Enable:      true,
			Configs: []PluginConfig{
				{Category: THRESHOLD, Type: CRITICAL, Value: "90"},
				{Category: THRESHOLD, Type: WARNING, Value: "80"},
			},
		},
		{
			Name:        "swap",
			Description: "Swap",
			Enable:      true,
			Configs: []PluginConfig{
				{Category: THRESHOLD, Type: CRITICAL, Value: "70"},
				{Category: THRESHOLD, Type: WARNING, Value: "50"},
			},
		},
	}
}

func GetSystemDefaultThresholdValues() map[string]Plugin {
	return map[string]Plugin{
		STORAGE_PROFILE_UTILIZATION: {
			Name:        STORAGE_PROFILE_UTILIZATION,
			Description: "Storage Profile",
			Enable:      true,
			Configs: []PluginConfig{
				{Category: THRESHOLD, Type: CRITICAL, Value: "85"},
				{Category: THRESHOLD, Type: WARNING, Value: "65"},
			},
		},
	}
}

var DefaultClusterMonitoringInterval = 600
<commit_msg>monitoring: Corrected description<commit_after>package monitoring

func GetDefaultThresholdValues() (plugins []Plugin) {
	return []Plugin{
		{
			Name:        "df",
			Description: "Mount Point",
			Enable:      true,
			Configs: []PluginConfig{
				{Category: THRESHOLD, Type: CRITICAL, Value: "90"},
				{Category: THRESHOLD, Type: WARNING, Value: "80"},
			},
		},
		{
			Name:        "memory",
			Description: "Memory",
			Enable:      true,
			Configs: []PluginConfig{
				{Category: THRESHOLD, Type: CRITICAL, Value: "90"},
				{Category: THRESHOLD, Type: WARNING, Value: "80"},
			},
		},
		{
			Name:        "cpu",
			Description: "CPU",
			Enable:      true,
			Configs: []PluginConfig{
				{Category: THRESHOLD, Type: CRITICAL, Value: "90"},
				{Category: THRESHOLD, Type: WARNING, Value: "80"},
			},
		},
		{
			Name:        "swap",
			Description: "Swap",
			Enable:      true,
			Configs: []PluginConfig{
				{Category: THRESHOLD, Type: CRITICAL, Value: "70"},
				{Category: THRESHOLD, Type: WARNING, Value: "50"},
			},
		},
	}
}

func GetSystemDefaultThresholdValues() map[string]Plugin {
	return map[string]Plugin{
		STORAGE_PROFILE_UTILIZATION: {
			Name:        STORAGE_PROFILE_UTILIZATION,
			Description: "Storage Profile",
			Enable:      true,
			Configs: []PluginConfig{
				{Category: THRESHOLD, Type: CRITICAL, Value: "85"},
				{Category: THRESHOLD, Type: WARNING, Value: "65"},
			},
		},
	}
}

var DefaultClusterMonitoringInterval = 600
<|endoftext|>


<commit_before>package ps

import (
	"encoding/csv"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"sort"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/gyuho/psn/table"
	"github.com/olekukonko/tablewriter"
)

// ProcessTableColumns is columns for CSV file.
var ProcessTableColumns = []string{
	"NAME",
	"STATE",

	"PID",
	"PPID",

	"CPU",
	"VM_RSS",
	"VM_SIZE",

	"FD",
	"THREADS",

	"CpuUsageFloat64",
	"VmRSSBytes",
	"VmSizeBytes",
}

// List finds the status by specifying the filter.
func List(filter *Process) ([]Process, error) {
	if filter != nil {
		if filter.Stat.Pid != 0 && filter.Status.Pid == 0 {
			filter.Status.Pid = filter.Stat.Pid
		}
		if filter.Stat.Pid == 0 && filter.Status.Pid != 0 {
			filter.Stat.Pid = filter.Status.Pid
		}
	}
	if filter != nil && filter.Stat.Pid != 0 && filter.Status.Pid != 0 {
		stat, err := GetStat(filter.Stat.Pid)
		if err != nil {
			return nil, err
		}
		status, err := GetStatus(filter.Status.Pid)
		if err != nil {
			return nil, err
		}
		return []Process{Process{Stat: stat, Status: status}}, err
	}

	ds, err := ioutil.ReadDir("/proc")
	if err != nil {
		return nil, err
	}
	pids := []int64{}
	for _, f := range ds {
		if f.IsDir() && isInt(f.Name()) {
			i, err := strconv.ParseInt(f.Name(), 10, 64)
			if err != nil {
				return nil, err
			}
			pids = append(pids, i)
		}
	}

	donec, errc := make(chan struct{}), make(chan error)
	rmap := make(map[int64]Process)
	var mu sync.Mutex

	for _, pid := range pids {
		go func(pid int64, filter *Process) {
			stat, err := GetStat(pid)
			if err != nil {
				errc <- err
				return
			}
			if stat.Match(filter) {
				mu.Lock()
				if v, ok := rmap[pid]; !ok {
					rmap[pid] = Process{Stat: stat}
				} else {
					v.Stat = stat
					rmap[pid] = v
				}
				mu.Unlock()
			}
			donec <- struct{}{}
		}(pid, filter)
		go func(pid int64, filter *Process) {
			status, err := GetStatus(pid)
			if err != nil {
				errc <- err
				return
			}
			if status.Match(filter) {
				mu.Lock()
				if v, ok := rmap[pid]; !ok {
					rmap[pid] = Process{Status: status}
				} else {
					v.Status = status
					rmap[pid] = v
				}
				mu.Unlock()
			}
			donec <- struct{}{}
		}(pid, filter)
	}

	cnt := 0
	for cnt != 2*len(pids) {
		select {
		case <-donec:
			cnt++
		case e := <-errc:
			return nil, e
		}
	}

	rs := []Process{}
	for _, proc := range rmap {
		if proc.Stat.Comm != proc.Status.Name {
			return nil, fmt.Errorf("%s != %s\n", proc.Stat.Comm, proc.Status.Name)
		}
		if proc.Stat.Pid != proc.Status.Pid {
			return nil, fmt.Errorf("%s : %d != %d\n", proc.Stat.Comm, proc.Stat.Pid, proc.Status.Pid)
		}
		rs = append(rs, proc)
	}
	return rs, nil
}

// Match matches Stat to filter. Only supports name and PID.
func (s *Stat) Match(filter *Process) bool {
	if s == nil {
		return false
	}
	if filter == nil {
		return true // no need to compare
	}
	name := filter.Stat.Comm
	if name != "" {
		if name != s.Comm {
			return false
		}
	}
	pid := filter.Stat.Pid
	if pid != 0 {
		if pid != s.Pid {
			return false
		}
	}
	return true
}

// Match matches Status to filter. Only supports name and PID.
func (s *Status) Match(filter *Process) bool {
	if s == nil {
		return false
	}
	if filter == nil {
		return true // no need to compare
	}
	name := filter.Status.Name
	if name != "" {
		if name != s.Name {
			return false
		}
	}
	pid := filter.Status.Pid
	if pid != 0 {
		if pid != s.Pid {
			return false
		}
	}
	state := filter.Status.State
	if state != "" {
		if state != s.State {
			return false
		}
	}
	return true
}

// WriteToTable writes slice of Process to ASCII table.
func WriteToTable(w io.Writer, top int, pss ...Process) {
	tw := tablewriter.NewWriter(w)
	tw.SetHeader(ProcessTableColumns[:9:9])

	rows := make([][]string, len(pss))
	for i, s := range pss {
		sl := make([]string, len(ProcessTableColumns))
		sl[0] = s.Status.Name
		sl[1] = s.Status.State
		sl[2] = fmt.Sprintf("%d", s.Status.Pid)
		sl[3] = fmt.Sprintf("%d", s.Status.PPid)
		sl[4] = fmt.Sprintf("%3.2f %%", s.Stat.CpuUsage)
		sl[5] = s.Status.VmRSS
		sl[6] = s.Status.VmSize
		sl[7] = fmt.Sprintf("%d", s.Status.FDSize)
		sl[8] = fmt.Sprintf("%d", s.Status.Threads)

		sl[9] = fmt.Sprintf("%3.2f", s.Stat.CpuUsage)
		sl[10] = fmt.Sprintf("%d", s.Status.VmRSSBytes)
		sl[11] = fmt.Sprintf("%d", s.Status.VmSizeBytes)
		rows[i] = sl
	}
	table.By(
		rows,
		table.MakeDescendingIntFunc(10),    // VM_RSS
		table.MakeDescendingFloat64Func(9), // CPU
		table.MakeDescendingIntFunc(11),    // VM_SIZE
	).Sort(rows)

	if top != 0 && len(rows) > top {
		rows = rows[:top:top]
	}
	for _, row := range rows {
		tw.Append(row[:9:9])
	}

	tw.Render()
}

var once sync.Once

// WriteToTable writes slice of Process to a csv file.
func WriteToCSV(f *os.File, pss ...Process) error {
	wr := csv.NewWriter(f)

	var werr error
	writeCSVHeader := func() {
		if err := wr.Write(append([]string{"unix_ts"}, ProcessTableColumns...)); err != nil {
			werr = err
		}
	}
	once.Do(writeCSVHeader)
	if werr != nil {
		return werr
	}

	rows := make([][]string, len(pss))
	for i, s := range pss {
		sl := make([]string, len(ProcessTableColumns))
		sl[0] = s.Status.Name
		sl[1] = s.Status.State
		sl[2] = fmt.Sprintf("%d", s.Status.Pid)
		sl[3] = fmt.Sprintf("%d", s.Status.PPid)
		sl[4] = fmt.Sprintf("%3.2f %%", s.Stat.CpuUsage)
		sl[5] = s.Status.VmRSS
		sl[6] = s.Status.VmSize
		sl[7] = fmt.Sprintf("%d", s.Status.FDSize)
		sl[8] = fmt.Sprintf("%d", s.Status.Threads)

		sl[9] = fmt.Sprintf("%3.2f", s.Stat.CpuUsage)
		sl[10] = fmt.Sprintf("%d", s.Status.VmRSSBytes)
		sl[11] = fmt.Sprintf("%d", s.Status.VmSizeBytes)
		rows[i] = sl
	}
	table.By(
		rows,
		table.MakeDescendingIntFunc(10),    // VM_RSS
		table.MakeDescendingFloat64Func(9), // CPU
		table.MakeDescendingIntFunc(11),    // VM_SIZE
	).Sort(rows)

	ts := fmt.Sprintf("%d", time.Now().Unix())
	nrows := make([][]string, len(rows))
	for i, row := range rows {
		nrows[i] = append([]string{ts}, row...)
	}
	if err := wr.WriteAll(nrows); err != nil {
		return err
	}

	wr.Flush()
	return wr.Error()
}

type int64Slice []int64

func (s int64Slice) Len() int           { return len(s) }
func (s int64Slice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s int64Slice) Less(i, j int) bool { return s[i] < s[j] }

// Kill kills all processes in arguments.
func Kill(w io.Writer, parent bool, pss ...Process) {
	defer func() {
		if err := recover(); err != nil {
			fmt.Fprintln(w, "Kill:", err)
		}
	}()

	pidToKill := make(map[int64]string)
	for _, s := range pss {
		pidToKill[s.Status.Pid] = s.Status.Name
		if parent && s.Status.PPid != 0 {
			pidToKill[s.Status.PPid] = s.Status.Name
		}
	}
	if len(pidToKill) == 0 {
		fmt.Fprintln(w, "no PID to kill...")
		return
	}

	pids := []int64{}
	for pid := range pidToKill {
		pids = append(pids, pid)
	}
	sort.Sort(int64Slice(pids))

	for _, pid := range pids {
		fmt.Fprintf(w, "\nsyscall.Kill: %s [PID: %d]\n", pidToKill[pid], pid)
		if err := syscall.Kill(int(pid), syscall.SIGTERM); err != nil {
			fmt.Fprintf(w, "syscall.SIGTERM error (%v)\n", err)

			shell := os.Getenv("SHELL")
			if len(shell) == 0 {
				shell = "sh"
			}
			args := []string{shell, "-c", fmt.Sprintf("sudo kill -9 %d", pid)}
			cmd := exec.Command(args[0], args[1:]...)
			cmd.Stdout = w
			cmd.Stderr = w
			fmt.Fprintf(w, "Starting: %q\n", strings.Join(cmd.Args, ""))
			if err := cmd.Start(); err != nil {
				fmt.Fprintf(w, "error when 'sudo kill -9' (%v)\n", err)
			}
			if err := cmd.Wait(); err != nil {
				fmt.Fprintf(w, "Start(%s) cmd.Wait returned %v\n", cmd.Path, err)
			}
			fmt.Fprintf(w, "    Done: %q\n", strings.Join(cmd.Args, ""))
		}
		if err := syscall.Kill(int(pid), syscall.SIGKILL); err != nil {
			fmt.Fprintf(w, "syscall.SIGKILL error (%v)\n", err)

			shell := os.Getenv("SHELL")
			if len(shell) == 0 {
				shell = "sh"
			}
			args := []string{shell, "-c", fmt.Sprintf("sudo kill -9 %d", pid)}
			cmd := exec.Command(args[0], args[1:]...)
			cmd.Stdout = w
			cmd.Stderr = w
			fmt.Fprintf(w, "Starting: %q\n", strings.Join(cmd.Args, ""))
			if err := cmd.Start(); err != nil {
				fmt.Fprintf(w, "error when 'sudo kill -9' (%v)\n", err)
			}
			if err := cmd.Wait(); err != nil {
				fmt.Fprintf(w, "Start(%s) cmd.Wait returned %v\n", cmd.Path, err)
			}
			fmt.Fprintf(w, "    Done: %q\n", strings.Join(cmd.Args, ""))
		}
	}
	fmt.Fprintln(w)
}
<commit_msg>ps: skip non-matching program<commit_after>package ps

import (
	"encoding/csv"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"sort"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/gyuho/psn/table"
	"github.com/olekukonko/tablewriter"
)

// ProcessTableColumns is columns for CSV file.
var ProcessTableColumns = []string{
	"NAME",
	"STATE",

	"PID",
	"PPID",

	"CPU",
	"VM_RSS",
	"VM_SIZE",

	"FD",
	"THREADS",

	"CpuUsageFloat64",
	"VmRSSBytes",
	"VmSizeBytes",
}

// List finds the status by specifying the filter.
func List(filter *Process) ([]Process, error) {
	if filter != nil {
		if filter.Stat.Pid != 0 && filter.Status.Pid == 0 {
			filter.Status.Pid = filter.Stat.Pid
		}
		if filter.Stat.Pid == 0 && filter.Status.Pid != 0 {
			filter.Stat.Pid = filter.Status.Pid
		}
	}
	if filter != nil && filter.Stat.Pid != 0 && filter.Status.Pid != 0 {
		stat, err := GetStat(filter.Stat.Pid)
		if err != nil {
			return nil, err
		}
		status, err := GetStatus(filter.Status.Pid)
		if err != nil {
			return nil, err
		}
		return []Process{Process{Stat: stat, Status: status}}, err
	}

	ds, err := ioutil.ReadDir("/proc")
	if err != nil {
		return nil, err
	}
	pids := []int64{}
	for _, f := range ds {
		if f.IsDir() && isInt(f.Name()) {
			i, err := strconv.ParseInt(f.Name(), 10, 64)
			if err != nil {
				return nil, err
			}
			pids = append(pids, i)
		}
	}

	donec, errc := make(chan struct{}), make(chan error)
	rmap := make(map[int64]Process)
	var mu sync.Mutex

	for _, pid := range pids {
		go func(pid int64, filter *Process) {
			stat, err := GetStat(pid)
			if err != nil {
				errc <- err
				return
			}
			if stat.Match(filter) {
				mu.Lock()
				if v, ok := rmap[pid]; !ok {
					rmap[pid] = Process{Stat: stat}
				} else {
					v.Stat = stat
					rmap[pid] = v
				}
				mu.Unlock()
			}
			donec <- struct{}{}
		}(pid, filter)
		go func(pid int64, filter *Process) {
			status, err := GetStatus(pid)
			if err != nil {
				errc <- err
				return
			}
			if status.Match(filter) {
				mu.Lock()
				if v, ok := rmap[pid]; !ok {
					rmap[pid] = Process{Status: status}
				} else {
					v.Status = status
					rmap[pid] = v
				}
				mu.Unlock()
			}
			donec <- struct{}{}
		}(pid, filter)
	}

	cnt := 0
	for cnt != 2*len(pids) {
		select {
		case <-donec:
			cnt++
		case e := <-errc:
			return nil, e
		}
	}

	rs := []Process{}
	for _, proc := range rmap {
		if proc.Stat.Comm != "" && proc.Status.Name == "" {
			proc.Stat.Comm = proc.Status.Name
			// return nil, fmt.Errorf("%s != %s\n", proc.Stat.Comm, proc.Status.Name)
		}
		if proc.Stat.Comm == "" && proc.Status.Name != "" {
			proc.Status.Name = proc.Stat.Comm
		}
		if proc.Stat.Pid != proc.Status.Pid {
			return nil, fmt.Errorf("%s : %d != %d\n", proc.Stat.Comm, proc.Stat.Pid, proc.Status.Pid)
		}
		rs = append(rs, proc)
	}
	return rs, nil
}

// Match matches Stat to filter. Only supports name and PID.
func (s *Stat) Match(filter *Process) bool {
	if s == nil {
		return false
	}
	if filter == nil {
		return true // no need to compare
	}
	name := filter.Stat.Comm
	if name != "" {
		if name != s.Comm {
			return false
		}
	}
	pid := filter.Stat.Pid
	if pid != 0 {
		if pid != s.Pid {
			return false
		}
	}
	return true
}

// Match matches Status to filter. Only supports name and PID.
func (s *Status) Match(filter *Process) bool {
	if s == nil {
		return false
	}
	if filter == nil {
		return true // no need to compare
	}
	name := filter.Status.Name
	if name != "" {
		if name != s.Name {
			return false
		}
	}
	pid := filter.Status.Pid
	if pid != 0 {
		if pid != s.Pid {
			return false
		}
	}
	state := filter.Status.State
	if state != "" {
		if state != s.State {
			return false
		}
	}
	return true
}

// WriteToTable writes slice of Process to ASCII table.
func WriteToTable(w io.Writer, top int, pss ...Process) {
	tw := tablewriter.NewWriter(w)
	tw.SetHeader(ProcessTableColumns[:9:9])

	rows := make([][]string, len(pss))
	for i, s := range pss {
		sl := make([]string, len(ProcessTableColumns))
		sl[0] = s.Status.Name
		sl[1] = s.Status.State
		sl[2] = fmt.Sprintf("%d", s.Status.Pid)
		sl[3] = fmt.Sprintf("%d", s.Status.PPid)
		sl[4] = fmt.Sprintf("%3.2f %%", s.Stat.CpuUsage)
		sl[5] = s.Status.VmRSS
		sl[6] = s.Status.VmSize
		sl[7] = fmt.Sprintf("%d", s.Status.FDSize)
		sl[8] = fmt.Sprintf("%d", s.Status.Threads)

		sl[9] = fmt.Sprintf("%3.2f", s.Stat.CpuUsage)
		sl[10] = fmt.Sprintf("%d", s.Status.VmRSSBytes)
		sl[11] = fmt.Sprintf("%d", s.Status.VmSizeBytes)
		rows[i] = sl
	}
	table.By(
		rows,
		table.MakeDescendingIntFunc(10),    // VM_RSS
		table.MakeDescendingFloat64Func(9), // CPU
		table.MakeDescendingIntFunc(11),    // VM_SIZE
	).Sort(rows)

	if top != 0 && len(rows) > top {
		rows = rows[:top:top]
	}
	for _, row := range rows {
		tw.Append(row[:9:9])
	}

	tw.Render()
}

var once sync.Once

// WriteToTable writes slice of Process to a csv file.
func WriteToCSV(f *os.File, pss ...Process) error {
	wr := csv.NewWriter(f)

	var werr error
	writeCSVHeader := func() {
		if err := wr.Write(append([]string{"unix_ts"}, ProcessTableColumns...)); err != nil {
			werr = err
		}
	}
	once.Do(writeCSVHeader)
	if werr != nil {
		return werr
	}

	rows := make([][]string, len(pss))
	for i, s := range pss {
		sl := make([]string, len(ProcessTableColumns))
		sl[0] = s.Status.Name
		sl[1] = s.Status.State
		sl[2] = fmt.Sprintf("%d", s.Status.Pid)
		sl[3] = fmt.Sprintf("%d", s.Status.PPid)
		sl[4] = fmt.Sprintf("%3.2f %%", s.Stat.CpuUsage)
		sl[5] = s.Status.VmRSS
		sl[6] = s.Status.VmSize
		sl[7] = fmt.Sprintf("%d", s.Status.FDSize)
		sl[8] = fmt.Sprintf("%d", s.Status.Threads)

		sl[9] = fmt.Sprintf("%3.2f", s.Stat.CpuUsage)
		sl[10] = fmt.Sprintf("%d", s.Status.VmRSSBytes)
		sl[11] = fmt.Sprintf("%d", s.Status.VmSizeBytes)
		rows[i] = sl
	}
	table.By(
		rows,
		table.MakeDescendingIntFunc(10),    // VM_RSS
		table.MakeDescendingFloat64Func(9), // CPU
		table.MakeDescendingIntFunc(11),    // VM_SIZE
	).Sort(rows)

	ts := fmt.Sprintf("%d", time.Now().Unix())
	nrows := make([][]string, len(rows))
	for i, row := range rows {
		nrows[i] = append([]string{ts}, row...)
	}
	if err := wr.WriteAll(nrows); err != nil {
		return err
	}

	wr.Flush()
	return wr.Error()
}

type int64Slice []int64

func (s int64Slice) Len() int           { return len(s) }
func (s int64Slice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s int64Slice) Less(i, j int) bool { return s[i] < s[j] }

// Kill kills all processes in arguments.
func Kill(w io.Writer, parent bool, pss ...Process) {
	defer func() {
		if err := recover(); err != nil {
			fmt.Fprintln(w, "Kill:", err)
		}
	}()

	pidToKill := make(map[int64]string)
	for _, s := range pss {
		pidToKill[s.Status.Pid] = s.Status.Name
		if parent && s.Status.PPid != 0 {
			pidToKill[s.Status.PPid] = s.Status.Name
		}
	}
	if len(pidToKill) == 0 {
		fmt.Fprintln(w, "no PID to kill...")
		return
	}

	pids := []int64{}
	for pid := range pidToKill {
		pids = append(pids, pid)
	}
	sort.Sort(int64Slice(pids))

	for _, pid := range pids {
		fmt.Fprintf(w, "\nsyscall.Kill: %s [PID: %d]\n", pidToKill[pid], pid)
		if err := syscall.Kill(int(pid), syscall.SIGTERM); err != nil {
			fmt.Fprintf(w, "syscall.SIGTERM error (%v)\n", err)

			shell := os.Getenv("SHELL")
			if len(shell) == 0 {
				shell = "sh"
			}
			args := []string{shell, "-c", fmt.Sprintf("sudo kill -9 %d", pid)}
			cmd := exec.Command(args[0], args[1:]...)
			cmd.Stdout = w
			cmd.Stderr = w
			fmt.Fprintf(w, "Starting: %q\n", strings.Join(cmd.Args, ""))
			if err := cmd.Start(); err != nil {
				fmt.Fprintf(w, "error when 'sudo kill -9' (%v)\n", err)
			}
			if err := cmd.Wait(); err != nil {
				fmt.Fprintf(w, "Start(%s) cmd.Wait returned %v\n", cmd.Path, err)
			}
			fmt.Fprintf(w, "    Done: %q\n", strings.Join(cmd.Args, ""))
		}
		if err := syscall.Kill(int(pid), syscall.SIGKILL); err != nil {
			fmt.Fprintf(w, "syscall.SIGKILL error (%v)\n", err)

			shell := os.Getenv("SHELL")
			if len(shell) == 0 {
				shell = "sh"
			}
			args := []string{shell, "-c", fmt.Sprintf("sudo kill -9 %d", pid)}
			cmd := exec.Command(args[0], args[1:]...)
			cmd.Stdout = w
			cmd.Stderr = w
			fmt.Fprintf(w, "Starting: %q\n", strings.Join(cmd.Args, ""))
			if err := cmd.Start(); err != nil {
				fmt.Fprintf(w, "error when 'sudo kill -9' (%v)\n", err)
			}
			if err := cmd.Wait(); err != nil {
				fmt.Fprintf(w, "Start(%s) cmd.Wait returned %v\n", cmd.Path, err)
			}
			fmt.Fprintf(w, "    Done: %q\n", strings.Join(cmd.Args, ""))
		}
	}
	fmt.Fprintln(w)
}
<|endoftext|>


<commit_before>package common

import (
	"encoding/json"
	"net/http"
	. "router/common/http"
)

func init() {
	http.HandleFunc("/healthz", func(w http.ResponseWriter, req *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(200)

		enc := json.NewEncoder(w)
		enc.Encode(UpdateHealthz())
	})

	http.HandleFunc("/varz", func(w http.ResponseWriter, req *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(200)

		enc := json.NewEncoder(w)
		enc.Encode(UpdateVarz())
	})
}

func startStatusServer() {
	f := func(user, password string) bool {
		return user == Component.Credentials[0] && password == Component.Credentials[1]
	}

	s := &http.Server{
		Addr:    Component.Host,
		Handler: &BasicAuth{http.DefaultServeMux, f},
	}

	s.ListenAndServe()
}
<commit_msg>Use http constant instead of raw status code<commit_after>package common

import (
	"encoding/json"
	"net/http"
	. "router/common/http"
)

func init() {
	http.HandleFunc("/healthz", func(w http.ResponseWriter, req *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)

		enc := json.NewEncoder(w)
		enc.Encode(UpdateHealthz())
	})

	http.HandleFunc("/varz", func(w http.ResponseWriter, req *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)

		enc := json.NewEncoder(w)
		enc.Encode(UpdateVarz())
	})
}

func startStatusServer() {
	f := func(user, password string) bool {
		return user == Component.Credentials[0] && password == Component.Credentials[1]
	}

	s := &http.Server{
		Addr:    Component.Host,
		Handler: &BasicAuth{http.DefaultServeMux, f},
	}

	s.ListenAndServe()
}
<|endoftext|>