<commit_before>package cdsclient

import (
	"crypto/tls"
	"io"
	"net/http"
	"os"
	"time"

	"github.com/facebookgo/httpcontrol"
	"github.com/ovh/cds/sdk"
)

type client struct {
	isWorker   bool
	isHatchery bool
	isService  bool
	HTTPClient HTTPClient
	config     Config
	name       string
}

// New returns a client from a config struct
func New(c Config) Interface {
	cli := new(client)
	cli.config = c
	cli.HTTPClient = &http.Client{
		Timeout: time.Second * 60,
	}
	cli.init()
	return cli
}

// NewService returns client for a service
func NewService(endpoint string, timeout time.Duration) Interface {
	conf := Config{
		Host:  endpoint,
		Retry: 2,
	}
	cli := new(client)
	cli.config = conf
	cli.HTTPClient = &http.Client{
		Timeout: timeout,
	}
	cli.isService = true
	cli.init()
	return cli
}

// NewWorker returns client for a worker
func NewWorker(endpoint string, name string, c HTTPClient) Interface {
	conf := Config{
		Host:  endpoint,
		Retry: 10,
	}
	cli := new(client)
	cli.config = conf

	if c == nil {
		cli.HTTPClient = &http.Client{Timeout: time.Second * 10}
	} else {
		cli.HTTPClient = c
		sdk.SetHTTPClient(c)
	}

	cli.isWorker = true
	cli.name = name
	cli.init()
	return cli
}

// NewHatchery returns client for a hatchery
func NewHatchery(endpoint string, token string, requestSecondsTimeout int, insecureSkipVerifyTLS bool, name string) Interface {
	conf := Config{
		Host:  endpoint,
		Retry: 2,
		Token: token,
	}
	cli := new(client)
	cli.config = conf
	cli.HTTPClient = &http.Client{
		Transport: &httpcontrol.Transport{
			RequestTimeout:  time.Duration(requestSecondsTimeout) * time.Second,
			MaxTries:        5,
			TLSClientConfig: &tls.Config{InsecureSkipVerify: insecureSkipVerifyTLS},
		},
	}

	// hatchery don't need to make a request without timeout on API
	cli.isHatchery = true
	cli.name = name
	cli.init()
	return cli
}

// NewClientFromConfig returns a client from the config file
func NewClientFromConfig(r io.Reader) (Interface, error) {
	return nil, nil
}

// NewClientFromEnv returns a client from the environment variables
func NewClientFromEnv() (Interface, error) {
	return nil, nil
}

func (c *client) init() {
	if c.isWorker {
		c.config.userAgent = sdk.WorkerAgent
	} else if c.isHatchery {
		c.config.userAgent = sdk.HatcheryAgent
	} else if c.isService {
		c.config.userAgent = sdk.ServiceAgent
	} else {
		c.config.userAgent = sdk.SDKAgent
	}

	if os.Getenv("CDS_VERBOSE") == "true" {
		c.config.Verbose = true
	}
}

func (c *client) APIURL() string {
	return c.config.Host
}
<commit_msg>fix (worker): don't init sdk http client (#2180)<commit_after>package cdsclient

import (
	"crypto/tls"
	"io"
	"net/http"
	"os"
	"time"

	"github.com/facebookgo/httpcontrol"
	"github.com/ovh/cds/sdk"
)

type client struct {
	isWorker   bool
	isHatchery bool
	isService  bool
	HTTPClient HTTPClient
	config     Config
	name       string
}

// New returns a client from a config struct
func New(c Config) Interface {
	cli := new(client)
	cli.config = c
	cli.HTTPClient = &http.Client{
		Timeout: time.Second * 60,
	}
	cli.init()
	return cli
}

// NewService returns client for a service
func NewService(endpoint string, timeout time.Duration) Interface {
	conf := Config{
		Host:  endpoint,
		Retry: 2,
	}
	cli := new(client)
	cli.config = conf
	cli.HTTPClient = &http.Client{
		Timeout: timeout,
	}
	cli.isService = true
	cli.init()
	return cli
}

// NewWorker returns client for a worker
func NewWorker(endpoint string, name string, c HTTPClient) Interface {
	conf := Config{
		Host:  endpoint,
		Retry: 10,
	}
	cli := new(client)
	cli.config = conf

	if c == nil {
		cli.HTTPClient = &http.Client{Timeout: time.Second * 10}
	} else {
		cli.HTTPClient = c
	}

	cli.isWorker = true
	cli.name = name
	cli.init()
	return cli
}

// NewHatchery returns client for a hatchery
func NewHatchery(endpoint string, token string, requestSecondsTimeout int, insecureSkipVerifyTLS bool, name string) Interface {
	conf := Config{
		Host:  endpoint,
		Retry: 2,
		Token: token,
	}
	cli := new(client)
	cli.config = conf
	cli.HTTPClient = &http.Client{
		Transport: &httpcontrol.Transport{
			RequestTimeout:  time.Duration(requestSecondsTimeout) * time.Second,
			MaxTries:        5,
			TLSClientConfig: &tls.Config{InsecureSkipVerify: insecureSkipVerifyTLS},
		},
	}

	// hatchery don't need to make a request without timeout on API
	cli.isHatchery = true
	cli.name = name
	cli.init()
	return cli
}

// NewClientFromConfig returns a client from the config file
func NewClientFromConfig(r io.Reader) (Interface, error) {
	return nil, nil
}

// NewClientFromEnv returns a client from the environment variables
func NewClientFromEnv() (Interface, error) {
	return nil, nil
}

func (c *client) init() {
	if c.isWorker {
		c.config.userAgent = sdk.WorkerAgent
	} else if c.isHatchery {
		c.config.userAgent = sdk.HatcheryAgent
	} else if c.isService {
		c.config.userAgent = sdk.ServiceAgent
	} else {
		c.config.userAgent = sdk.SDKAgent
	}

	if os.Getenv("CDS_VERBOSE") == "true" {
		c.config.Verbose = true
	}
}

func (c *client) APIURL() string {
	return c.config.Host
}
<|endoftext|>


<commit_before>/*
   Copyright 2015 Cesanta Software Ltd.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       https://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package authn

import (
	"bytes"
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"strings"

	"github.com/go-ldap/ldap"
	"github.com/golang/glog"
)

type LDAPAuthConfig struct {
	Addr                  string `yaml:"addr,omitempty"`
	TLS                   string `yaml:"tls,omitempty"`
	InsecureTLSSkipVerify bool   `yaml:"insecure_tls_skip_verify,omitempty"`
	Base                  string `yaml:"base,omitempty"`
	Filter                string `yaml:"filter,omitempty"`
	BindDN                string `yaml:"bind_dn,omitempty"`
	BindPasswordFile      string `yaml:"bind_password_file,omitempty"`
	GroupBaseDN           string `yaml:"group_base_dn,omitempty"`
	GroupFilter           string `yaml:"group_filter,omitempty"`
}

type LDAPAuth struct {
	config *LDAPAuthConfig
}

func NewLDAPAuth(c *LDAPAuthConfig) (*LDAPAuth, error) {
	if c.TLS == "" && strings.HasSuffix(c.Addr, ":636") {
		c.TLS = "always"
	}
	return &LDAPAuth{
		config: c,
	}, nil
}

//How to authenticate user, please refer to https://github.com/go-ldap/ldap/blob/master/example_test.go#L166
func (la *LDAPAuth) Authenticate(account string, password PasswordString) (bool, error) {
	if account == "" {
		return false, NoMatch
	}
	l, err := la.ldapConnection()
	if err != nil {
		return false, err
	}
	defer l.Close()

	// First bind with a read only user, to prevent the following search won't perform any write action
	if bindErr := la.bindReadOnlyUser(l); bindErr != nil {
		return false, bindErr
	}

	account = la.escapeAccountInput(account)

	filter := la.getFilter(account)
	accountEntryDN, uSearchErr := la.ldapSearch(l, &la.config.Base, &filter, &[]string{})
	if uSearchErr != nil {
		return false, uSearchErr
	}
	if accountEntryDN == "" {
		return false, nil // User does not exist
	}
	// Bind as the user to verify their password
	if len(accountEntryDN) > 0 {
		err := l.Bind(accountEntryDN, string(password))
		if err != nil {
			if ldap.IsErrorWithCode(err, ldap.LDAPResultInvalidCredentials) {
				return false, nil
			}
			return false, err
		}
	}
	// Rebind as the read only user for any futher queries
	if bindErr := la.bindReadOnlyUser(l); bindErr != nil {
		return false, bindErr
	}

	return true, nil
}

func (la *LDAPAuth) bindReadOnlyUser(l *ldap.Conn) error {
	if la.config.BindDN != "" {
		password, err := ioutil.ReadFile(la.config.BindPasswordFile)
		if err != nil {
			return err
		}
		password_str := strings.TrimSpace(string(password))
		glog.V(2).Infof("Bind read-only user (DN = %s)", la.config.BindDN)
		err = l.Bind(la.config.BindDN, password_str)
		if err != nil {
			return err
		}
	}
	return nil
}

//To prevent LDAP injection, some characters must be escaped for searching
//e.g. char '\' will be replaced by hex '\5c'
//Filter meta chars are choosen based on filter complier code
//https://github.com/go-ldap/ldap/blob/master/filter.go#L159
func (la *LDAPAuth) escapeAccountInput(account string) string {
	r := strings.NewReplacer(
		`\`, `\5c`,
		`(`, `\28`,
		`)`, `\29`,
		`!`, `\21`,
		`*`, `\2a`,
		`&`, `\26`,
		`|`, `\7c`,
		`=`, `\3d`,
		`>`, `\3e`,
		`<`, `\3c`,
		`~`, `\7e`,
	)
	return r.Replace(account)
}

func (la *LDAPAuth) ldapConnection() (*ldap.Conn, error) {
	var l *ldap.Conn
	var err error
	if la.config.TLS == "" || la.config.TLS == "none" || la.config.TLS == "starttls" {
		glog.V(2).Infof("Dial: starting...%s", la.config.Addr)
		l, err = ldap.Dial("tcp", fmt.Sprintf("%s", la.config.Addr))
		if err == nil && la.config.TLS == "starttls" {
			glog.V(2).Infof("StartTLS...")
			if tlserr := l.StartTLS(&tls.Config{InsecureSkipVerify: la.config.InsecureTLSSkipVerify}); tlserr != nil {
				return nil, tlserr
			}
		}
	} else if la.config.TLS == "always" {
		glog.V(2).Infof("DialTLS: starting...%s", la.config.Addr)
		l, err = ldap.DialTLS("tcp", fmt.Sprintf("%s", la.config.Addr), &tls.Config{InsecureSkipVerify: la.config.InsecureTLSSkipVerify})
	}
	if err != nil {
		return nil, err
	}
	return l, nil
}

func (la *LDAPAuth) getFilter(account string) string {
	filter := strings.NewReplacer("${account}", account).Replace(la.config.Filter)
	glog.V(2).Infof("search filter is %s", filter)
	return filter
}

//ldap search and return required attributes' value from searched entries
//default return entry's DN value if you leave attrs array empty
func (la *LDAPAuth) ldapSearch(l *ldap.Conn, baseDN *string, filter *string, attrs *[]string) (string, error) {
	if l == nil {
		return "", fmt.Errorf("No ldap connection!")
	}
	glog.V(2).Infof("Searching...basedDN:%s, filter:%s", *baseDN, *filter)
	searchRequest := ldap.NewSearchRequest(
		*baseDN,
		ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
		*filter,
		*attrs,
		nil)
	sr, err := l.Search(searchRequest)
	if err != nil {
		return "", err
	}

	if len(sr.Entries) == 0 {
		return "", nil // User does not exist
	} else if len(sr.Entries) > 1 {
		return "", fmt.Errorf("Too many entries returned.")
	}

	var buffer bytes.Buffer
	for _, entry := range sr.Entries {
		if len(*attrs) == 0 {
			glog.V(2).Infof("Entry DN = %s", entry.DN)
			buffer.WriteString(entry.DN)
		} else {
			for _, attr := range *attrs {
				values := strings.Join(entry.GetAttributeValues(attr), " ")
				glog.V(2).Infof("Entry %s = %s", attr, values)
				buffer.WriteString(values)
			}
		}
	}

	return buffer.String(), nil
}

func (la *LDAPAuth) Stop() {
}

func (la *LDAPAuth) Name() string {
	return "LDAP"
}
<commit_msg>Return NoMatch when user does not exist in LDAP<commit_after>/*
   Copyright 2015 Cesanta Software Ltd.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       https://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package authn

import (
	"bytes"
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"strings"

	"github.com/go-ldap/ldap"
	"github.com/golang/glog"
)

type LDAPAuthConfig struct {
	Addr                  string `yaml:"addr,omitempty"`
	TLS                   string `yaml:"tls,omitempty"`
	InsecureTLSSkipVerify bool   `yaml:"insecure_tls_skip_verify,omitempty"`
	Base                  string `yaml:"base,omitempty"`
	Filter                string `yaml:"filter,omitempty"`
	BindDN                string `yaml:"bind_dn,omitempty"`
	BindPasswordFile      string `yaml:"bind_password_file,omitempty"`
	GroupBaseDN           string `yaml:"group_base_dn,omitempty"`
	GroupFilter           string `yaml:"group_filter,omitempty"`
}

type LDAPAuth struct {
	config *LDAPAuthConfig
}

func NewLDAPAuth(c *LDAPAuthConfig) (*LDAPAuth, error) {
	if c.TLS == "" && strings.HasSuffix(c.Addr, ":636") {
		c.TLS = "always"
	}
	return &LDAPAuth{
		config: c,
	}, nil
}

//How to authenticate user, please refer to https://github.com/go-ldap/ldap/blob/master/example_test.go#L166
func (la *LDAPAuth) Authenticate(account string, password PasswordString) (bool, error) {
	if account == "" {
		return false, NoMatch
	}
	l, err := la.ldapConnection()
	if err != nil {
		return false, err
	}
	defer l.Close()

	// First bind with a read only user, to prevent the following search won't perform any write action
	if bindErr := la.bindReadOnlyUser(l); bindErr != nil {
		return false, bindErr
	}

	account = la.escapeAccountInput(account)

	filter := la.getFilter(account)
	accountEntryDN, uSearchErr := la.ldapSearch(l, &la.config.Base, &filter, &[]string{})
	if uSearchErr != nil {
		return false, uSearchErr
	}
	if accountEntryDN == "" {
		return false, NoMatch // User does not exist
	}
	// Bind as the user to verify their password
	if len(accountEntryDN) > 0 {
		err := l.Bind(accountEntryDN, string(password))
		if err != nil {
			if ldap.IsErrorWithCode(err, ldap.LDAPResultInvalidCredentials) {
				return false, nil
			}
			return false, err
		}
	}
	// Rebind as the read only user for any futher queries
	if bindErr := la.bindReadOnlyUser(l); bindErr != nil {
		return false, bindErr
	}

	return true, nil
}

func (la *LDAPAuth) bindReadOnlyUser(l *ldap.Conn) error {
	if la.config.BindDN != "" {
		password, err := ioutil.ReadFile(la.config.BindPasswordFile)
		if err != nil {
			return err
		}
		password_str := strings.TrimSpace(string(password))
		glog.V(2).Infof("Bind read-only user (DN = %s)", la.config.BindDN)
		err = l.Bind(la.config.BindDN, password_str)
		if err != nil {
			return err
		}
	}
	return nil
}

//To prevent LDAP injection, some characters must be escaped for searching
//e.g. char '\' will be replaced by hex '\5c'
//Filter meta chars are choosen based on filter complier code
//https://github.com/go-ldap/ldap/blob/master/filter.go#L159
func (la *LDAPAuth) escapeAccountInput(account string) string {
	r := strings.NewReplacer(
		`\`, `\5c`,
		`(`, `\28`,
		`)`, `\29`,
		`!`, `\21`,
		`*`, `\2a`,
		`&`, `\26`,
		`|`, `\7c`,
		`=`, `\3d`,
		`>`, `\3e`,
		`<`, `\3c`,
		`~`, `\7e`,
	)
	return r.Replace(account)
}

func (la *LDAPAuth) ldapConnection() (*ldap.Conn, error) {
	var l *ldap.Conn
	var err error
	if la.config.TLS == "" || la.config.TLS == "none" || la.config.TLS == "starttls" {
		glog.V(2).Infof("Dial: starting...%s", la.config.Addr)
		l, err = ldap.Dial("tcp", fmt.Sprintf("%s", la.config.Addr))
		if err == nil && la.config.TLS == "starttls" {
			glog.V(2).Infof("StartTLS...")
			if tlserr := l.StartTLS(&tls.Config{InsecureSkipVerify: la.config.InsecureTLSSkipVerify}); tlserr != nil {
				return nil, tlserr
			}
		}
	} else if la.config.TLS == "always" {
		glog.V(2).Infof("DialTLS: starting...%s", la.config.Addr)
		l, err = ldap.DialTLS("tcp", fmt.Sprintf("%s", la.config.Addr), &tls.Config{InsecureSkipVerify: la.config.InsecureTLSSkipVerify})
	}
	if err != nil {
		return nil, err
	}
	return l, nil
}

func (la *LDAPAuth) getFilter(account string) string {
	filter := strings.NewReplacer("${account}", account).Replace(la.config.Filter)
	glog.V(2).Infof("search filter is %s", filter)
	return filter
}

//ldap search and return required attributes' value from searched entries
//default return entry's DN value if you leave attrs array empty
func (la *LDAPAuth) ldapSearch(l *ldap.Conn, baseDN *string, filter *string, attrs *[]string) (string, error) {
	if l == nil {
		return "", fmt.Errorf("No ldap connection!")
	}
	glog.V(2).Infof("Searching...basedDN:%s, filter:%s", *baseDN, *filter)
	searchRequest := ldap.NewSearchRequest(
		*baseDN,
		ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
		*filter,
		*attrs,
		nil)
	sr, err := l.Search(searchRequest)
	if err != nil {
		return "", err
	}

	if len(sr.Entries) == 0 {
		return "", nil // User does not exist
	} else if len(sr.Entries) > 1 {
		return "", fmt.Errorf("Too many entries returned.")
	}

	var buffer bytes.Buffer
	for _, entry := range sr.Entries {
		if len(*attrs) == 0 {
			glog.V(2).Infof("Entry DN = %s", entry.DN)
			buffer.WriteString(entry.DN)
		} else {
			for _, attr := range *attrs {
				values := strings.Join(entry.GetAttributeValues(attr), " ")
				glog.V(2).Infof("Entry %s = %s", attr, values)
				buffer.WriteString(values)
			}
		}
	}

	return buffer.String(), nil
}

func (la *LDAPAuth) Stop() {
}

func (la *LDAPAuth) Name() string {
	return "LDAP"
}
<|endoftext|>


<commit_before>// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package testbed

import (
	"fmt"
	"io"
	"log"
	"os"
	"path"
	"time"
)

type Results struct {
	resultsDir     string
	resultsFile    *os.File
	perTestResults []*TestResult
	totalDuration  time.Duration
}

var results = Results{}

type TestResult struct {
	testName          string
	result            string
	duration          time.Duration
	cpuPercentageAvg  float64
	cpuPercentageMax  float64
	ramMibAvg         uint32
	ramMibMax         uint32
	sentSpanCount     uint64
	receivedSpanCount uint64
	errorCause        string
}

func (r *Results) Init(resultsDir string) {
	r.resultsDir = resultsDir
	r.perTestResults = []*TestResult{}

	// Create results file
	var err error
	r.resultsFile, err = os.Create(path.Join(r.resultsDir, "TESTRESULTS.md"))
	if err != nil {
		log.Fatalf(err.Error())
	}

	// Write the header
	_, _ = io.WriteString(r.resultsFile,
		"# Test Results\n"+
			fmt.Sprintf("Started: %s\n\n", time.Now().Format(time.RFC1123Z))+
			"Test                                    |Result|Duration|CPU Avg%|CPU Max%|RAM Avg MiB|RAM Max MiB|Sent Items|Received Items|\n"+
			"----------------------------------------|------|-------:|-------:|-------:|----------:|----------:|---------:|-------------:|\n")
}

// Save the total results and close the file.
func (r *Results) Save() {
	_, _ = io.WriteString(r.resultsFile,
		fmt.Sprintf("\nTotal duration: %.0fs\n", r.totalDuration.Seconds()))
	r.resultsFile.Close()
}

// Add results for one test.
func (r *Results) Add(testName string, result *TestResult) {
	_, _ = io.WriteString(r.resultsFile,
		fmt.Sprintf("%-40s|%-6s|%7.0fs|%8.1f|%8.1f|%11d|%11d|%10d|%14d|%s\n",
			result.testName,
			result.result,
			result.duration.Seconds(),
			result.cpuPercentageAvg,
			result.cpuPercentageMax,
			result.ramMibAvg,
			result.ramMibMax,
			result.sentSpanCount,
			result.receivedSpanCount,
			result.errorCause,
		),
	)
	r.totalDuration = r.totalDuration + result.duration
}
<commit_msg>Create results directory if it doesn't exist during testbed setup (#1116)<commit_after>// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package testbed

import (
	"fmt"
	"io"
	"log"
	"os"
	"path"
	"time"
)

type Results struct {
	resultsDir     string
	resultsFile    *os.File
	perTestResults []*TestResult
	totalDuration  time.Duration
}

var results = Results{}

type TestResult struct {
	testName          string
	result            string
	duration          time.Duration
	cpuPercentageAvg  float64
	cpuPercentageMax  float64
	ramMibAvg         uint32
	ramMibMax         uint32
	sentSpanCount     uint64
	receivedSpanCount uint64
	errorCause        string
}

func (r *Results) Init(resultsDir string) {
	r.resultsDir = resultsDir
	r.perTestResults = []*TestResult{}

	// Create results directory if it does not exist
	if _, err := os.Stat(r.resultsDir); os.IsNotExist(err) {
		os.Mkdir(r.resultsDir, os.FileMode(0755))
	}

	// Create results file
	var err error
	r.resultsFile, err = os.Create(path.Join(r.resultsDir, "TESTRESULTS.md"))
	if err != nil {
		log.Fatalf(err.Error())
	}

	// Write the header
	_, _ = io.WriteString(r.resultsFile,
		"# Test Results\n"+
			fmt.Sprintf("Started: %s\n\n", time.Now().Format(time.RFC1123Z))+
			"Test                                    |Result|Duration|CPU Avg%|CPU Max%|RAM Avg MiB|RAM Max MiB|Sent Items|Received Items|\n"+
			"----------------------------------------|------|-------:|-------:|-------:|----------:|----------:|---------:|-------------:|\n")
}

// Save the total results and close the file.
func (r *Results) Save() {
	_, _ = io.WriteString(r.resultsFile,
		fmt.Sprintf("\nTotal duration: %.0fs\n", r.totalDuration.Seconds()))
	r.resultsFile.Close()
}

// Add results for one test.
func (r *Results) Add(testName string, result *TestResult) {
	_, _ = io.WriteString(r.resultsFile,
		fmt.Sprintf("%-40s|%-6s|%7.0fs|%8.1f|%8.1f|%11d|%11d|%10d|%14d|%s\n",
			result.testName,
			result.result,
			result.duration.Seconds(),
			result.cpuPercentageAvg,
			result.cpuPercentageMax,
			result.ramMibAvg,
			result.ramMibMax,
			result.sentSpanCount,
			result.receivedSpanCount,
			result.errorCause,
		),
	)
	r.totalDuration = r.totalDuration + result.duration
}
<|endoftext|>


<commit_before>// Copyright 2016 LINE Corporation
//
// LINE Corporation licenses this file to you under the Apache License,
// version 2.0 (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at:
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package linebot

import (
	"errors"
	"io"
	"net/http"
	"net/url"
	"path"

	"golang.org/x/net/context"
	"golang.org/x/net/context/ctxhttp"
)

// APIEndpoint constants
const (
	APIEndpointBase = "https://api.line.me"

	APIEndpointPushMessage       = "/v2/bot/message/push"
	APIEndpointReplyMessage      = "/v2/bot/message/reply"
	APIEndpointGetMessageContent = "/v2/bot/message/%s/content"
	APIEndpointLeaveGroup        = "/v2/bot/group/%s/leave"
	APIEndpointLeaveRoom         = "/v2/bot/room/%s/leave"
	APIEndpointGetProfile        = "/v2/bot/profile/%s"
)

// Client type
type Client struct {
	channelSecret string
	channelToken  string
	endpointBase  *url.URL     // default APIEndpointBase
	httpClient    *http.Client // default http.DefaultClient
}

// ClientOption type
type ClientOption func(*Client) error

// New returns a new bot client instance.
func New(channelSecret, channelToken string, options ...ClientOption) (*Client, error) {
	if channelSecret == "" {
		return nil, errors.New("missing channel secret")
	}
	if channelToken == "" {
		return nil, errors.New("missing channel access token")
	}
	c := &Client{
		channelSecret: channelSecret,
		channelToken:  channelToken,
		httpClient:    http.DefaultClient,
	}
	for _, option := range options {
		err := option(c)
		if err != nil {
			return nil, err
		}
	}
	if c.endpointBase == nil {
		u, err := url.ParseRequestURI(APIEndpointBase)
		if err != nil {
			return nil, err
		}
		c.endpointBase = u
	}
	return c, nil
}

// WithHTTPClient function
func WithHTTPClient(c *http.Client) ClientOption {
	return func(client *Client) error {
		client.httpClient = c
		return nil
	}
}

// WithEndpointBase function
func WithEndpointBase(endpointBase string) ClientOption {
	return func(client *Client) error {
		u, err := url.ParseRequestURI(endpointBase)
		if err != nil {
			return err
		}
		client.endpointBase = u
		return nil
	}
}

func (client *Client) url(endpoint string) string {
	u := *client.endpointBase
	u.Path = path.Join(u.Path, endpoint)
	return u.String()
}

func (client *Client) do(ctx context.Context, req *http.Request) (*http.Response, error) {
	req.Header.Set("Authorization", "Bearer "+client.channelToken)
	req.Header.Set("User-Agent", "LINE-BotSDK-Go/"+version)
	if ctx != nil {
		return ctxhttp.Do(ctx, client.httpClient, req)
	}
	return client.httpClient.Do(req)

}

func (client *Client) get(ctx context.Context, endpoint string) (*http.Response, error) {
	req, err := http.NewRequest("GET", client.url(endpoint), nil)
	if err != nil {
		return nil, err
	}
	return client.do(ctx, req)
}

func (client *Client) post(ctx context.Context, endpoint string, body io.Reader) (*http.Response, error) {
	req, err := http.NewRequest("POST", client.url(endpoint), body)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json; charset=UTF-8")
	return client.do(ctx, req)
}
<commit_msg>Delete client.go<commit_after><|endoftext|>


<commit_before>// package resolver contains functions to handle resolving .mesos
// domains
package resolver

import (
	"errors"
	"github.com/mesosphere/mesos-dns/logging"
	"github.com/mesosphere/mesos-dns/records"
	"math/rand"
	"net"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
	"io"
	"encoding/json"

	"github.com/miekg/dns"
	"github.com/emicklei/go-restful"
)

var (
	recurseCnt = 3
)

// resolveOut queries other nameserver
// randomly picks from the list that is not mesos
func (res *Resolver) resolveOut(r *dns.Msg, nameserver string, proto string, cnt int) (*dns.Msg, error) {
	var in *dns.Msg
	var err error

	c := new(dns.Client)
	c.Net = proto

	var t time.Duration = 5 * 1e9
	if res.Config.Timeout != 0 {
		t = time.Duration(int64(res.Config.Timeout * 1e9))
	}

	c.DialTimeout = t
	c.ReadTimeout = t
	c.WriteTimeout = t

	in, _, err = c.Exchange(r, nameserver)
	if err != nil {
		return in, err
	}

	// recurse
	if (in != nil) && (len(in.Answer) == 0) && (!in.MsgHdr.Authoritative) && (len(in.Ns) > 0) && (err != nil) {

		if cnt == recurseCnt {
			logging.CurLog.NonMesosRecursed.Inc()
		}

		if cnt > 0 {

			if soa, ok := (in.Ns[0]).(*dns.SOA); ok {
				return res.resolveOut(r, soa.Ns+":53", proto, cnt-1)
			}
		}

	}

	return in, err
}

// cleanWild strips any wildcards out thus mapping cleanly to the
// original serviceName
func cleanWild(dom string) string {
	if strings.Contains(dom, ".*") {
		return strings.Replace(dom, ".*", "", -1)
	} else {
		return dom
	}
}

// splitDomain splits dom into host and port pair
func (res *Resolver) splitDomain(dom string) (host string, port int) {
	s := strings.Split(dom, ":")
	host = s[0]

	// As won't have ports
	if len(s) == 1 {
		return host, 0
	} else {
		port, _ = strconv.Atoi(s[1])
		return host, port
	}
}

// formatSRV returns the SRV resource record for target
func (res *Resolver) formatSRV(name string, target string) (*dns.SRV, error) {
	ttl := uint32(res.Config.TTL)

	h, p := res.splitDomain(target)

	return &dns.SRV{
		Hdr: dns.RR_Header{
			Name:   name,
			Rrtype: dns.TypeSRV,
			Class:  dns.ClassINET,
			Ttl:    ttl,
		},
		Priority: 0,
		Weight:   0,
		Port:     uint16(p),
		Target:   h + ".",
	}, nil
}

// formatA returns the A resource record for target
func (res *Resolver) formatA(dom string, target string) (*dns.A, error) {
	ttl := uint32(res.Config.TTL)

	h, _ := res.splitDomain(target)

	ip, err := net.ResolveIPAddr("ip4", h)

	if err != nil {
		return nil, err
	} else {
		a := ip.IP

		return &dns.A{
			Hdr: dns.RR_Header{
				Name:   dom,
				Rrtype: dns.TypeA,
				Class:  dns.ClassINET,
				Ttl:    ttl},
			A: a.To4(),
		}, nil
	}
}

// formatSOA returns the SOA resource record for the mesos domain
func (res *Resolver) formatSOA(dom string) (*dns.SOA, error) {
	ttl := uint32(res.Config.TTL)

	return &dns.SOA{
		Hdr: dns.RR_Header{
			Name:   dom,
			Rrtype: dns.TypeSOA,
			Class:  dns.ClassINET,
			Ttl:    ttl,
		},
		Ns:      res.Config.Mname,
		Mbox:    res.Config.Email,
		Serial:  uint32(time.Now().Unix()),
		Refresh: ttl,
		Retry:   600,
		Expire:  86400,
		Minttl:  ttl,
	}, nil
}

// shuffleAnswers reorders answers for very basic load balancing
func shuffleAnswers(answers []dns.RR) []dns.RR {
	rand.Seed(time.Now().UTC().UnixNano())

	n := len(answers)
	for i := 0; i < n; i++ {
		r := i + rand.Intn(n-i)
		answers[r], answers[i] = answers[i], answers[r]
	}

	return answers
}

// HandleNonMesos makes non-mesos queries
func (res *Resolver) HandleNonMesos(w dns.ResponseWriter, r *dns.Msg) {
	var err error
	var m *dns.Msg

	proto := "udp"
	if _, ok := w.RemoteAddr().(*net.TCPAddr); ok {
		proto = "tcp"
	}

	for i := 0; i < len(res.Config.Resolvers); i++ {
		nameserver := res.Config.Resolvers[i] + ":53"
		m, err = res.resolveOut(r, nameserver, proto, recurseCnt)
		if err == nil {
			break
		}
	}

	if err != nil {
		logging.Error.Println(r.Question[0].Name)
		logging.Error.Println(err)
	}

	// resolveOut returns nil Msg sometimes cause of perf
	if m == nil {
		m = new(dns.Msg)
		m.SetReply(r)
		m.SetRcode(r, 2)
		err = errors.New("nil msg")
	}

	// tracing info
	logging.CurLog.NonMesosRequests.Inc()

	if err != nil {
		logging.Error.Println(err)
		logging.CurLog.NonMesosFailed.Inc()
	} else {

		// nxdomain
		if len(m.Answer) == 0 {
			logging.CurLog.NonMesosNXDomain.Inc()
		} else {
			logging.CurLog.NonMesosSuccess.Inc()
		}
	}

	err = w.WriteMsg(m)
	if err != nil {
		logging.Error.Println(err)
	}
}

// HandleMesos is a resolver request handler that responds to a resource
// question with resource answer(s)
// it can handle {A, SRV, ANY}
func (res *Resolver) HandleMesos(w dns.ResponseWriter, r *dns.Msg) {
	var err error

	dom := strings.ToLower(cleanWild(r.Question[0].Name))
	qType := r.Question[0].Qtype

	m := new(dns.Msg)
	m.Authoritative = true
	m.RecursionAvailable = true
	m.SetReply(r)

	switch qType {
	case dns.TypeSRV:
		for i := 0; i < len(res.rs.SRVs[dom]); i++ {
			rr, err := res.formatSRV(r.Question[0].Name, res.rs.SRVs[dom][i])
			if err != nil {
				logging.Error.Println(err)
			} else {
				m.Answer = append(m.Answer, rr)
			}
		}
	case dns.TypeA:
		for i := 0; i < len(res.rs.As[dom]); i++ {
			rr, err := res.formatA(dom, res.rs.As[dom][i])
			if err != nil {
				logging.Error.Println(err)
			} else {
				m.Answer = append(m.Answer, rr)
			}

		}
	case dns.TypeANY:
		// refactor me
		for i := 0; i < len(res.rs.As[dom]); i++ {
			rr, err := res.formatA(r.Question[0].Name, res.rs.As[dom][i])
			if err != nil {
				logging.Error.Println(err)
			} else {
				m.Answer = append(m.Answer, rr)
			}
		}

		for i := 0; i < len(res.rs.SRVs[dom]); i++ {
			rr, err := res.formatSRV(dom, res.rs.SRVs[dom][i])
			if err != nil {
				logging.Error.Println(err)
			} else {
				m.Answer = append(m.Answer, rr)
			}
		}

	case dns.TypeSOA:

		m = new(dns.Msg)
		m.SetReply(r)

		rr, err := res.formatSOA(r.Question[0].Name)
		if err != nil {
			logging.Error.Println(err)
		} else {
			m.Ns = append(m.Ns, rr)
		}

	}

	// shuffle answers
	m.Answer = shuffleAnswers(m.Answer)

	// tracing info
	logging.CurLog.MesosRequests.Inc()

	if err != nil {
		logging.CurLog.MesosFailed.Inc()
	} else if (qType == dns.TypeAAAA) && (len(res.rs.SRVs[dom]) > 0 || len(res.rs.As[dom]) > 0) {

		m = new(dns.Msg)
		m.Authoritative = true
		m.SetReply(r)
		// set NOERROR
		m.SetRcode(r, 0)
		// leave answer empty (NOERROR --> NODATA)

	} else {
		// no answers but not a {SOA,SRV} request
		if len(m.Answer) == 0 && (qType != dns.TypeSOA) && (qType != dns.TypeSRV) {

			m = new(dns.Msg)
			m.SetReply(r)

			// set NXDOMAIN
			m.SetRcode(r, 3)

			rr, err := res.formatSOA(r.Question[0].Name)
			if err != nil {
				logging.Error.Println(err)
			} else {
				m.Ns = append(m.Ns, rr)
			}

			logging.CurLog.MesosNXDomain.Inc()
			logging.VeryVerbose.Println("total A rrs:\t" + strconv.Itoa(len(res.rs.As)))
			logging.VeryVerbose.Println("failed looking for " + r.Question[0].String())
		} else {
			logging.CurLog.MesosSuccess.Inc()
		}
	}

	err = w.WriteMsg(m)
	if err != nil {
		logging.Error.Println(err)
	}
}

// Serve starts a dns server for net protocol
func (res *Resolver) Serve(net string) {
	defer func() {
		if rec := recover(); rec != nil {
			logging.Error.Printf("%s\n", rec)
			os.Exit(1)
		}
	}()

	server := &dns.Server{
		Addr:       res.Config.Listener + ":" + strconv.Itoa(res.Config.Port),
		Net:        net,
		TsigSecret: nil,
	}

	err := server.ListenAndServe()
	if err != nil {
		logging.Error.Printf("Failed to setup "+net+" server: %s\n", err.Error())
	} else {
		logging.Error.Printf("Not listening/serving any more requests.")
	}

	os.Exit(1)
}

// Hdns starts an http server for mesos-dns queries
func (res *Resolver) Hdns() {
	defer func() {
		if rec := recover(); rec != nil {
			logging.Error.Printf("%s\n", rec)
			os.Exit(1)
		}
	}()

    // webserver + available routes
	ws := new(restful.WebService)
	ws.Route(ws.GET("/config").To(res.HdnsConfig))
	ws.Route(ws.GET("/version").To(res.HdnsVersion))
	restful.Add(ws)

	portString := ":" + strconv.Itoa(res.Config.HttpPort)
	if err := http.ListenAndServe(portString, nil); err != nil {
		logging.Error.Printf("Failed to setup http server: %s\n", err.Error())
	} else {
		logging.Error.Printf("Not serving http requests any more .")
	}

	os.Exit(1)
}

// Reports configuration through http interface
func (res *Resolver) HdnsConfig(req *restful.Request, resp *restful.Response) {
	output, err := json.Marshal(res.Config)
	if err != nil {
			logging.Error.Println(err)
	}
	io.WriteString(resp, string(output))
}

// Reports configuration through http interface
func (res *Resolver) HdnsVersion(req *restful.Request, resp *restful.Response) {
	mapV := map[string]string{"Version": res.Version, "url": "https://github.com/mesosphere/mesos-dns"}
	output, err := json.Marshal(mapV)
	if err != nil {
			logging.Error.Println(err)
	}
	io.WriteString(resp, string(output))
}

// Resolver holds configuration information and the resource records
// refactor me
type Resolver struct {
	rs     records.RecordGenerator
	Config records.Config
	Version string
}

// Reload triggers a new refresh from mesos master
func (res *Resolver) Reload() {
	t := records.RecordGenerator{}
	err := t.ParseState(&res.Config)

	if err == nil {
		res.rs = t
	} else {
		logging.VeryVerbose.Println("Warning: master not found; keeping old DNS state")
	}
}
<commit_msg>Interface.<commit_after>// package resolver contains functions to handle resolving .mesos
// domains
package resolver

import (
	"errors"
	"github.com/mesosphere/mesos-dns/logging"
	"github.com/mesosphere/mesos-dns/records"
	"math/rand"
	"net"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
	"io"
	"encoding/json"

	"github.com/miekg/dns"
	"github.com/emicklei/go-restful"
)

var (
	recurseCnt = 3
)

// resolveOut queries other nameserver
// randomly picks from the list that is not mesos
func (res *Resolver) resolveOut(r *dns.Msg, nameserver string, proto string, cnt int) (*dns.Msg, error) {
	var in *dns.Msg
	var err error

	c := new(dns.Client)
	c.Net = proto

	var t time.Duration = 5 * 1e9
	if res.Config.Timeout != 0 {
		t = time.Duration(int64(res.Config.Timeout * 1e9))
	}

	c.DialTimeout = t
	c.ReadTimeout = t
	c.WriteTimeout = t

	in, _, err = c.Exchange(r, nameserver)
	if err != nil {
		return in, err
	}

	// recurse
	if (in != nil) && (len(in.Answer) == 0) && (!in.MsgHdr.Authoritative) && (len(in.Ns) > 0) && (err != nil) {

		if cnt == recurseCnt {
			logging.CurLog.NonMesosRecursed.Inc()
		}

		if cnt > 0 {

			if soa, ok := (in.Ns[0]).(*dns.SOA); ok {
				return res.resolveOut(r, soa.Ns+":53", proto, cnt-1)
			}
		}

	}

	return in, err
}

// cleanWild strips any wildcards out thus mapping cleanly to the
// original serviceName
func cleanWild(dom string) string {
	if strings.Contains(dom, ".*") {
		return strings.Replace(dom, ".*", "", -1)
	} else {
		return dom
	}
}

// splitDomain splits dom into host and port pair
func (res *Resolver) splitDomain(dom string) (host string, port int) {
	s := strings.Split(dom, ":")
	host = s[0]

	// As won't have ports
	if len(s) == 1 {
		return host, 0
	} else {
		port, _ = strconv.Atoi(s[1])
		return host, port
	}
}

// formatSRV returns the SRV resource record for target
func (res *Resolver) formatSRV(name string, target string) (*dns.SRV, error) {
	ttl := uint32(res.Config.TTL)

	h, p := res.splitDomain(target)

	return &dns.SRV{
		Hdr: dns.RR_Header{
			Name:   name,
			Rrtype: dns.TypeSRV,
			Class:  dns.ClassINET,
			Ttl:    ttl,
		},
		Priority: 0,
		Weight:   0,
		Port:     uint16(p),
		Target:   h + ".",
	}, nil
}

// formatA returns the A resource record for target
func (res *Resolver) formatA(dom string, target string) (*dns.A, error) {
	ttl := uint32(res.Config.TTL)

	h, _ := res.splitDomain(target)

	ip, err := net.ResolveIPAddr("ip4", h)

	if err != nil {
		return nil, err
	} else {
		a := ip.IP

		return &dns.A{
			Hdr: dns.RR_Header{
				Name:   dom,
				Rrtype: dns.TypeA,
				Class:  dns.ClassINET,
				Ttl:    ttl},
			A: a.To4(),
		}, nil
	}
}

// formatSOA returns the SOA resource record for the mesos domain
func (res *Resolver) formatSOA(dom string) (*dns.SOA, error) {
	ttl := uint32(res.Config.TTL)

	return &dns.SOA{
		Hdr: dns.RR_Header{
			Name:   dom,
			Rrtype: dns.TypeSOA,
			Class:  dns.ClassINET,
			Ttl:    ttl,
		},
		Ns:      res.Config.Mname,
		Mbox:    res.Config.Email,
		Serial:  uint32(time.Now().Unix()),
		Refresh: ttl,
		Retry:   600,
		Expire:  86400,
		Minttl:  ttl,
	}, nil
}

// shuffleAnswers reorders answers for very basic load balancing
func shuffleAnswers(answers []dns.RR) []dns.RR {
	rand.Seed(time.Now().UTC().UnixNano())

	n := len(answers)
	for i := 0; i < n; i++ {
		r := i + rand.Intn(n-i)
		answers[r], answers[i] = answers[i], answers[r]
	}

	return answers
}

// HandleNonMesos makes non-mesos queries
func (res *Resolver) HandleNonMesos(w dns.ResponseWriter, r *dns.Msg) {
	var err error
	var m *dns.Msg

	proto := "udp"
	if _, ok := w.RemoteAddr().(*net.TCPAddr); ok {
		proto = "tcp"
	}

	for i := 0; i < len(res.Config.Resolvers); i++ {
		nameserver := res.Config.Resolvers[i] + ":53"
		m, err = res.resolveOut(r, nameserver, proto, recurseCnt)
		if err == nil {
			break
		}
	}

	if err != nil {
		logging.Error.Println(r.Question[0].Name)
		logging.Error.Println(err)
	}

	// resolveOut returns nil Msg sometimes cause of perf
	if m == nil {
		m = new(dns.Msg)
		m.SetReply(r)
		m.SetRcode(r, 2)
		err = errors.New("nil msg")
	}

	// tracing info
	logging.CurLog.NonMesosRequests.Inc()

	if err != nil {
		logging.Error.Println(err)
		logging.CurLog.NonMesosFailed.Inc()
	} else {

		// nxdomain
		if len(m.Answer) == 0 {
			logging.CurLog.NonMesosNXDomain.Inc()
		} else {
			logging.CurLog.NonMesosSuccess.Inc()
		}
	}

	err = w.WriteMsg(m)
	if err != nil {
		logging.Error.Println(err)
	}
}

// HandleMesos is a resolver request handler that responds to a resource
// question with resource answer(s)
// it can handle {A, SRV, ANY}
func (res *Resolver) HandleMesos(w dns.ResponseWriter, r *dns.Msg) {
	var err error

	dom := strings.ToLower(cleanWild(r.Question[0].Name))
	qType := r.Question[0].Qtype

	m := new(dns.Msg)
	m.Authoritative = true
	m.RecursionAvailable = true
	m.SetReply(r)

	switch qType {
	case dns.TypeSRV:
		for i := 0; i < len(res.rs.SRVs[dom]); i++ {
			rr, err := res.formatSRV(r.Question[0].Name, res.rs.SRVs[dom][i])
			if err != nil {
				logging.Error.Println(err)
			} else {
				m.Answer = append(m.Answer, rr)
			}
		}
	case dns.TypeA:
		for i := 0; i < len(res.rs.As[dom]); i++ {
			rr, err := res.formatA(dom, res.rs.As[dom][i])
			if err != nil {
				logging.Error.Println(err)
			} else {
				m.Answer = append(m.Answer, rr)
			}

		}
	case dns.TypeANY:
		// refactor me
		for i := 0; i < len(res.rs.As[dom]); i++ {
			rr, err := res.formatA(r.Question[0].Name, res.rs.As[dom][i])
			if err != nil {
				logging.Error.Println(err)
			} else {
				m.Answer = append(m.Answer, rr)
			}
		}

		for i := 0; i < len(res.rs.SRVs[dom]); i++ {
			rr, err := res.formatSRV(dom, res.rs.SRVs[dom][i])
			if err != nil {
				logging.Error.Println(err)
			} else {
				m.Answer = append(m.Answer, rr)
			}
		}

	case dns.TypeSOA:

		m = new(dns.Msg)
		m.SetReply(r)

		rr, err := res.formatSOA(r.Question[0].Name)
		if err != nil {
			logging.Error.Println(err)
		} else {
			m.Ns = append(m.Ns, rr)
		}

	}

	// shuffle answers
	m.Answer = shuffleAnswers(m.Answer)

	// tracing info
	logging.CurLog.MesosRequests.Inc()

	if err != nil {
		logging.CurLog.MesosFailed.Inc()
	} else if (qType == dns.TypeAAAA) && (len(res.rs.SRVs[dom]) > 0 || len(res.rs.As[dom]) > 0) {

		m = new(dns.Msg)
		m.Authoritative = true
		m.SetReply(r)
		// set NOERROR
		m.SetRcode(r, 0)
		// leave answer empty (NOERROR --> NODATA)

	} else {
		// no answers but not a {SOA,SRV} request
		if len(m.Answer) == 0 && (qType != dns.TypeSOA) && (qType != dns.TypeSRV) {

			m = new(dns.Msg)
			m.SetReply(r)

			// set NXDOMAIN
			m.SetRcode(r, 3)

			rr, err := res.formatSOA(r.Question[0].Name)
			if err != nil {
				logging.Error.Println(err)
			} else {
				m.Ns = append(m.Ns, rr)
			}

			logging.CurLog.MesosNXDomain.Inc()
			logging.VeryVerbose.Println("total A rrs:\t" + strconv.Itoa(len(res.rs.As)))
			logging.VeryVerbose.Println("failed looking for " + r.Question[0].String())
		} else {
			logging.CurLog.MesosSuccess.Inc()
		}
	}

	err = w.WriteMsg(m)
	if err != nil {
		logging.Error.Println(err)
	}
}

// Serve starts a dns server for net protocol
func (res *Resolver) Serve(net string) {
	defer func() {
		if rec := recover(); rec != nil {
			logging.Error.Printf("%s\n", rec)
			os.Exit(1)
		}
	}()

	server := &dns.Server{
		Addr:       res.Config.Listener + ":" + strconv.Itoa(res.Config.Port),
		Net:        net,
		TsigSecret: nil,
	}

	err := server.ListenAndServe()
	if err != nil {
		logging.Error.Printf("Failed to setup "+net+" server: %s\n", err.Error())
	} else {
		logging.Error.Printf("Not listening/serving any more requests.")
	}

	os.Exit(1)
}

// Hdns starts an http server for mesos-dns queries
func (res *Resolver) Hdns() {
	defer func() {
		if rec := recover(); rec != nil {
			logging.Error.Printf("%s\n", rec)
			os.Exit(1)
		}
	}()

    // webserver + available routes
	ws := new(restful.WebService)
	ws.Route(ws.GET("/v1/version").To(res.HdnsVersion))
	ws.Route(ws.GET("/v1/config").To(res.HdnsConfig))
	ws.Route(ws.GET("/v1/hosts/{host}").To(res.HdnsHosts))
	ws.Route(ws.GET("/v1/hosts/{host}/ports").To(res.HdnsPorts))
	ws.Route(ws.GET("/v1/services/{service}").To(res.HdnsServices))
	restful.Add(ws)

	portString := ":" + strconv.Itoa(res.Config.HttpPort)
	if err := http.ListenAndServe(portString, nil); err != nil {
		logging.Error.Printf("Failed to setup http server: %s\n", err.Error())
	} else {
		logging.Error.Printf("Not serving http requests any more .")
	}

	os.Exit(1)
}

// Reports configuration through http interface
func (res *Resolver) HdnsConfig(req *restful.Request, resp *restful.Response) {
	output, err := json.Marshal(res.Config)
	if err != nil {
			logging.Error.Println(err)
	}
	io.WriteString(resp, string(output))
}

// Reports Mesos-DNS version through http interface
func (res *Resolver) HdnsVersion(req *restful.Request, resp *restful.Response) {
	mapV := map[string]string{"Service": "Mesos-DNS",
	                          "Version": res.Version,
	                          "URL": "https://github.com/mesosphere/mesos-dns"}
	output, err := json.Marshal(mapV)
	if err != nil {
			logging.Error.Println(err)
	}
	io.WriteString(resp, string(output))
}

// Reports Mesos-DNS version through http interface
func (res *Resolver) HdnsHosts(req *restful.Request, resp *restful.Response) {
		io.WriteString(resp, "To be implemented...")
}

// Reports Mesos-DNS version through http interface
func (res *Resolver) HdnsPorts(req *restful.Request, resp *restful.Response) {
		io.WriteString(resp, "To be implemented...")
}

// Reports Mesos-DNS version through http interface
func (res *Resolver) HdnsServices(req *restful.Request, resp *restful.Response) {
	service := req.PathParameter("service")
	io.WriteString(resp, "Will soon look for " + service)

}

// Resolver holds configuration information and the resource records
// refactor me
type Resolver struct {
	rs     records.RecordGenerator
	Config records.Config
	Version string
}

// Reload triggers a new refresh from mesos master
func (res *Resolver) Reload() {
	t := records.RecordGenerator{}
	err := t.ParseState(&res.Config)

	if err == nil {
		res.rs = t
	} else {
		logging.VeryVerbose.Println("Warning: master not found; keeping old DNS state")
	}
}
<|endoftext|>


<commit_before>package main

import (
	alks "github.com/Cox-Automotive/alks-go"
	"github.com/hashicorp/terraform/helper/schema"
	"log"
)

func resourceAlksLtk() *schema.Resource {
	return &schema.Resource{
		Create: resourceAlksLtkCreate,
		Read:   resourceAlksLtkRead,
		Delete: resourceAlksLtkDelete,

		SchemaVersion: 1,

		Schema: map[string]*schema.Schema{
			"iam_username": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"account_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"role_name": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"account": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"role": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"action": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"added_iam_user_to_group": &schema.Schema{
				Type:     schema.TypeBool,
				Computed: true,
			},
			"partial_error": &schema.Schema{
				Type:     schema.TypeBool,
				Computed: true,
			},
			"iam_user_arn": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"access_key": &schema.Schema{
				Sensitive: true,
				Type:     schema.TypeString,
				Computed: true,
			},
			"secret_key": &schema.Schema{
				Sensitive: true,
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func resourceAlksLtkCreate(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[INFO] ALKS LTK User Create")

	var iamUsername = d.Get("iam_username").(string)

	client := meta.(*alks.Client)
	resp, err := client.CreateLongTermKey(iamUsername)

	if err != nil {
		return err
	}

	d.SetId(iamUsername)
	_ = d.Set("account_id", resp.AccountDetails.Account)
	_ = d.Set("role_name", resp.AccountDetails.Role)
	_ = d.Set("role", resp.Role)
	_ = d.Set("action", resp.Action)
	_ = d.Set("added_iam_user_to_group", resp.AddedIAMUserToGroup)
	_ = d.Set("partial_error", resp.PartialError)
	_ = d.Set("iam_user_arn", resp.IAMUserArn)
	_ = d.Set("access_key", resp.AccessKey)
	_ = d.Set("secret_key", resp.SecretKey)

	log.Printf("[INFO] alks_ltk.id: %v", d.Id())

	return nil
}

func resourceAlksLtkRead(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[INFO] ALKS LTK Users Read")

	client := meta.(*alks.Client)
	resp, err := client.GetLongTermKey(d.Id())

	if err != nil {
		return err
	}

	log.Printf("[INFO] alks_ltk.id: %v", d.Id())

	return populateResourceDataFromLTK(resp, d)
}

func resourceAlksLtkDelete(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[INFO] ALKS LTK User Delete")

	client := meta.(*alks.Client)
	_, err := client.DeleteLongTermKey(d.Id())

	if err != nil {
		return err
	}

	return nil
}

func populateResourceDataFromLTK(longTermKey *alks.GetLongTermKeyResponse, d *schema.ResourceData) error {
	d.SetId(longTermKey.UserName)
	_ = d.Set("access_key", longTermKey.AccessKeyID)
	_ = d.Set("create_date", longTermKey.CreateDate)

	return nil
}
<commit_msg>Rather than returning nil for a LTK user not found, we return the resource does not exist. Also, removed some fields from state which are not really needed.<commit_after>package main

import (
	alks "github.com/Cox-Automotive/alks-go"
	"github.com/hashicorp/terraform/helper/schema"
	"log"
)

func resourceAlksLtk() *schema.Resource {
	return &schema.Resource{
		Create: resourceAlksLtkCreate,
		Read:   resourceAlksLtkRead,
		Delete: resourceAlksLtkDelete,

		SchemaVersion: 1,

		Schema: map[string]*schema.Schema{
			"iam_username": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"account_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"role_name": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"account": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"role": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"action": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"added_iam_user_to_group": &schema.Schema{
				Type:     schema.TypeBool,
				Computed: true,
			},
			"partial_error": &schema.Schema{
				Type:     schema.TypeBool,
				Computed: true,
			},
			"iam_user_arn": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"access_key": &schema.Schema{
				Sensitive: true,
				Type:     schema.TypeString,
				Computed: true,
			},
			"secret_key": &schema.Schema{
				Sensitive: true,
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func resourceAlksLtkCreate(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[INFO] ALKS LTK User Create")

	var iamUsername = d.Get("iam_username").(string)

	client := meta.(*alks.Client)
	resp, err := client.CreateLongTermKey(iamUsername)

	if err != nil {
		return err
	}

	d.SetId(iamUsername)
	_ = d.Set("iam_user_arn", resp.IAMUserArn)
	_ = d.Set("access_key", resp.AccessKey)
	_ = d.Set("secret_key", resp.SecretKey)

	log.Printf("[INFO] alks_ltk.id: %v", d.Id())

	return nil
}

func resourceAlksLtkRead(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[INFO] ALKS LTK Users Read")

	client := meta.(*alks.Client)
	resp, err := client.GetLongTermKey(d.Id())

	if err != nil {
		d.SetId("")
		return nil
	}

	log.Printf("[INFO] alks_ltk.id: %v", d.Id())

	return populateResourceDataFromLTK(resp, d)
}

func resourceAlksLtkDelete(d *schema.ResourceData, meta interface{}) error {
	log.Printf("[INFO] ALKS LTK User Delete")

	client := meta.(*alks.Client)
	_, err := client.DeleteLongTermKey(d.Id())

	if err != nil {
		return err
	}

	return nil
}

func populateResourceDataFromLTK(longTermKey *alks.GetLongTermKeyResponse, d *schema.ResourceData) error {
	d.SetId(longTermKey.UserName)
	_ = d.Set("access_key", longTermKey.AccessKeyID)
	_ = d.Set("create_date", longTermKey.CreateDate)

	return nil
}
<|endoftext|>


<commit_before>package ess

import "github.com/denverdino/aliyungo/common"

type LifecycleState string

const (
	Active    = LifecycleState("Active")
	Inacitve  = LifecycleState("Inacitve")
	Deleting  = LifecycleState("Deleting")
	InService = LifecycleState("InService")
	Pending   = LifecycleState("Pending")
	Removing  = LifecycleState("Removing")
)

type CreateScalingGroupArgs struct {
	RegionId         common.Region
	ScalingGroupName string
	LoadBalancerId   string
	VpcId            string
	VSwitchId        string
	MaxSize          int
	MinSize          int
	DefaultCooldown  int
	RemovalPolicy    common.FlattenArray
	DBInstanceId     common.FlattenArray
}

type CreateScalingGroupResponse struct {
	common.Response
	ScalingGroupId string
}

// CreateScalingGroup create scaling group
//
// You can read doc at https://help.aliyun.com/document_detail/25936.html?spm=5176.doc25940.6.617.vm6LXF
func (client *Client) CreateScalingGroup(args *CreateScalingGroupArgs) (resp *CreateScalingGroupResponse, err error) {
	response := CreateScalingGroupResponse{}
	err = client.InvokeByFlattenMethod("CreateScalingGroup", args, &response)

	if err != nil {
		return nil, err
	}
	return &response, nil
}

type ModifyScalingGroupArgs struct {
	ScalingGroupId               string
	ScalingGroupName             string
	ActiveScalingConfigurationId string
	MinSize                      int
	MaxSize                      int
	DefaultCooldown              int
	RemovalPolicy                common.FlattenArray
}

type ModifyScalingGroupResponse struct {
	common.Response
}

// ModifyScalingGroup modify scaling group
//
// You can read doc at https://help.aliyun.com/document_detail/25937.html?spm=5176.doc25936.6.618.iwDcXT
func (client *Client) ModifyScalingGroup(args *ModifyScalingGroupArgs) (resp *ModifyScalingGroupResponse, err error) {
	response := ModifyScalingGroupResponse{}
	err = client.InvokeByFlattenMethod("ModifyScalingGroup", args, &response)

	if err != nil {
		return nil, err
	}
	return &response, nil
}

type DescribeScalingGroupsArgs struct {
	RegionId         common.Region
	ScalingGroupId   common.FlattenArray
	ScalingGroupName common.FlattenArray
	common.Pagination
}

type DescribeInstancesResponse struct {
	common.Response
	common.PaginationResult
	ScalingGroups struct {
		ScalingGroup []ScalingGroupItemType
	}
}

type ScalingGroupItemType struct {
	ScalingGroupId               string
	ScalingGroupName             string
	ActiveScalingConfigurationId string
	RegionId                     string
	LoadBalancerId               string
	VSwitchId                    string
	CreationTime                 string
	LifecycleState               LifecycleState
	MinSize                      int
	MaxSize                      int
	DefaultCooldown              int
	TotalCapacity                int
	ActiveCapacity               int
	PendingCapacity              int
	RemovingCapacity             int
	RemovalPolicies              RemovalPolicySetType
	DBInstanceIds                DBInstanceIdSetType
}

type RemovalPolicySetType struct {
	RemovalPolicy []string
}

type DBInstanceIdSetType struct {
	DBInstanceId []string
}

// DescribeScalingGroups describes scaling groups
//
// You can read doc at https://help.aliyun.com/document_detail/25938.html?spm=5176.doc25937.6.619.sUUOT7
func (client *Client) DescribeScalingGroups(args *DescribeScalingGroupsArgs) (groups []ScalingGroupItemType, pagination *common.PaginationResult, err error) {
	args.Validate()
	response := DescribeInstancesResponse{}

	err = client.InvokeByFlattenMethod("DescribeScalingGroups", args, &response)

	if err == nil {
		return response.ScalingGroups.ScalingGroup, &response.PaginationResult, nil
	}

	return nil, nil, err
}

type DescribeScalingInstancesArgs struct {
	RegionId               common.Region
	ScalingGroupId         string
	ScalingConfigurationId string
	HealthStatus           string
	CreationType           string
	LifecycleState         LifecycleState
	InstanceId             common.FlattenArray
	common.Pagination
}

type DescribeScalingInstancesResponse struct {
	common.Response
	common.PaginationResult
	ScalingInstances struct {
		ScalingInstance []ScalingInstanceItemType
	}
}

type ScalingInstanceItemType struct {
	InstanceId             string
	ScalingGroupId         string
	ScalingConfigurationId string
	HealthStatus           string
	CreationTime           string
	CreationType           string
	LifecycleState         LifecycleState
}

// DescribeScalingInstances describes scaling instances
//
// You can read doc at https://help.aliyun.com/document_detail/25942.html?spm=5176.doc25941.6.623.2xA0Uj
func (client *Client) DescribeScalingInstances(args *DescribeScalingInstancesArgs) (instances []ScalingInstanceItemType, pagination *common.PaginationResult, err error) {
	args.Validate()
	response := DescribeScalingInstancesResponse{}

	err = client.InvokeByFlattenMethod("DescribeScalingInstances", args, &response)

	if err == nil {
		return response.ScalingInstances.ScalingInstance, &response.PaginationResult, nil
	}

	return nil, nil, err
}

type EnableScalingGroupArgs struct {
	ScalingGroupId               string
	ActiveScalingConfigurationId string
	InstanceId                   common.FlattenArray
}

type EnableScalingGroupResponse struct {
	common.Response
}

// EnableScalingGroup enable scaling group
//
// You can read doc at https://help.aliyun.com/document_detail/25939.html?spm=5176.doc25938.6.620.JiJhkx
func (client *Client) EnableScalingGroup(args *EnableScalingGroupArgs) (resp *EnableScalingGroupResponse, err error) {
	response := EnableScalingGroupResponse{}
	err = client.InvokeByFlattenMethod("EnableScalingGroup", args, &response)

	if err != nil {
		return nil, err
	}
	return &response, nil
}

type DisableScalingGroupArgs struct {
	ScalingGroupId string
}

type DisableScalingGroupResponse struct {
	common.Response
}

// DisableScalingGroup disable scaling group
//
// You can read doc at https://help.aliyun.com/document_detail/25940.html?spm=5176.doc25939.6.621.M8GuuY
func (client *Client) DisableScalingGroup(args *DisableScalingGroupArgs) (resp *DisableScalingGroupResponse, err error) {
	response := DisableScalingGroupResponse{}
	err = client.InvokeByFlattenMethod("DisableScalingGroup", args, &response)

	if err != nil {
		return nil, err
	}
	return &response, nil
}

type DeleteScalingGroupArgs struct {
	ScalingGroupId string
	ForceDelete    bool
}

type DeleteScalingGroupResponse struct {
	common.Response
}

// DeleteScalingGroup delete scaling group
//
// You can read doc at https://help.aliyun.com/document_detail/25941.html?spm=5176.doc25940.6.622.mRBCuw
func (client *Client) DeleteScalingGroup(args *DeleteScalingGroupArgs) (resp *DeleteScalingGroupResponse, err error) {
	response := DeleteScalingGroupResponse{}
	err = client.InvokeByFlattenMethod("DeleteScalingGroup", args, &response)

	if err != nil {
		return nil, err
	}
	return &response, nil
}

type AttachInstancesArgs struct {
	ScalingGroupId string
	InstanceId     common.FlattenArray
}

type AttachInstancesResponse struct {
	common.Response
	ScalingActivityId string
}

// AttachInstances attach instances to scaling group
//
// You can read doc at https://help.aliyun.com/document_detail/25954.html?spm=5176.product25855.6.633.y5gmzX
func (client *Client) AttachInstances(args *AttachInstancesArgs) (resp *AttachInstancesResponse, err error) {
	response := AttachInstancesResponse{}
	err = client.InvokeByFlattenMethod("AttachInstances", args, &response)

	if err != nil {
		return nil, err
	}
	return &response, nil
}

// RemoveInstances detach instances from scaling group
//
// You can read doc at https://help.aliyun.com/document_detail/25955.html?spm=5176.doc25954.6.634.GtpzuJ
func (client *Client) RemoveInstances(args *AttachInstancesArgs) (resp *AttachInstancesResponse, err error) {
	response := AttachInstancesResponse{}
	err = client.InvokeByFlattenMethod("RemoveInstances", args, &response)

	if err != nil {
		return nil, err
	}
	return &response, nil
}<commit_msg>use coressponding variable in RemoveInstances API<commit_after>package ess

import "github.com/denverdino/aliyungo/common"

type LifecycleState string

const (
	Active    = LifecycleState("Active")
	Inacitve  = LifecycleState("Inacitve")
	Deleting  = LifecycleState("Deleting")
	InService = LifecycleState("InService")
	Pending   = LifecycleState("Pending")
	Removing  = LifecycleState("Removing")
)

type CreateScalingGroupArgs struct {
	RegionId         common.Region
	ScalingGroupName string
	LoadBalancerId   string
	VpcId            string
	VSwitchId        string
	MaxSize          int
	MinSize          int
	DefaultCooldown  int
	RemovalPolicy    common.FlattenArray
	DBInstanceId     common.FlattenArray
}

type CreateScalingGroupResponse struct {
	common.Response
	ScalingGroupId string
}

// CreateScalingGroup create scaling group
//
// You can read doc at https://help.aliyun.com/document_detail/25936.html?spm=5176.doc25940.6.617.vm6LXF
func (client *Client) CreateScalingGroup(args *CreateScalingGroupArgs) (resp *CreateScalingGroupResponse, err error) {
	response := CreateScalingGroupResponse{}
	err = client.InvokeByFlattenMethod("CreateScalingGroup", args, &response)

	if err != nil {
		return nil, err
	}
	return &response, nil
}

type ModifyScalingGroupArgs struct {
	ScalingGroupId               string
	ScalingGroupName             string
	ActiveScalingConfigurationId string
	MinSize                      int
	MaxSize                      int
	DefaultCooldown              int
	RemovalPolicy                common.FlattenArray
}

type ModifyScalingGroupResponse struct {
	common.Response
}

// ModifyScalingGroup modify scaling group
//
// You can read doc at https://help.aliyun.com/document_detail/25937.html?spm=5176.doc25936.6.618.iwDcXT
func (client *Client) ModifyScalingGroup(args *ModifyScalingGroupArgs) (resp *ModifyScalingGroupResponse, err error) {
	response := ModifyScalingGroupResponse{}
	err = client.InvokeByFlattenMethod("ModifyScalingGroup", args, &response)

	if err != nil {
		return nil, err
	}
	return &response, nil
}

type DescribeScalingGroupsArgs struct {
	RegionId         common.Region
	ScalingGroupId   common.FlattenArray
	ScalingGroupName common.FlattenArray
	common.Pagination
}

type DescribeInstancesResponse struct {
	common.Response
	common.PaginationResult
	ScalingGroups struct {
		ScalingGroup []ScalingGroupItemType
	}
}

type ScalingGroupItemType struct {
	ScalingGroupId               string
	ScalingGroupName             string
	ActiveScalingConfigurationId string
	RegionId                     string
	LoadBalancerId               string
	VSwitchId                    string
	CreationTime                 string
	LifecycleState               LifecycleState
	MinSize                      int
	MaxSize                      int
	DefaultCooldown              int
	TotalCapacity                int
	ActiveCapacity               int
	PendingCapacity              int
	RemovingCapacity             int
	RemovalPolicies              RemovalPolicySetType
	DBInstanceIds                DBInstanceIdSetType
}

type RemovalPolicySetType struct {
	RemovalPolicy []string
}

type DBInstanceIdSetType struct {
	DBInstanceId []string
}

// DescribeScalingGroups describes scaling groups
//
// You can read doc at https://help.aliyun.com/document_detail/25938.html?spm=5176.doc25937.6.619.sUUOT7
func (client *Client) DescribeScalingGroups(args *DescribeScalingGroupsArgs) (groups []ScalingGroupItemType, pagination *common.PaginationResult, err error) {
	args.Validate()
	response := DescribeInstancesResponse{}

	err = client.InvokeByFlattenMethod("DescribeScalingGroups", args, &response)

	if err == nil {
		return response.ScalingGroups.ScalingGroup, &response.PaginationResult, nil
	}

	return nil, nil, err
}

type DescribeScalingInstancesArgs struct {
	RegionId               common.Region
	ScalingGroupId         string
	ScalingConfigurationId string
	HealthStatus           string
	CreationType           string
	LifecycleState         LifecycleState
	InstanceId             common.FlattenArray
	common.Pagination
}

type DescribeScalingInstancesResponse struct {
	common.Response
	common.PaginationResult
	ScalingInstances struct {
		ScalingInstance []ScalingInstanceItemType
	}
}

type ScalingInstanceItemType struct {
	InstanceId             string
	ScalingGroupId         string
	ScalingConfigurationId string
	HealthStatus           string
	CreationTime           string
	CreationType           string
	LifecycleState         LifecycleState
}

// DescribeScalingInstances describes scaling instances
//
// You can read doc at https://help.aliyun.com/document_detail/25942.html?spm=5176.doc25941.6.623.2xA0Uj
func (client *Client) DescribeScalingInstances(args *DescribeScalingInstancesArgs) (instances []ScalingInstanceItemType, pagination *common.PaginationResult, err error) {
	args.Validate()
	response := DescribeScalingInstancesResponse{}

	err = client.InvokeByFlattenMethod("DescribeScalingInstances", args, &response)

	if err == nil {
		return response.ScalingInstances.ScalingInstance, &response.PaginationResult, nil
	}

	return nil, nil, err
}

type EnableScalingGroupArgs struct {
	ScalingGroupId               string
	ActiveScalingConfigurationId string
	InstanceId                   common.FlattenArray
}

type EnableScalingGroupResponse struct {
	common.Response
}

// EnableScalingGroup enable scaling group
//
// You can read doc at https://help.aliyun.com/document_detail/25939.html?spm=5176.doc25938.6.620.JiJhkx
func (client *Client) EnableScalingGroup(args *EnableScalingGroupArgs) (resp *EnableScalingGroupResponse, err error) {
	response := EnableScalingGroupResponse{}
	err = client.InvokeByFlattenMethod("EnableScalingGroup", args, &response)

	if err != nil {
		return nil, err
	}
	return &response, nil
}

type DisableScalingGroupArgs struct {
	ScalingGroupId string
}

type DisableScalingGroupResponse struct {
	common.Response
}

// DisableScalingGroup disable scaling group
//
// You can read doc at https://help.aliyun.com/document_detail/25940.html?spm=5176.doc25939.6.621.M8GuuY
func (client *Client) DisableScalingGroup(args *DisableScalingGroupArgs) (resp *DisableScalingGroupResponse, err error) {
	response := DisableScalingGroupResponse{}
	err = client.InvokeByFlattenMethod("DisableScalingGroup", args, &response)

	if err != nil {
		return nil, err
	}
	return &response, nil
}

type DeleteScalingGroupArgs struct {
	ScalingGroupId string
	ForceDelete    bool
}

type DeleteScalingGroupResponse struct {
	common.Response
}

// DeleteScalingGroup delete scaling group
//
// You can read doc at https://help.aliyun.com/document_detail/25941.html?spm=5176.doc25940.6.622.mRBCuw
func (client *Client) DeleteScalingGroup(args *DeleteScalingGroupArgs) (resp *DeleteScalingGroupResponse, err error) {
	response := DeleteScalingGroupResponse{}
	err = client.InvokeByFlattenMethod("DeleteScalingGroup", args, &response)

	if err != nil {
		return nil, err
	}
	return &response, nil
}

type AttachInstancesArgs struct {
	ScalingGroupId string
	InstanceId     common.FlattenArray
}

type AttachInstancesResponse struct {
	common.Response
	ScalingActivityId string
}

type RemoveInstancesArgs struct {
	ScalingGroupId string
	InstanceId     common.FlattenArray
}

type RemoveInstancesResponse struct {
	common.Response
	ScalingActivityId string
}

// AttachInstances attach instances to scaling group
//
// You can read doc at https://help.aliyun.com/document_detail/25954.html?spm=5176.product25855.6.633.y5gmzX
func (client *Client) AttachInstances(args *AttachInstancesArgs) (resp *AttachInstancesResponse, err error) {
	response := AttachInstancesResponse{}
	err = client.InvokeByFlattenMethod("AttachInstances", args, &response)

	if err != nil {
		return nil, err
	}
	return &response, nil
}

// RemoveInstances detach instances from scaling group
//
// You can read doc at https://help.aliyun.com/document_detail/25955.html?spm=5176.doc25954.6.634.GtpzuJ
func (client *Client) RemoveInstances(args *RemoveInstancesArgs) (resp *RemoveInstancesResponse, err error) {
	response := RemoveInstancesResponse{}
	err = client.InvokeByFlattenMethod("RemoveInstances", args, &response)

	if err != nil {
		return nil, err
	}
	return &response, nil
}
<|endoftext|>


<commit_before>package mocknet

import (
	"fmt"
	"sync"

	inet "github.com/jbenet/go-ipfs/net"
	peer "github.com/jbenet/go-ipfs/peer"
	testutil "github.com/jbenet/go-ipfs/util/testutil"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	ctxgroup "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-ctxgroup"
)

type peerID string

// mocknet implements mocknet.Mocknet
type mocknet struct {
	// must map on peer.ID (instead of peer.Peer) because
	// each inet.Network has different peerstore
	nets map[peerID]*peernet

	// links make it possible to connect two peers.
	// think of links as the physical medium.
	// usually only one, but there could be multiple
	// **links are shared between peers**
	links map[peerID]map[peerID]map[*link]struct{}

	linkDefaults LinkOptions

	cg ctxgroup.ContextGroup // for Context closing
	sync.RWMutex
}

func New(ctx context.Context) Mocknet {
	return &mocknet{
		nets:  map[peerID]*peernet{},
		links: map[peerID]map[peerID]map[*link]struct{}{},
	}
}

func (mn *mocknet) GenPeer() (inet.Network, error) {
	p, err := testutil.PeerWithNewKeys()
	if err != nil {
		return nil, err
	}

	n, err := mn.AddPeer(p.ID())
	if err != nil {
		return nil, err
	}

	// copy over keys
	if err := n.LocalPeer().Update(p); err != nil {
		return nil, err
	}

	return n, nil
}

func (mn *mocknet) AddPeer(p peer.ID) (inet.Network, error) {
	n, err := newPeernet(mn.cg.Context(), mn, p)
	if err != nil {
		return nil, err
	}

	mn.cg.AddChildGroup(n.cg)

	mn.Lock()
	mn.nets[pid(n.peer)] = n
	mn.Unlock()
	return n, nil
}

func (mn *mocknet) Peer(pid peer.ID) peer.Peer {
	mn.RLock()
	defer mn.RUnlock()

	for _, n := range mn.nets {
		if n.peer.ID().Equal(pid) {
			return n.peer
		}
	}
	return nil
}

func (mn *mocknet) Peers() []peer.Peer {
	mn.RLock()
	defer mn.RUnlock()

	cp := make([]peer.Peer, 0, len(mn.nets))
	for _, n := range mn.nets {
		cp = append(cp, n.peer)
	}
	return cp
}

func (mn *mocknet) Net(pid peer.ID) inet.Network {
	mn.RLock()
	defer mn.RUnlock()

	for _, n := range mn.nets {
		if n.peer.ID().Equal(pid) {
			return n
		}
	}
	return nil
}

func (mn *mocknet) Nets() []inet.Network {
	mn.RLock()
	defer mn.RUnlock()

	cp := make([]inet.Network, 0, len(mn.nets))
	for _, n := range mn.nets {
		cp = append(cp, n)
	}
	return cp
}

func (mn *mocknet) LinkAll() error {
	nets := mn.Nets()
	for _, n1 := range nets {
		for _, n2 := range nets {
			if _, err := mn.LinkNets(n1, n2); err != nil {
				return err
			}
		}
	}
	return nil
}

func (mn *mocknet) LinkPeers(p1, p2 peer.Peer) (Link, error) {
	mn.RLock()
	n1 := mn.nets[pid(p1)]
	n2 := mn.nets[pid(p2)]
	mn.RUnlock()

	if n1 == nil {
		return nil, fmt.Errorf("network for p1 not in mocknet")
	}

	if n2 == nil {
		return nil, fmt.Errorf("network for p2 not in mocknet")
	}

	return mn.LinkNets(n1, n2)
}

func (mn *mocknet) validate(n inet.Network) (*peernet, error) {
	// WARNING: assumes locks acquired

	nr, ok := n.(*peernet)
	if !ok {
		return nil, fmt.Errorf("Network not supported (use mock package nets only)")
	}

	if _, found := mn.nets[pid(nr.peer)]; !found {
		return nil, fmt.Errorf("Network not on mocknet. is it from another mocknet?")
	}

	return nr, nil
}

func (mn *mocknet) LinkNets(n1, n2 inet.Network) (Link, error) {
	mn.Lock()
	defer mn.Unlock()

	if _, err := mn.validate(n1); err != nil {
		return nil, err
	}

	if _, err := mn.validate(n2); err != nil {
		return nil, err
	}

	l := newLink(mn)
	mn.addLink(l)
	return l, nil
}

func (mn *mocknet) Unlink(l2 Link) error {

	l, ok := l2.(*link)
	if !ok {
		return fmt.Errorf("only links from mocknet are supported")
	}

	mn.removeLink(l)
	return nil
}

func (mn *mocknet) UnlinkPeers(p1, p2 peer.Peer) error {
	ls := mn.LinksBetweenPeers(p1, p2)
	if ls == nil {
		return fmt.Errorf("no link between p1 and p2")
	}

	for _, l := range ls {
		if err := mn.Unlink(l); err != nil {
			return err
		}
	}
	return nil
}

func (mn *mocknet) UnlinkNets(n1, n2 inet.Network) error {
	return mn.DisconnectPeers(n1.LocalPeer(), n2.LocalPeer())
}

func (mn *mocknet) addLink(l *link) {
	mn.Lock()
	defer mn.Unlock()

	n1, n2 := l.nets[0], l.nets[1]
	mn.links[pid(n1.peer)][pid(n2.peer)][l] = struct{}{}
	mn.links[pid(n2.peer)][pid(n1.peer)][l] = struct{}{}
}

func (mn *mocknet) removeLink(l *link) {
	mn.Lock()
	defer mn.Unlock()

	n1, n2 := l.nets[0], l.nets[1]
	delete(mn.links[pid(n1.peer)][pid(n2.peer)], l)
	delete(mn.links[pid(n2.peer)][pid(n1.peer)], l)
}

func (mn *mocknet) ConnectAll(p1, p2 peer.Peer) (Link, error) {
	panic("nyi")
}

func (mn *mocknet) ConnectPeers(a, b peer.Peer) error {
	panic("nyi")
}

func (mn *mocknet) ConnectNets(inet.Network, inet.Network) error {
	panic("nyi")
}

func (mn *mocknet) DisconnectPeers(p1, p2 peer.Peer) error {
	panic("nyi")
}

func (mn *mocknet) DisconnectNets(n1, n2 inet.Network) error {
	return mn.DisconnectPeers(n1.LocalPeer(), n2.LocalPeer())
}

func (mn *mocknet) LinksBetweenPeers(p1, p2 peer.Peer) []Link {
	mn.RLock()
	defer mn.RUnlock()

	ls1, found := mn.links[pid(p1)]
	if !found {
		return nil
	}

	ls2, found := ls1[pid(p2)]
	if !found {
		return nil
	}

	cp := make([]Link, 0, len(ls2))
	for l := range ls2 {
		cp = append(cp, l)
	}
	return cp
}

func (mn *mocknet) LinksBetweenNets(n1, n2 inet.Network) []Link {
	return mn.LinksBetweenPeers(n1.LocalPeer(), n2.LocalPeer())
}

func (mn *mocknet) SetLinkDefaults(o LinkOptions) {
	mn.Lock()
	mn.linkDefaults = o
	mn.Unlock()
}

func (mn *mocknet) LinkDefaults() LinkOptions {
	mn.RLock()
	defer mn.RUnlock()
	return mn.linkDefaults
}
<commit_msg>unlinkPeers fix<commit_after>package mocknet

import (
	"fmt"
	"sync"

	inet "github.com/jbenet/go-ipfs/net"
	peer "github.com/jbenet/go-ipfs/peer"
	testutil "github.com/jbenet/go-ipfs/util/testutil"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	ctxgroup "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-ctxgroup"
)

type peerID string

// mocknet implements mocknet.Mocknet
type mocknet struct {
	// must map on peer.ID (instead of peer.Peer) because
	// each inet.Network has different peerstore
	nets map[peerID]*peernet

	// links make it possible to connect two peers.
	// think of links as the physical medium.
	// usually only one, but there could be multiple
	// **links are shared between peers**
	links map[peerID]map[peerID]map[*link]struct{}

	linkDefaults LinkOptions

	cg ctxgroup.ContextGroup // for Context closing
	sync.RWMutex
}

func New(ctx context.Context) Mocknet {
	return &mocknet{
		nets:  map[peerID]*peernet{},
		links: map[peerID]map[peerID]map[*link]struct{}{},
	}
}

func (mn *mocknet) GenPeer() (inet.Network, error) {
	p, err := testutil.PeerWithNewKeys()
	if err != nil {
		return nil, err
	}

	n, err := mn.AddPeer(p.ID())
	if err != nil {
		return nil, err
	}

	// copy over keys
	if err := n.LocalPeer().Update(p); err != nil {
		return nil, err
	}

	return n, nil
}

func (mn *mocknet) AddPeer(p peer.ID) (inet.Network, error) {
	n, err := newPeernet(mn.cg.Context(), mn, p)
	if err != nil {
		return nil, err
	}

	mn.cg.AddChildGroup(n.cg)

	mn.Lock()
	mn.nets[pid(n.peer)] = n
	mn.Unlock()
	return n, nil
}

func (mn *mocknet) Peer(pid peer.ID) peer.Peer {
	mn.RLock()
	defer mn.RUnlock()

	for _, n := range mn.nets {
		if n.peer.ID().Equal(pid) {
			return n.peer
		}
	}
	return nil
}

func (mn *mocknet) Peers() []peer.Peer {
	mn.RLock()
	defer mn.RUnlock()

	cp := make([]peer.Peer, 0, len(mn.nets))
	for _, n := range mn.nets {
		cp = append(cp, n.peer)
	}
	return cp
}

func (mn *mocknet) Net(pid peer.ID) inet.Network {
	mn.RLock()
	defer mn.RUnlock()

	for _, n := range mn.nets {
		if n.peer.ID().Equal(pid) {
			return n
		}
	}
	return nil
}

func (mn *mocknet) Nets() []inet.Network {
	mn.RLock()
	defer mn.RUnlock()

	cp := make([]inet.Network, 0, len(mn.nets))
	for _, n := range mn.nets {
		cp = append(cp, n)
	}
	return cp
}

func (mn *mocknet) LinkAll() error {
	nets := mn.Nets()
	for _, n1 := range nets {
		for _, n2 := range nets {
			if _, err := mn.LinkNets(n1, n2); err != nil {
				return err
			}
		}
	}
	return nil
}

func (mn *mocknet) LinkPeers(p1, p2 peer.Peer) (Link, error) {
	mn.RLock()
	n1 := mn.nets[pid(p1)]
	n2 := mn.nets[pid(p2)]
	mn.RUnlock()

	if n1 == nil {
		return nil, fmt.Errorf("network for p1 not in mocknet")
	}

	if n2 == nil {
		return nil, fmt.Errorf("network for p2 not in mocknet")
	}

	return mn.LinkNets(n1, n2)
}

func (mn *mocknet) validate(n inet.Network) (*peernet, error) {
	// WARNING: assumes locks acquired

	nr, ok := n.(*peernet)
	if !ok {
		return nil, fmt.Errorf("Network not supported (use mock package nets only)")
	}

	if _, found := mn.nets[pid(nr.peer)]; !found {
		return nil, fmt.Errorf("Network not on mocknet. is it from another mocknet?")
	}

	return nr, nil
}

func (mn *mocknet) LinkNets(n1, n2 inet.Network) (Link, error) {
	mn.Lock()
	defer mn.Unlock()

	if _, err := mn.validate(n1); err != nil {
		return nil, err
	}

	if _, err := mn.validate(n2); err != nil {
		return nil, err
	}

	l := newLink(mn)
	mn.addLink(l)
	return l, nil
}

func (mn *mocknet) Unlink(l2 Link) error {

	l, ok := l2.(*link)
	if !ok {
		return fmt.Errorf("only links from mocknet are supported")
	}

	mn.removeLink(l)
	return nil
}

func (mn *mocknet) UnlinkPeers(p1, p2 peer.Peer) error {
	ls := mn.LinksBetweenPeers(p1, p2)
	if ls == nil {
		return fmt.Errorf("no link between p1 and p2")
	}

	for _, l := range ls {
		if err := mn.Unlink(l); err != nil {
			return err
		}
	}
	return nil
}

func (mn *mocknet) UnlinkNets(n1, n2 inet.Network) error {
	return mn.UnlinkPeers(n1.LocalPeer(), n2.LocalPeer())
}

func (mn *mocknet) addLink(l *link) {
	mn.Lock()
	defer mn.Unlock()

	n1, n2 := l.nets[0], l.nets[1]
	mn.links[pid(n1.peer)][pid(n2.peer)][l] = struct{}{}
	mn.links[pid(n2.peer)][pid(n1.peer)][l] = struct{}{}
}

func (mn *mocknet) removeLink(l *link) {
	mn.Lock()
	defer mn.Unlock()

	n1, n2 := l.nets[0], l.nets[1]
	delete(mn.links[pid(n1.peer)][pid(n2.peer)], l)
	delete(mn.links[pid(n2.peer)][pid(n1.peer)], l)
}

func (mn *mocknet) ConnectAll(p1, p2 peer.Peer) (Link, error) {
	panic("nyi")
}

func (mn *mocknet) ConnectPeers(a, b peer.Peer) error {
	panic("nyi")
}

func (mn *mocknet) ConnectNets(inet.Network, inet.Network) error {
	panic("nyi")
}

func (mn *mocknet) DisconnectPeers(p1, p2 peer.Peer) error {
	panic("nyi")
}

func (mn *mocknet) DisconnectNets(n1, n2 inet.Network) error {
	return mn.DisconnectPeers(n1.LocalPeer(), n2.LocalPeer())
}

func (mn *mocknet) LinksBetweenPeers(p1, p2 peer.Peer) []Link {
	mn.RLock()
	defer mn.RUnlock()

	ls1, found := mn.links[pid(p1)]
	if !found {
		return nil
	}

	ls2, found := ls1[pid(p2)]
	if !found {
		return nil
	}

	cp := make([]Link, 0, len(ls2))
	for l := range ls2 {
		cp = append(cp, l)
	}
	return cp
}

func (mn *mocknet) LinksBetweenNets(n1, n2 inet.Network) []Link {
	return mn.LinksBetweenPeers(n1.LocalPeer(), n2.LocalPeer())
}

func (mn *mocknet) SetLinkDefaults(o LinkOptions) {
	mn.Lock()
	mn.linkDefaults = o
	mn.Unlock()
}

func (mn *mocknet) LinkDefaults() LinkOptions {
	mn.RLock()
	defer mn.RUnlock()
	return mn.linkDefaults
}
<|endoftext|>


<commit_before>package rest

import (
	"fmt"
	"net/http"
	"reflect"
)

// BaseResourceHandler is a base implementation of ResourceHandler with stubs for the
// CRUD operations. This allows ResourceHandler implementations to only implement
// what they need.
type BaseResourceHandler struct{}

// ResourceName is a stub. It must be implemented.
func (b BaseResourceHandler) ResourceName() string {
	return ""
}

// CreateURI is a stub. Implement if necessary. The default create URI is
// /api/v{version:[^/]+}/resourceName.
func (b BaseResourceHandler) CreateURI() string {
	return ""
}

// ReadURI is a stub. Implement if necessary. The default read URI is
// /api/v{version:[^/]+}/resourceName/{resource_id}.
func (b BaseResourceHandler) ReadURI() string {
	return ""
}

// ReadListURI is a stub. Implement if necessary. The default read list URI is
// /api/v{version:[^/]+}/resourceName.
func (b BaseResourceHandler) ReadListURI() string {
	return ""
}

// UpdateURI is a stub. Implement if necessary. The default update URI is
// /api/v{version:[^/]+}/resourceName/{resource_id}.
func (b BaseResourceHandler) UpdateURI() string {
	return ""
}

// DeleteURI is a stub. Implement if necessary. The default delete URI is
// /api/v{version:[^/]+}/resourceName/{resource_id}.
func (b BaseResourceHandler) DeleteURI() string {
	return ""
}

// EmptyResource is a stub. Implement if Rules are defined.
func (b BaseResourceHandler) EmptyResource() interface{} {
	return nil
}

// CreateResource is a stub. Implement if necessary.
func (b BaseResourceHandler) CreateResource(ctx RequestContext, data Payload,
	version string) (Resource, error) {
	return nil, NotImplemented("CreateResource is not implemented")
}

// ReadResourceList is a stub. Implement if necessary.
func (b BaseResourceHandler) ReadResourceList(ctx RequestContext, limit int,
	cursor string, version string) ([]Resource, string, error) {
	return nil, "", NotImplemented("ReadResourceList not implemented")
}

// ReadResource is a stub. Implement if necessary.
func (b BaseResourceHandler) ReadResource(ctx RequestContext, id string,
	version string) (Resource, error) {
	return nil, NotImplemented("ReadResource not implemented")
}

// UpdateResource is a stub. Implement if necessary.
func (b BaseResourceHandler) UpdateResource(ctx RequestContext, id string,
	data Payload, version string) (Resource, error) {
	return nil, NotImplemented("UpdateResource not implemented")
}

// DeleteResource is a stub. Implement if necessary.
func (b BaseResourceHandler) DeleteResource(ctx RequestContext, id string,
	version string) (Resource, error) {
	return nil, NotImplemented("DeleteResource not implemented")
}

// Authenticate is the default authentication logic. All requests are authorized.
// Implement custom authentication logic if necessary.
func (b BaseResourceHandler) Authenticate(r http.Request) error {
	return nil
}

// Rules returns the resource rules to apply to incoming requests and outgoing
// responses. No rules are applied by default. Implement if necessary.
func (b BaseResourceHandler) Rules() Rules {
	return Rules{}
}

// resourceHandlerProxy wraps a ResourceHandler and injects the resource type into its
// Rules. This allows the framework to provide additional logic around the proxied
// ResourceHandler. It also provides default logic such as REST URIs.
type resourceHandlerProxy struct {
	ResourceHandler
}

// ResourceName returns the wrapped ResourceHandler's resource name. If the proxied
// handler doesn't have ResourceName implemented, it panics.
func (r resourceHandlerProxy) ResourceName() string {
	name := r.ResourceHandler.ResourceName()
	if name == "" {
		panic("ResourceHandler must implement ResourceName()")
	}
	return name
}

// Rules returns the wrapped ResourceHandler's Rules after injecting them with the
// resource type.
func (r resourceHandlerProxy) Rules() Rules {
	rules := r.ResourceHandler.Rules()
	for _, rule := range rules {
		// Associate Rules with their respective type.
		rule.resourceType = reflect.TypeOf(r.EmptyResource())
	}

	return rules
}

// CreateURI returns the URI for creating a resource using the handler-specified
// URI while falling back to a sensible default if not provided.
func (r resourceHandlerProxy) CreateURI() string {
	url := r.ResourceHandler.CreateURI()
	if url == "" {
		url = fmt.Sprintf("/api/v{%s:[^/]+}/%s", versionKey, r.ResourceName())
	}
	return url
}

// ReadURI returns the URI for reading a specific resource using the handler-specified
// URI while falling back to a sensible default if not provided.
func (r resourceHandlerProxy) ReadURI() string {
	url := r.ResourceHandler.ReadURI()
	if url == "" {
		url = fmt.Sprintf("/api/v{%s:[^/]+}/%s/{%s}", versionKey, r.ResourceName(),
			resourceIDKey)
	}
	return url
}

// ReadListURI returns the URI for reading a list of resources using the handler-
// specified URI while falling back to a sensible default if not provided.
func (r resourceHandlerProxy) ReadListURI() string {
	url := r.ResourceHandler.ReadListURI()
	if url == "" {
		url = fmt.Sprintf("/api/v{%s:[^/]+}/%s", versionKey, r.ResourceName())
	}
	return url
}

// UpdateURI returns the URI for updating a specific resource using the handler-
// specified URI while falling back to a sensible default if not provided.
func (r resourceHandlerProxy) UpdateURI() string {
	url := r.ResourceHandler.UpdateURI()
	if url == "" {
		url = fmt.Sprintf("/api/v{%s:[^/]+}/%s/{%s}", versionKey, r.ResourceName(),
			resourceIDKey)
	}
	return url
}

// DeleteURI returns the URI for deleting a specific resource using the handler-
// specified URI while falling back to a sensible default if not provided.
func (r resourceHandlerProxy) DeleteURI() string {
	url := r.ResourceHandler.DeleteURI()
	if url == "" {
		url = fmt.Sprintf("/api/v{%s:[^/]+}/%s/{%s}", versionKey,
			r.ResourceHandler.ResourceName(), resourceIDKey)
	}
	return url
}
<commit_msg>Rename url to uri to be more accurate<commit_after>package rest

import (
	"fmt"
	"net/http"
	"reflect"
)

// BaseResourceHandler is a base implementation of ResourceHandler with stubs for the
// CRUD operations. This allows ResourceHandler implementations to only implement
// what they need.
type BaseResourceHandler struct{}

// ResourceName is a stub. It must be implemented.
func (b BaseResourceHandler) ResourceName() string {
	return ""
}

// CreateURI is a stub. Implement if necessary. The default create URI is
// /api/v{version:[^/]+}/resourceName.
func (b BaseResourceHandler) CreateURI() string {
	return ""
}

// ReadURI is a stub. Implement if necessary. The default read URI is
// /api/v{version:[^/]+}/resourceName/{resource_id}.
func (b BaseResourceHandler) ReadURI() string {
	return ""
}

// ReadListURI is a stub. Implement if necessary. The default read list URI is
// /api/v{version:[^/]+}/resourceName.
func (b BaseResourceHandler) ReadListURI() string {
	return ""
}

// UpdateURI is a stub. Implement if necessary. The default update URI is
// /api/v{version:[^/]+}/resourceName/{resource_id}.
func (b BaseResourceHandler) UpdateURI() string {
	return ""
}

// DeleteURI is a stub. Implement if necessary. The default delete URI is
// /api/v{version:[^/]+}/resourceName/{resource_id}.
func (b BaseResourceHandler) DeleteURI() string {
	return ""
}

// EmptyResource is a stub. Implement if Rules are defined.
func (b BaseResourceHandler) EmptyResource() interface{} {
	return nil
}

// CreateResource is a stub. Implement if necessary.
func (b BaseResourceHandler) CreateResource(ctx RequestContext, data Payload,
	version string) (Resource, error) {
	return nil, NotImplemented("CreateResource is not implemented")
}

// ReadResourceList is a stub. Implement if necessary.
func (b BaseResourceHandler) ReadResourceList(ctx RequestContext, limit int,
	cursor string, version string) ([]Resource, string, error) {
	return nil, "", NotImplemented("ReadResourceList not implemented")
}

// ReadResource is a stub. Implement if necessary.
func (b BaseResourceHandler) ReadResource(ctx RequestContext, id string,
	version string) (Resource, error) {
	return nil, NotImplemented("ReadResource not implemented")
}

// UpdateResource is a stub. Implement if necessary.
func (b BaseResourceHandler) UpdateResource(ctx RequestContext, id string,
	data Payload, version string) (Resource, error) {
	return nil, NotImplemented("UpdateResource not implemented")
}

// DeleteResource is a stub. Implement if necessary.
func (b BaseResourceHandler) DeleteResource(ctx RequestContext, id string,
	version string) (Resource, error) {
	return nil, NotImplemented("DeleteResource not implemented")
}

// Authenticate is the default authentication logic. All requests are authorized.
// Implement custom authentication logic if necessary.
func (b BaseResourceHandler) Authenticate(r http.Request) error {
	return nil
}

// Rules returns the resource rules to apply to incoming requests and outgoing
// responses. No rules are applied by default. Implement if necessary.
func (b BaseResourceHandler) Rules() Rules {
	return Rules{}
}

// resourceHandlerProxy wraps a ResourceHandler and injects the resource type into its
// Rules. This allows the framework to provide additional logic around the proxied
// ResourceHandler. It also provides default logic such as REST URIs.
type resourceHandlerProxy struct {
	ResourceHandler
}

// ResourceName returns the wrapped ResourceHandler's resource name. If the proxied
// handler doesn't have ResourceName implemented, it panics.
func (r resourceHandlerProxy) ResourceName() string {
	name := r.ResourceHandler.ResourceName()
	if name == "" {
		panic("ResourceHandler must implement ResourceName()")
	}
	return name
}

// Rules returns the wrapped ResourceHandler's Rules after injecting them with the
// resource type.
func (r resourceHandlerProxy) Rules() Rules {
	rules := r.ResourceHandler.Rules()
	for _, rule := range rules {
		// Associate Rules with their respective type.
		rule.resourceType = reflect.TypeOf(r.EmptyResource())
	}

	return rules
}

// CreateURI returns the URI for creating a resource using the handler-specified
// URI while falling back to a sensible default if not provided.
func (r resourceHandlerProxy) CreateURI() string {
	uri := r.ResourceHandler.CreateURI()
	if uri == "" {
		uri = fmt.Sprintf("/api/v{%s:[^/]+}/%s", versionKey, r.ResourceName())
	}
	return uri
}

// ReadURI returns the URI for reading a specific resource using the handler-specified
// URI while falling back to a sensible default if not provided.
func (r resourceHandlerProxy) ReadURI() string {
	uri := r.ResourceHandler.ReadURI()
	if uri == "" {
		uri = fmt.Sprintf("/api/v{%s:[^/]+}/%s/{%s}", versionKey, r.ResourceName(),
			resourceIDKey)
	}
	return uri
}

// ReadListURI returns the URI for reading a list of resources using the handler-
// specified URI while falling back to a sensible default if not provided.
func (r resourceHandlerProxy) ReadListURI() string {
	uri := r.ResourceHandler.ReadListURI()
	if uri == "" {
		uri = fmt.Sprintf("/api/v{%s:[^/]+}/%s", versionKey, r.ResourceName())
	}
	return uri
}

// UpdateURI returns the URI for updating a specific resource using the handler-
// specified URI while falling back to a sensible default if not provided.
func (r resourceHandlerProxy) UpdateURI() string {
	uri := r.ResourceHandler.UpdateURI()
	if uri == "" {
		uri = fmt.Sprintf("/api/v{%s:[^/]+}/%s/{%s}", versionKey, r.ResourceName(),
			resourceIDKey)
	}
	return uri
}

// DeleteURI returns the URI for deleting a specific resource using the handler-
// specified URI while falling back to a sensible default if not provided.
func (r resourceHandlerProxy) DeleteURI() string {
	uri := r.ResourceHandler.DeleteURI()
	if uri == "" {
		uri = fmt.Sprintf("/api/v{%s:[^/]+}/%s/{%s}", versionKey,
			r.ResourceHandler.ResourceName(), resourceIDKey)
	}
	return uri
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/codegangsta/cli"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

// TODO(jrubin) test recursive keys
func TestEtcd(t *testing.T) {
	Convey("When getting keys from etcd", t, func() {
		set := flagSet(appTest.Name, appTest.Flags)
		ctx := cli.NewContext(appTest, set, set)

		etcdConf := newEtcdConfig(ctx)
		etcdClient, err := getClient(etcdConf)

		Convey("newEtcdConfig should return an etcd config", func() {
			So(etcdConf.Key.Prefix, ShouldEqual, "/config")
			So(etcdConf.Key.Hostname, ShouldEqual, "env")
			So(etcdConf.Sync, ShouldBeTrue)
			So(etcdConf.Key.System, ShouldEqual, "nsq")
			So(etcdConf.Key.Service, ShouldEqual, "redis")
			So(etcdConf.Peers, ShouldContain, "http://127.0.0.1:4001")

			Convey("getClient should return an etcd client based on a given config", func() {
				So(err, ShouldBeNil)
				So(etcdClient, ShouldNotBeEmpty)
				So(etcdClient.CheckRetry, ShouldBeNil)

				Convey("getKeyPairs returns keypairs", func() {
					keyPairs := getKeyPairs(etcdConf, etcdClient)
					So(keyPairs["system_nsq_service_zvelo-nsq_PortA"], ShouldEqual, "1111")
					So(keyPairs["service_zvelo-nsqd_PortA"], ShouldEqual, "4150")
					So(keyPairs["service_zvelo-nsqd_PortB"], ShouldEqual, "4151")
					So(keyPairs["service_zvelo-nsqd_LookupAddress"], ShouldEqual, "172.17.8.101")
					So(keyPairs["port"], ShouldEqual, "1234")

				})
			})
		})
	})
}
<commit_msg>Added tests for getEnpoints and getTransport<commit_after>package main

import (
	"github.com/codegangsta/cli"
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

// TODO(jrubin) test recursive keys
func TestEtcd(t *testing.T) {
	Convey("When getting keys from etcd", t, func() {
		set := flagSet(appTest.Name, appTest.Flags)
		ctx := cli.NewContext(appTest, set, set)

		etcdConf := newEtcdConfig(ctx)
		etcdClient, err := getClient(etcdConf)

		Convey("newEtcdConfig should return an etcd config", func() {
			So(etcdConf.Key.Prefix, ShouldEqual, "/config")
			So(etcdConf.Key.Hostname, ShouldEqual, "env")
			So(etcdConf.Sync, ShouldBeTrue)
			So(etcdConf.Key.System, ShouldEqual, "nsq")
			So(etcdConf.Key.Service, ShouldEqual, "redis")
			So(etcdConf.Peers, ShouldContain, "http://127.0.0.1:4001")

			Convey("getEndpoints should return an array of end points", func() {
				endPoints, err := getEndpoints(etcdConf)
				So(err, ShouldBeNil)
				So(endPoints, ShouldContain, "http://127.0.0.1:4001")
			})

			Convey("getTransport should return an http transport object", func() {
				transObj, err := getTransport(etcdConf)
				So(err, ShouldBeNil)
				So(transObj.Proxy, ShouldBeNil)
				So(transObj.DisableKeepAlives, ShouldBeFalse)
				So(transObj.TLSHandshakeTimeout, ShouldEqual, 10000000000)
				So(transObj.MaxIdleConnsPerHost, ShouldBeZeroValue)
			})

			Convey("getClient should return an etcd client based on a given config", func() {
				So(err, ShouldBeNil)
				So(etcdClient, ShouldNotBeEmpty)
				So(etcdClient.CheckRetry, ShouldBeNil)

				Convey("getKeyPairs returns keypairs", func() {
					keyPairs := getKeyPairs(etcdConf, etcdClient)
					So(keyPairs["system_nsq_service_zvelo-nsq_PortA"], ShouldEqual, "1111")
					So(keyPairs["service_zvelo-nsqd_PortA"], ShouldEqual, "4150")
					So(keyPairs["service_zvelo-nsqd_PortB"], ShouldEqual, "4151")
					So(keyPairs["service_zvelo-nsqd_LookupAddress"], ShouldEqual, "172.17.8.101")
					So(keyPairs["port"], ShouldEqual, "1234")

				})
			})
		})
	})
}
<|endoftext|>


<commit_before>package medias

import (
	"io/ioutil"
	"encoding/json"
	"errors"
	"log"
	"github.com/mitchellh/mapstructure"
)

var Medias []Media

const path_to_config string = "data/medias.config.json"

func LoadMedias() {
	//Medias configurations are loaded from a JSON file on the FS.
	content, err := ioutil.ReadFile(path_to_config)
	check(err)

	var obj []interface{}
	json.Unmarshal([]byte(content), &obj)

	//Map the json to the Media structure
	for _, b := range obj {
		var media Media
		err = mapstructure.Decode(b.(map[string]interface{}), &media)
		if err != nil {
			panic(err)
		}

		Medias = append(Medias, media)
	}

	log.Print("Medias configurations is loaded...")
}

func GetMedia(idMedia string) (*Media, error) {
	for _, media := range Medias {
		if idMedia == media.ID {
			return &media, nil
		}
	}

	return nil, errors.New("NO_MEDIA_FOUND")
}
<commit_msg>[Add] Create and return a new empty media<commit_after>package medias

import (
	"encoding/json"
	"errors"
	"github.com/mitchellh/mapstructure"
	"io/ioutil"
	"log"
	"github.com/Zenika/MARCEL/backend/commons"
)

var Medias []Media

const path_to_config string = "data/medias.config.json"

func LoadMedias() {
	//Medias configurations are loaded from a JSON file on the FS.
	content, err := ioutil.ReadFile(path_to_config)
	check(err)

	var obj []interface{}
	json.Unmarshal([]byte(content), &obj)

	//Map the json to the Media structure
	for _, b := range obj {
		var media Media
		err = mapstructure.Decode(b.(map[string]interface{}), &media)
		if err != nil {
			panic(err)
		}

		Medias = append(Medias, media)
	}

	log.Print("Medias configurations is loaded...")
}

func GetMedia(idMedia string) (*Media, error) {
	for _, media := range Medias {
		if idMedia == media.ID {
			return &media, nil
		}
	}

	return nil, errors.New("NO_MEDIA_FOUND")
}

func CreateMedia() (*Media) {
	newMedia := new(Media)
	newMedia.ID = commons.GetUID()

	//SaveMedia(newMedia)

	return newMedia
}<|endoftext|>