<commit_before>package aws

import (
	"crypto/tls"
	"fmt"
	"log"
	"net/http"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/request"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/apigateway"
	"github.com/aws/aws-sdk-go/service/applicationautoscaling"
	"github.com/aws/aws-sdk-go/service/autoscaling"
	"github.com/aws/aws-sdk-go/service/cloudformation"
	"github.com/aws/aws-sdk-go/service/cloudfront"
	"github.com/aws/aws-sdk-go/service/cloudtrail"
	"github.com/aws/aws-sdk-go/service/cloudwatch"
	"github.com/aws/aws-sdk-go/service/cloudwatchevents"
	"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
	"github.com/aws/aws-sdk-go/service/codecommit"
	"github.com/aws/aws-sdk-go/service/codedeploy"
	"github.com/aws/aws-sdk-go/service/directoryservice"
	"github.com/aws/aws-sdk-go/service/dynamodb"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/aws/aws-sdk-go/service/ecr"
	"github.com/aws/aws-sdk-go/service/ecs"
	"github.com/aws/aws-sdk-go/service/efs"
	"github.com/aws/aws-sdk-go/service/elasticache"
	"github.com/aws/aws-sdk-go/service/elasticbeanstalk"
	elasticsearch "github.com/aws/aws-sdk-go/service/elasticsearchservice"
	"github.com/aws/aws-sdk-go/service/elastictranscoder"
	"github.com/aws/aws-sdk-go/service/elb"
	"github.com/aws/aws-sdk-go/service/emr"
	"github.com/aws/aws-sdk-go/service/firehose"
	"github.com/aws/aws-sdk-go/service/glacier"
	"github.com/aws/aws-sdk-go/service/iam"
	"github.com/aws/aws-sdk-go/service/kinesis"
	"github.com/aws/aws-sdk-go/service/kms"
	"github.com/aws/aws-sdk-go/service/lambda"
	"github.com/aws/aws-sdk-go/service/opsworks"
	"github.com/aws/aws-sdk-go/service/rds"
	"github.com/aws/aws-sdk-go/service/redshift"
	"github.com/aws/aws-sdk-go/service/route53"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/ses"
	"github.com/aws/aws-sdk-go/service/simpledb"
	"github.com/aws/aws-sdk-go/service/sns"
	"github.com/aws/aws-sdk-go/service/sqs"
	"github.com/aws/aws-sdk-go/service/sts"
	"github.com/hashicorp/errwrap"
	"github.com/hashicorp/go-cleanhttp"
	"github.com/hashicorp/go-multierror"
	"github.com/hashicorp/terraform/helper/logging"
	"github.com/hashicorp/terraform/terraform"
)

type Config struct {
	AccessKey     string
	SecretKey     string
	CredsFilename string
	Profile       string
	Token         string
	Region        string
	MaxRetries    int

	AllowedAccountIds   []interface{}
	ForbiddenAccountIds []interface{}

	DynamoDBEndpoint string
	KinesisEndpoint  string
	Ec2Endpoint      string
	IamEndpoint      string
	ElbEndpoint      string
	S3Endpoint       string
	Insecure         bool

	SkipCredsValidation     bool
	SkipRequestingAccountId bool
	SkipMetadataApiCheck    bool
	S3ForcePathStyle        bool
}

type AWSClient struct {
	cfconn                *cloudformation.CloudFormation
	cloudfrontconn        *cloudfront.CloudFront
	cloudtrailconn        *cloudtrail.CloudTrail
	cloudwatchconn        *cloudwatch.CloudWatch
	cloudwatchlogsconn    *cloudwatchlogs.CloudWatchLogs
	cloudwatcheventsconn  *cloudwatchevents.CloudWatchEvents
	dsconn                *directoryservice.DirectoryService
	dynamodbconn          *dynamodb.DynamoDB
	ec2conn               *ec2.EC2
	ecrconn               *ecr.ECR
	ecsconn               *ecs.ECS
	efsconn               *efs.EFS
	elbconn               *elb.ELB
	emrconn               *emr.EMR
	esconn                *elasticsearch.ElasticsearchService
	apigateway            *apigateway.APIGateway
	appautoscalingconn    *applicationautoscaling.ApplicationAutoScaling
	autoscalingconn       *autoscaling.AutoScaling
	s3conn                *s3.S3
	sesConn               *ses.SES
	simpledbconn          *simpledb.SimpleDB
	sqsconn               *sqs.SQS
	snsconn               *sns.SNS
	stsconn               *sts.STS
	redshiftconn          *redshift.Redshift
	r53conn               *route53.Route53
	accountid             string
	region                string
	rdsconn               *rds.RDS
	iamconn               *iam.IAM
	kinesisconn           *kinesis.Kinesis
	kmsconn               *kms.KMS
	firehoseconn          *firehose.Firehose
	elasticacheconn       *elasticache.ElastiCache
	elasticbeanstalkconn  *elasticbeanstalk.ElasticBeanstalk
	elastictranscoderconn *elastictranscoder.ElasticTranscoder
	lambdaconn            *lambda.Lambda
	opsworksconn          *opsworks.OpsWorks
	glacierconn           *glacier.Glacier
	codedeployconn        *codedeploy.CodeDeploy
	codecommitconn        *codecommit.CodeCommit
}

// Client configures and returns a fully initialized AWSClient
func (c *Config) Client() (interface{}, error) {
	// Get the auth and region. This can fail if keys/regions were not
	// specified and we're attempting to use the environment.
	var errs []error

	log.Println("[INFO] Building AWS region structure")
	err := c.ValidateRegion()
	if err != nil {
		errs = append(errs, err)
	}

	var client AWSClient
	if len(errs) == 0 {
		// store AWS region in client struct, for region specific operations such as
		// bucket storage in S3
		client.region = c.Region

		log.Println("[INFO] Building AWS auth structure")
		creds := GetCredentials(c)
		// Call Get to check for credential provider. If nothing found, we'll get an
		// error, and we can present it nicely to the user
		cp, err := creds.Get()
		if err != nil {
			if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoCredentialProviders" {
				errs = append(errs, fmt.Errorf(`No valid credential sources found for AWS Provider.
  Please see https://terraform.io/docs/providers/aws/index.html for more information on
  providing credentials for the AWS Provider`))
			} else {
				errs = append(errs, fmt.Errorf("Error loading credentials for AWS Provider: %s", err))
			}
			return nil, &multierror.Error{Errors: errs}
		}

		log.Printf("[INFO] AWS Auth provider used: %q", cp.ProviderName)

		awsConfig := &aws.Config{
			Credentials:      creds,
			Region:           aws.String(c.Region),
			MaxRetries:       aws.Int(c.MaxRetries),
			HTTPClient:       cleanhttp.DefaultClient(),
			S3ForcePathStyle: aws.Bool(c.S3ForcePathStyle),
		}

		if logging.IsDebugOrHigher() {
			awsConfig.LogLevel = aws.LogLevel(aws.LogDebugWithHTTPBody)
			awsConfig.Logger = awsLogger{}
		}

		if c.Insecure {
			transport := awsConfig.HTTPClient.Transport.(*http.Transport)
			transport.TLSClientConfig = &tls.Config{
				InsecureSkipVerify: true,
			}
		}

		// Set up base session
		sess, err := session.NewSession(awsConfig)
		if err != nil {
			return nil, errwrap.Wrapf("Error creating AWS session: %s", err)
		}
		sess.Handlers.Build.PushFrontNamed(addTerraformVersionToUserAgent)

		// Some services exist only in us-east-1, e.g. because they manage
		// resources that can span across multiple regions, or because
		// signature format v4 requires region to be us-east-1 for global
		// endpoints:
		// http://docs.aws.amazon.com/general/latest/gr/sigv4_changes.html
		usEast1Sess := sess.Copy(&aws.Config{Region: aws.String("us-east-1")})

		// Some services have user-configurable endpoints
		awsEc2Sess := sess.Copy(&aws.Config{Endpoint: aws.String(c.Ec2Endpoint)})
		awsElbSess := sess.Copy(&aws.Config{Endpoint: aws.String(c.ElbEndpoint)})
		awsIamSess := sess.Copy(&aws.Config{Endpoint: aws.String(c.IamEndpoint)})
		awsS3Sess := sess.Copy(&aws.Config{Endpoint: aws.String(c.S3Endpoint)})
		dynamoSess := sess.Copy(&aws.Config{Endpoint: aws.String(c.DynamoDBEndpoint)})
		kinesisSess := sess.Copy(&aws.Config{Endpoint: aws.String(c.KinesisEndpoint)})

		// These two services need to be set up early so we can check on AccountID
		client.iamconn = iam.New(awsIamSess)
		client.stsconn = sts.New(sess)

		if !c.SkipCredsValidation {
			err = c.ValidateCredentials(client.stsconn)
			if err != nil {
				errs = append(errs, err)
				return nil, &multierror.Error{Errors: errs}
			}
		}

		if !c.SkipRequestingAccountId {
			accountId, err := GetAccountId(client.iamconn, client.stsconn, cp.ProviderName)
			if err == nil {
				client.accountid = accountId
			}
		}

		authErr := c.ValidateAccountId(client.accountid)
		if authErr != nil {
			errs = append(errs, authErr)
		}

		client.apigateway = apigateway.New(sess)
		client.appautoscalingconn = applicationautoscaling.New(sess)
		client.autoscalingconn = autoscaling.New(sess)
		client.cfconn = cloudformation.New(sess)
		client.cloudfrontconn = cloudfront.New(sess)
		client.cloudtrailconn = cloudtrail.New(sess)
		client.cloudwatchconn = cloudwatch.New(sess)
		client.cloudwatcheventsconn = cloudwatchevents.New(sess)
		client.cloudwatchlogsconn = cloudwatchlogs.New(sess)
		client.codecommitconn = codecommit.New(usEast1Sess)
		client.codedeployconn = codedeploy.New(sess)
		client.dsconn = directoryservice.New(sess)
		client.dynamodbconn = dynamodb.New(dynamoSess)
		client.ec2conn = ec2.New(awsEc2Sess)
		client.ecrconn = ecr.New(sess)
		client.ecsconn = ecs.New(sess)
		client.efsconn = efs.New(sess)
		client.elasticacheconn = elasticache.New(sess)
		client.elasticbeanstalkconn = elasticbeanstalk.New(sess)
		client.elastictranscoderconn = elastictranscoder.New(sess)
		client.elbconn = elb.New(awsElbSess)
		client.emrconn = emr.New(sess)
		client.esconn = elasticsearch.New(sess)
		client.firehoseconn = firehose.New(sess)
		client.glacierconn = glacier.New(sess)
		client.kinesisconn = kinesis.New(kinesisSess)
		client.kmsconn = kms.New(sess)
		client.lambdaconn = lambda.New(sess)
		client.opsworksconn = opsworks.New(usEast1Sess)
		client.r53conn = route53.New(usEast1Sess)
		client.rdsconn = rds.New(sess)
		client.redshiftconn = redshift.New(sess)
		client.simpledbconn = simpledb.New(sess)
		client.s3conn = s3.New(awsS3Sess)
		client.sesConn = ses.New(sess)
		client.snsconn = sns.New(sess)
		client.sqsconn = sqs.New(sess)
	}

	if len(errs) > 0 {
		return nil, &multierror.Error{Errors: errs}
	}

	return &client, nil
}

// ValidateRegion returns an error if the configured region is not a
// valid aws region and nil otherwise.
func (c *Config) ValidateRegion() error {
	var regions = [13]string{
		"ap-northeast-1",
		"ap-northeast-2",
		"ap-south-1",
		"ap-southeast-1",
		"ap-southeast-2",
		"cn-north-1",
		"eu-central-1",
		"eu-west-1",
		"sa-east-1",
		"us-east-1",
		"us-gov-west-1",
		"us-west-1",
		"us-west-2",
	}

	for _, valid := range regions {
		if c.Region == valid {
			return nil
		}
	}
	return fmt.Errorf("Not a valid region: %s", c.Region)
}

// Validate credentials early and fail before we do any graph walking.
func (c *Config) ValidateCredentials(stsconn *sts.STS) error {
	_, err := stsconn.GetCallerIdentity(&sts.GetCallerIdentityInput{})
	return err
}

// ValidateAccountId returns a context-specific error if the configured account
// id is explicitly forbidden or not authorised; and nil if it is authorised.
func (c *Config) ValidateAccountId(accountId string) error {
	if c.AllowedAccountIds == nil && c.ForbiddenAccountIds == nil {
		return nil
	}

	log.Printf("[INFO] Validating account ID")

	if c.ForbiddenAccountIds != nil {
		for _, id := range c.ForbiddenAccountIds {
			if id == accountId {
				return fmt.Errorf("Forbidden account ID (%s)", id)
			}
		}
	}

	if c.AllowedAccountIds != nil {
		for _, id := range c.AllowedAccountIds {
			if id == accountId {
				return nil
			}
		}
		return fmt.Errorf("Account ID not allowed (%s)", accountId)
	}

	return nil
}

// addTerraformVersionToUserAgent is a named handler that will add Terraform's
// version information to requests made by the AWS SDK.
var addTerraformVersionToUserAgent = request.NamedHandler{
	Name: "terraform.TerraformVersionUserAgentHandler",
	Fn: request.MakeAddToUserAgentHandler(
		"terraform", terraform.VersionString()),
}

type awsLogger struct{}

func (l awsLogger) Log(args ...interface{}) {
	tokens := make([]string, 0, len(args))
	for _, arg := range args {
		if token, ok := arg.(string); ok {
			tokens = append(tokens, token)
		}
	}
	log.Printf("[DEBUG] [aws-sdk-go] %s", strings.Join(tokens, " "))
}
<commit_msg>provider/aws: Add ELBv2 to AWS config<commit_after>package aws

import (
	"crypto/tls"
	"fmt"
	"log"
	"net/http"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/request"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/apigateway"
	"github.com/aws/aws-sdk-go/service/applicationautoscaling"
	"github.com/aws/aws-sdk-go/service/autoscaling"
	"github.com/aws/aws-sdk-go/service/cloudformation"
	"github.com/aws/aws-sdk-go/service/cloudfront"
	"github.com/aws/aws-sdk-go/service/cloudtrail"
	"github.com/aws/aws-sdk-go/service/cloudwatch"
	"github.com/aws/aws-sdk-go/service/cloudwatchevents"
	"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
	"github.com/aws/aws-sdk-go/service/codecommit"
	"github.com/aws/aws-sdk-go/service/codedeploy"
	"github.com/aws/aws-sdk-go/service/directoryservice"
	"github.com/aws/aws-sdk-go/service/dynamodb"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/aws/aws-sdk-go/service/ecr"
	"github.com/aws/aws-sdk-go/service/ecs"
	"github.com/aws/aws-sdk-go/service/efs"
	"github.com/aws/aws-sdk-go/service/elasticache"
	"github.com/aws/aws-sdk-go/service/elasticbeanstalk"
	elasticsearch "github.com/aws/aws-sdk-go/service/elasticsearchservice"
	"github.com/aws/aws-sdk-go/service/elastictranscoder"
	"github.com/aws/aws-sdk-go/service/elb"
	"github.com/aws/aws-sdk-go/service/elbv2"
	"github.com/aws/aws-sdk-go/service/emr"
	"github.com/aws/aws-sdk-go/service/firehose"
	"github.com/aws/aws-sdk-go/service/glacier"
	"github.com/aws/aws-sdk-go/service/iam"
	"github.com/aws/aws-sdk-go/service/kinesis"
	"github.com/aws/aws-sdk-go/service/kms"
	"github.com/aws/aws-sdk-go/service/lambda"
	"github.com/aws/aws-sdk-go/service/opsworks"
	"github.com/aws/aws-sdk-go/service/rds"
	"github.com/aws/aws-sdk-go/service/redshift"
	"github.com/aws/aws-sdk-go/service/route53"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/ses"
	"github.com/aws/aws-sdk-go/service/simpledb"
	"github.com/aws/aws-sdk-go/service/sns"
	"github.com/aws/aws-sdk-go/service/sqs"
	"github.com/aws/aws-sdk-go/service/sts"
	"github.com/hashicorp/errwrap"
	"github.com/hashicorp/go-cleanhttp"
	"github.com/hashicorp/go-multierror"
	"github.com/hashicorp/terraform/helper/logging"
	"github.com/hashicorp/terraform/terraform"
)

type Config struct {
	AccessKey     string
	SecretKey     string
	CredsFilename string
	Profile       string
	Token         string
	Region        string
	MaxRetries    int

	AllowedAccountIds   []interface{}
	ForbiddenAccountIds []interface{}

	DynamoDBEndpoint string
	KinesisEndpoint  string
	Ec2Endpoint      string
	IamEndpoint      string
	ElbEndpoint      string
	S3Endpoint       string
	Insecure         bool

	SkipCredsValidation     bool
	SkipRequestingAccountId bool
	SkipMetadataApiCheck    bool
	S3ForcePathStyle        bool
}

type AWSClient struct {
	cfconn                *cloudformation.CloudFormation
	cloudfrontconn        *cloudfront.CloudFront
	cloudtrailconn        *cloudtrail.CloudTrail
	cloudwatchconn        *cloudwatch.CloudWatch
	cloudwatchlogsconn    *cloudwatchlogs.CloudWatchLogs
	cloudwatcheventsconn  *cloudwatchevents.CloudWatchEvents
	dsconn                *directoryservice.DirectoryService
	dynamodbconn          *dynamodb.DynamoDB
	ec2conn               *ec2.EC2
	ecrconn               *ecr.ECR
	ecsconn               *ecs.ECS
	efsconn               *efs.EFS
	elbconn               *elb.ELB
	elbv2conn             *elbv2.ELBV2
	emrconn               *emr.EMR
	esconn                *elasticsearch.ElasticsearchService
	apigateway            *apigateway.APIGateway
	appautoscalingconn    *applicationautoscaling.ApplicationAutoScaling
	autoscalingconn       *autoscaling.AutoScaling
	s3conn                *s3.S3
	sesConn               *ses.SES
	simpledbconn          *simpledb.SimpleDB
	sqsconn               *sqs.SQS
	snsconn               *sns.SNS
	stsconn               *sts.STS
	redshiftconn          *redshift.Redshift
	r53conn               *route53.Route53
	accountid             string
	region                string
	rdsconn               *rds.RDS
	iamconn               *iam.IAM
	kinesisconn           *kinesis.Kinesis
	kmsconn               *kms.KMS
	firehoseconn          *firehose.Firehose
	elasticacheconn       *elasticache.ElastiCache
	elasticbeanstalkconn  *elasticbeanstalk.ElasticBeanstalk
	elastictranscoderconn *elastictranscoder.ElasticTranscoder
	lambdaconn            *lambda.Lambda
	opsworksconn          *opsworks.OpsWorks
	glacierconn           *glacier.Glacier
	codedeployconn        *codedeploy.CodeDeploy
	codecommitconn        *codecommit.CodeCommit
}

// Client configures and returns a fully initialized AWSClient
func (c *Config) Client() (interface{}, error) {
	// Get the auth and region. This can fail if keys/regions were not
	// specified and we're attempting to use the environment.
	var errs []error

	log.Println("[INFO] Building AWS region structure")
	err := c.ValidateRegion()
	if err != nil {
		errs = append(errs, err)
	}

	var client AWSClient
	if len(errs) == 0 {
		// store AWS region in client struct, for region specific operations such as
		// bucket storage in S3
		client.region = c.Region

		log.Println("[INFO] Building AWS auth structure")
		creds := GetCredentials(c)
		// Call Get to check for credential provider. If nothing found, we'll get an
		// error, and we can present it nicely to the user
		cp, err := creds.Get()
		if err != nil {
			if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoCredentialProviders" {
				errs = append(errs, fmt.Errorf(`No valid credential sources found for AWS Provider.
  Please see https://terraform.io/docs/providers/aws/index.html for more information on
  providing credentials for the AWS Provider`))
			} else {
				errs = append(errs, fmt.Errorf("Error loading credentials for AWS Provider: %s", err))
			}
			return nil, &multierror.Error{Errors: errs}
		}

		log.Printf("[INFO] AWS Auth provider used: %q", cp.ProviderName)

		awsConfig := &aws.Config{
			Credentials:      creds,
			Region:           aws.String(c.Region),
			MaxRetries:       aws.Int(c.MaxRetries),
			HTTPClient:       cleanhttp.DefaultClient(),
			S3ForcePathStyle: aws.Bool(c.S3ForcePathStyle),
		}

		if logging.IsDebugOrHigher() {
			awsConfig.LogLevel = aws.LogLevel(aws.LogDebugWithHTTPBody)
			awsConfig.Logger = awsLogger{}
		}

		if c.Insecure {
			transport := awsConfig.HTTPClient.Transport.(*http.Transport)
			transport.TLSClientConfig = &tls.Config{
				InsecureSkipVerify: true,
			}
		}

		// Set up base session
		sess, err := session.NewSession(awsConfig)
		if err != nil {
			return nil, errwrap.Wrapf("Error creating AWS session: %s", err)
		}
		sess.Handlers.Build.PushFrontNamed(addTerraformVersionToUserAgent)

		// Some services exist only in us-east-1, e.g. because they manage
		// resources that can span across multiple regions, or because
		// signature format v4 requires region to be us-east-1 for global
		// endpoints:
		// http://docs.aws.amazon.com/general/latest/gr/sigv4_changes.html
		usEast1Sess := sess.Copy(&aws.Config{Region: aws.String("us-east-1")})

		// Some services have user-configurable endpoints
		awsEc2Sess := sess.Copy(&aws.Config{Endpoint: aws.String(c.Ec2Endpoint)})
		awsElbSess := sess.Copy(&aws.Config{Endpoint: aws.String(c.ElbEndpoint)})
		awsIamSess := sess.Copy(&aws.Config{Endpoint: aws.String(c.IamEndpoint)})
		awsS3Sess := sess.Copy(&aws.Config{Endpoint: aws.String(c.S3Endpoint)})
		dynamoSess := sess.Copy(&aws.Config{Endpoint: aws.String(c.DynamoDBEndpoint)})
		kinesisSess := sess.Copy(&aws.Config{Endpoint: aws.String(c.KinesisEndpoint)})

		// These two services need to be set up early so we can check on AccountID
		client.iamconn = iam.New(awsIamSess)
		client.stsconn = sts.New(sess)

		if !c.SkipCredsValidation {
			err = c.ValidateCredentials(client.stsconn)
			if err != nil {
				errs = append(errs, err)
				return nil, &multierror.Error{Errors: errs}
			}
		}

		if !c.SkipRequestingAccountId {
			accountId, err := GetAccountId(client.iamconn, client.stsconn, cp.ProviderName)
			if err == nil {
				client.accountid = accountId
			}
		}

		authErr := c.ValidateAccountId(client.accountid)
		if authErr != nil {
			errs = append(errs, authErr)
		}

		client.apigateway = apigateway.New(sess)
		client.appautoscalingconn = applicationautoscaling.New(sess)
		client.autoscalingconn = autoscaling.New(sess)
		client.cfconn = cloudformation.New(sess)
		client.cloudfrontconn = cloudfront.New(sess)
		client.cloudtrailconn = cloudtrail.New(sess)
		client.cloudwatchconn = cloudwatch.New(sess)
		client.cloudwatcheventsconn = cloudwatchevents.New(sess)
		client.cloudwatchlogsconn = cloudwatchlogs.New(sess)
		client.codecommitconn = codecommit.New(usEast1Sess)
		client.codedeployconn = codedeploy.New(sess)
		client.dsconn = directoryservice.New(sess)
		client.dynamodbconn = dynamodb.New(dynamoSess)
		client.ec2conn = ec2.New(awsEc2Sess)
		client.ecrconn = ecr.New(sess)
		client.ecsconn = ecs.New(sess)
		client.efsconn = efs.New(sess)
		client.elasticacheconn = elasticache.New(sess)
		client.elasticbeanstalkconn = elasticbeanstalk.New(sess)
		client.elastictranscoderconn = elastictranscoder.New(sess)
		client.elbconn = elb.New(awsElbSess)
		client.elbv2conn = elbv2.New(awsElbSess)
		client.emrconn = emr.New(sess)
		client.esconn = elasticsearch.New(sess)
		client.firehoseconn = firehose.New(sess)
		client.glacierconn = glacier.New(sess)
		client.kinesisconn = kinesis.New(kinesisSess)
		client.kmsconn = kms.New(sess)
		client.lambdaconn = lambda.New(sess)
		client.opsworksconn = opsworks.New(usEast1Sess)
		client.r53conn = route53.New(usEast1Sess)
		client.rdsconn = rds.New(sess)
		client.redshiftconn = redshift.New(sess)
		client.simpledbconn = simpledb.New(sess)
		client.s3conn = s3.New(awsS3Sess)
		client.sesConn = ses.New(sess)
		client.snsconn = sns.New(sess)
		client.sqsconn = sqs.New(sess)
	}

	if len(errs) > 0 {
		return nil, &multierror.Error{Errors: errs}
	}

	return &client, nil
}

// ValidateRegion returns an error if the configured region is not a
// valid aws region and nil otherwise.
func (c *Config) ValidateRegion() error {
	var regions = [13]string{
		"ap-northeast-1",
		"ap-northeast-2",
		"ap-south-1",
		"ap-southeast-1",
		"ap-southeast-2",
		"cn-north-1",
		"eu-central-1",
		"eu-west-1",
		"sa-east-1",
		"us-east-1",
		"us-gov-west-1",
		"us-west-1",
		"us-west-2",
	}

	for _, valid := range regions {
		if c.Region == valid {
			return nil
		}
	}
	return fmt.Errorf("Not a valid region: %s", c.Region)
}

// Validate credentials early and fail before we do any graph walking.
func (c *Config) ValidateCredentials(stsconn *sts.STS) error {
	_, err := stsconn.GetCallerIdentity(&sts.GetCallerIdentityInput{})
	return err
}

// ValidateAccountId returns a context-specific error if the configured account
// id is explicitly forbidden or not authorised; and nil if it is authorised.
func (c *Config) ValidateAccountId(accountId string) error {
	if c.AllowedAccountIds == nil && c.ForbiddenAccountIds == nil {
		return nil
	}

	log.Printf("[INFO] Validating account ID")

	if c.ForbiddenAccountIds != nil {
		for _, id := range c.ForbiddenAccountIds {
			if id == accountId {
				return fmt.Errorf("Forbidden account ID (%s)", id)
			}
		}
	}

	if c.AllowedAccountIds != nil {
		for _, id := range c.AllowedAccountIds {
			if id == accountId {
				return nil
			}
		}
		return fmt.Errorf("Account ID not allowed (%s)", accountId)
	}

	return nil
}

// addTerraformVersionToUserAgent is a named handler that will add Terraform's
// version information to requests made by the AWS SDK.
var addTerraformVersionToUserAgent = request.NamedHandler{
	Name: "terraform.TerraformVersionUserAgentHandler",
	Fn: request.MakeAddToUserAgentHandler(
		"terraform", terraform.VersionString()),
}

type awsLogger struct{}

func (l awsLogger) Log(args ...interface{}) {
	tokens := make([]string, 0, len(args))
	for _, arg := range args {
		if token, ok := arg.(string); ok {
			tokens = append(tokens, token)
		}
	}
	log.Printf("[DEBUG] [aws-sdk-go] %s", strings.Join(tokens, " "))
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/BurntSushi/toml"

	"github.com/stripe/sequins/blocks"
)

const defaultSearchPath = "sequins.conf:/etc/sequins.conf"

var errNoConfig = errors.New("no config file found")

type sequinsConfig struct {
	Source             string   `toml:"source"`
	Bind               string   `toml:"bind"`
	MaxParallelLoads   int      `toml:"max_parallel_loads"`
	ThrottleLoads      duration `toml:"throttle_loads"`
	LocalStore         string   `toml:"local_store"`
	RefreshPeriod      duration `toml:"refresh_period"`
	RequireSuccessFile bool     `toml:"require_success_file"`
	ContentType        string   `toml:"content_type"`

	Storage  storageConfig  `toml:"storage"`
	S3       s3Config       `toml:"s3"`
	Sharding shardingConfig `toml:"sharding"`
	ZK       zkConfig       `toml:"zk"`
	Debug    debugConfig    `toml:"debug"`
	Test     testConfig     `toml:"test"`
}

type storageConfig struct {
	Compression blocks.Compression `toml:"compression"`
	BlockSize   int                `toml:"block_size"`
}

type s3Config struct {
	Region          string `toml:"region"`
	AccessKeyId     string `toml:"access_key_id"`
	SecretAccessKey string `toml:"secret_access_key"`
}

type shardingConfig struct {
	Enabled            bool     `toml:"enabled"`
	Replication        int      `toml:"replication"`
	TimeToConverge     duration `toml:"time_to_converge"`
	ProxyTimeout       duration `toml:"proxy_timeout"`
	ProxyStageTimeout  duration `toml:"proxy_stage_timeout"`
	ClusterName        string   `toml:"cluster_name"`
	AdvertisedHostname string   `toml:"advertised_hostname"`
	ShardID            string   `toml:"shard_id"`
}

type zkConfig struct {
	Servers        []string `toml:"servers"`
	ConnectTimeout duration `toml:"connect_timeout"`
	SessionTimeout duration `toml:"session_timeout"`
}

type debugConfig struct {
	Bind    string `toml:"bind"`
	Expvars bool   `toml:"expvars"`
	Pprof   bool   `toml:"pprof"`
}

// testConfig has some options used in functional tests to slow sequins down
// and make it more observable.
type testConfig struct {
	UpgradeDelay         duration `toml:"upgrade_delay"`
	AllowLocalCluster    bool     `toml:"allow_local_cluster"`
	VersionRemoveTimeout duration `toml:"version_remove_timeout"`
	S3                   s3Config `toml:"s3"`
}

func defaultConfig() sequinsConfig {
	return sequinsConfig{
		Source:             "",
		Bind:               "0.0.0.0:9599",
		LocalStore:         "/var/sequins/",
		MaxParallelLoads:   0,
		RefreshPeriod:      duration{time.Duration(0)},
		RequireSuccessFile: false,
		ContentType:        "",
		Storage: storageConfig{
			Compression: blocks.SnappyCompression,
			BlockSize:   4096,
		},
		S3: s3Config{
			Region:          "",
			AccessKeyId:     "",
			SecretAccessKey: "",
		},
		Sharding: shardingConfig{
			Enabled:            false,
			Replication:        2,
			TimeToConverge:     duration{10 * time.Second},
			ProxyTimeout:       duration{100 * time.Millisecond},
			ProxyStageTimeout:  duration{time.Duration(0)},
			ClusterName:        "sequins",
			AdvertisedHostname: "",
			ShardID:            "",
		},
		ZK: zkConfig{
			Servers:        []string{"localhost:2181"},
			ConnectTimeout: duration{1 * time.Second},
			SessionTimeout: duration{10 * time.Second},
		},
		Debug: debugConfig{
			Bind:    "",
			Expvars: true,
			Pprof:   false,
		},
		Test: testConfig{
			UpgradeDelay:         duration{time.Duration(0)},
			VersionRemoveTimeout: duration{time.Duration(0)},
			S3: s3Config{
				Region:          "",
				AccessKeyId:     "",
				SecretAccessKey: "",
			},
		},
	}
}

func loadConfig(searchPath string) (sequinsConfig, error) {
	if searchPath == "" {
		searchPath = defaultSearchPath
	}

	config := defaultConfig()
	paths := filepath.SplitList(searchPath)
	for _, path := range paths {
		md, err := toml.DecodeFile(path, &config)
		if os.IsNotExist(err) {
			continue
		} else if err != nil {
			return config, err
		} else if len(md.Undecoded()) > 0 {
			return config, fmt.Errorf("found unrecognized properties: %v", md.Undecoded())
		}

		return config, nil
	}

	return config, errNoConfig
}

func validateConfig(config sequinsConfig) (sequinsConfig, error) {
	if !filepath.IsAbs(config.LocalStore) {
		return config, fmt.Errorf("local store path must be absolute: %s", config.LocalStore)
	}

	if config.Source == "" {
		return config, errors.New("source must be set")
	}

	parsed, err := url.Parse(config.Source)
	if err != nil {
		return config, fmt.Errorf("parsing source: %s", err)
	}

	if parsed.Scheme == "" || parsed.Scheme == "file" {
		if parsed.Host != "" {
			return config, fmt.Errorf("local source path is invalid (likely missing a '/'): %s", config.Source)
		}

		if !filepath.IsAbs(parsed.Path) {
			return config, fmt.Errorf("local source path must be absolute: %s", config.Source)
		}

		if strings.HasPrefix(filepath.Clean(config.LocalStore), filepath.Clean(parsed.Path)) {
			return config, fmt.Errorf("local store can't be within source root: %s", config.LocalStore)
		}

		if config.Sharding.Enabled && !config.Test.AllowLocalCluster {
			return config, errors.New("you can't run sequins with sharding enabled on local paths")
		}
	}

	switch config.Storage.Compression {
	case blocks.SnappyCompression, blocks.NoCompression:
	default:
		return config, fmt.Errorf("lnrecognized compression option: %s", config.Storage.Compression)
	}

	if config.Sharding.Replication <= 0 {
		return config, fmt.Errorf("lnvalid replication factor: %d", config.Sharding.Replication)
	}

	return config, nil
}

type duration struct {
	time.Duration
}

func (d *duration) UnmarshalText(text []byte) error {
	var err error
	d.Duration, err = time.ParseDuration(string(text))
	return err
}

func (d duration) MarshalText() ([]byte, error) {
	return []byte(d.Duration.String()), nil
}
<commit_msg>Fix weird typos<commit_after>package main

import (
	"errors"
	"fmt"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/BurntSushi/toml"

	"github.com/stripe/sequins/blocks"
)

const defaultSearchPath = "sequins.conf:/etc/sequins.conf"

var errNoConfig = errors.New("no config file found")

type sequinsConfig struct {
	Source             string   `toml:"source"`
	Bind               string   `toml:"bind"`
	MaxParallelLoads   int      `toml:"max_parallel_loads"`
	ThrottleLoads      duration `toml:"throttle_loads"`
	LocalStore         string   `toml:"local_store"`
	RefreshPeriod      duration `toml:"refresh_period"`
	RequireSuccessFile bool     `toml:"require_success_file"`
	ContentType        string   `toml:"content_type"`

	Storage  storageConfig  `toml:"storage"`
	S3       s3Config       `toml:"s3"`
	Sharding shardingConfig `toml:"sharding"`
	ZK       zkConfig       `toml:"zk"`
	Debug    debugConfig    `toml:"debug"`
	Test     testConfig     `toml:"test"`
}

type storageConfig struct {
	Compression blocks.Compression `toml:"compression"`
	BlockSize   int                `toml:"block_size"`
}

type s3Config struct {
	Region          string `toml:"region"`
	AccessKeyId     string `toml:"access_key_id"`
	SecretAccessKey string `toml:"secret_access_key"`
}

type shardingConfig struct {
	Enabled            bool     `toml:"enabled"`
	Replication        int      `toml:"replication"`
	TimeToConverge     duration `toml:"time_to_converge"`
	ProxyTimeout       duration `toml:"proxy_timeout"`
	ProxyStageTimeout  duration `toml:"proxy_stage_timeout"`
	ClusterName        string   `toml:"cluster_name"`
	AdvertisedHostname string   `toml:"advertised_hostname"`
	ShardID            string   `toml:"shard_id"`
}

type zkConfig struct {
	Servers        []string `toml:"servers"`
	ConnectTimeout duration `toml:"connect_timeout"`
	SessionTimeout duration `toml:"session_timeout"`
}

type debugConfig struct {
	Bind    string `toml:"bind"`
	Expvars bool   `toml:"expvars"`
	Pprof   bool   `toml:"pprof"`
}

// testConfig has some options used in functional tests to slow sequins down
// and make it more observable.
type testConfig struct {
	UpgradeDelay         duration `toml:"upgrade_delay"`
	AllowLocalCluster    bool     `toml:"allow_local_cluster"`
	VersionRemoveTimeout duration `toml:"version_remove_timeout"`
	S3                   s3Config `toml:"s3"`
}

func defaultConfig() sequinsConfig {
	return sequinsConfig{
		Source:             "",
		Bind:               "0.0.0.0:9599",
		LocalStore:         "/var/sequins/",
		MaxParallelLoads:   0,
		RefreshPeriod:      duration{time.Duration(0)},
		RequireSuccessFile: false,
		ContentType:        "",
		Storage: storageConfig{
			Compression: blocks.SnappyCompression,
			BlockSize:   4096,
		},
		S3: s3Config{
			Region:          "",
			AccessKeyId:     "",
			SecretAccessKey: "",
		},
		Sharding: shardingConfig{
			Enabled:            false,
			Replication:        2,
			TimeToConverge:     duration{10 * time.Second},
			ProxyTimeout:       duration{100 * time.Millisecond},
			ProxyStageTimeout:  duration{time.Duration(0)},
			ClusterName:        "sequins",
			AdvertisedHostname: "",
			ShardID:            "",
		},
		ZK: zkConfig{
			Servers:        []string{"localhost:2181"},
			ConnectTimeout: duration{1 * time.Second},
			SessionTimeout: duration{10 * time.Second},
		},
		Debug: debugConfig{
			Bind:    "",
			Expvars: true,
			Pprof:   false,
		},
		Test: testConfig{
			UpgradeDelay:         duration{time.Duration(0)},
			VersionRemoveTimeout: duration{time.Duration(0)},
			S3: s3Config{
				Region:          "",
				AccessKeyId:     "",
				SecretAccessKey: "",
			},
		},
	}
}

func loadConfig(searchPath string) (sequinsConfig, error) {
	if searchPath == "" {
		searchPath = defaultSearchPath
	}

	config := defaultConfig()
	paths := filepath.SplitList(searchPath)
	for _, path := range paths {
		md, err := toml.DecodeFile(path, &config)
		if os.IsNotExist(err) {
			continue
		} else if err != nil {
			return config, err
		} else if len(md.Undecoded()) > 0 {
			return config, fmt.Errorf("found unrecognized properties: %v", md.Undecoded())
		}

		return config, nil
	}

	return config, errNoConfig
}

func validateConfig(config sequinsConfig) (sequinsConfig, error) {
	if !filepath.IsAbs(config.LocalStore) {
		return config, fmt.Errorf("local store path must be absolute: %s", config.LocalStore)
	}

	if config.Source == "" {
		return config, errors.New("source must be set")
	}

	parsed, err := url.Parse(config.Source)
	if err != nil {
		return config, fmt.Errorf("parsing source: %s", err)
	}

	if parsed.Scheme == "" || parsed.Scheme == "file" {
		if parsed.Host != "" {
			return config, fmt.Errorf("local source path is invalid (likely missing a '/'): %s", config.Source)
		}

		if !filepath.IsAbs(parsed.Path) {
			return config, fmt.Errorf("local source path must be absolute: %s", config.Source)
		}

		if strings.HasPrefix(filepath.Clean(config.LocalStore), filepath.Clean(parsed.Path)) {
			return config, fmt.Errorf("local store can't be within source root: %s", config.LocalStore)
		}

		if config.Sharding.Enabled && !config.Test.AllowLocalCluster {
			return config, errors.New("you can't run sequins with sharding enabled on local paths")
		}
	}

	switch config.Storage.Compression {
	case blocks.SnappyCompression, blocks.NoCompression:
	default:
		return config, fmt.Errorf("unrecognized compression option: %s", config.Storage.Compression)
	}

	if config.Sharding.Replication <= 0 {
		return config, fmt.Errorf("invalid replication factor: %d", config.Sharding.Replication)
	}

	return config, nil
}

type duration struct {
	time.Duration
}

func (d *duration) UnmarshalText(text []byte) error {
	var err error
	d.Duration, err = time.ParseDuration(string(text))
	return err
}

func (d duration) MarshalText() ([]byte, error) {
	return []byte(d.Duration.String()), nil
}
<|endoftext|>


<commit_before>package torrent

import (
	"github.com/anacrolix/torrent/dht"
)

// Override Client defaults.
type Config struct {
	// Store torrent file data in this directory unless TorrentDataOpener is
	// specified.
	DataDir string `long:"data-dir" description:"directory to store downloaded torrent data"`
	// The address to listen for new uTP and TCP bittorrent protocol
	// connections. DHT shares a UDP socket with uTP unless configured
	// otherwise.
	ListenAddr string `long:"listen-addr" value-name:"HOST:PORT"`
	// Don't announce to trackers. This only leaves DHT to discover peers.
	DisableTrackers bool `long:"disable-trackers"`
	DisablePEX      bool `long:"disable-pex"`
	// Don't create a DHT.
	NoDHT bool `long:"disable-dht"`
	// Overrides the default DHT configuration.
	DHTConfig *dht.ServerConfig
	// Don't send chunks to peers.
	NoUpload bool `long:"no-upload"`
	// User-provided Client peer ID. If not present, one is generated automatically.
	PeerID string
	// For the bittorrent protocol.
	DisableUTP bool
	// For the bittorrent protocol.
	DisableTCP bool
	// Don't automatically load "$ConfigDir/blocklist".
	NoDefaultBlocklist bool
	// Defaults to "$HOME/.config/torrent". This is where "blocklist",
	// "torrents" and other operational files are stored.
	ConfigDir string
	// Don't save or load to a cache of torrent files stored in
	// "$ConfigDir/torrents".
	DisableMetainfoCache bool
	// Called to instantiate storage for each added torrent. Provided backends
	// are in $REPO/data. If not set, the "file" implementation is used.
	TorrentDataOpener
	DisableEncryption bool `long:"disable-encryption"`
}
<commit_msg>Add the --disable-tcp flag to the client options<commit_after>package torrent

import (
	"github.com/anacrolix/torrent/dht"
)

// Override Client defaults.
type Config struct {
	// Store torrent file data in this directory unless TorrentDataOpener is
	// specified.
	DataDir string `long:"data-dir" description:"directory to store downloaded torrent data"`
	// The address to listen for new uTP and TCP bittorrent protocol
	// connections. DHT shares a UDP socket with uTP unless configured
	// otherwise.
	ListenAddr string `long:"listen-addr" value-name:"HOST:PORT"`
	// Don't announce to trackers. This only leaves DHT to discover peers.
	DisableTrackers bool `long:"disable-trackers"`
	DisablePEX      bool `long:"disable-pex"`
	// Don't create a DHT.
	NoDHT bool `long:"disable-dht"`
	// Overrides the default DHT configuration.
	DHTConfig *dht.ServerConfig
	// Don't send chunks to peers.
	NoUpload bool `long:"no-upload"`
	// User-provided Client peer ID. If not present, one is generated automatically.
	PeerID string
	// For the bittorrent protocol.
	DisableUTP bool
	// For the bittorrent protocol.
	DisableTCP bool `long:"disable-tcp"`
	// Don't automatically load "$ConfigDir/blocklist".
	NoDefaultBlocklist bool
	// Defaults to "$HOME/.config/torrent". This is where "blocklist",
	// "torrents" and other operational files are stored.
	ConfigDir string
	// Don't save or load to a cache of torrent files stored in
	// "$ConfigDir/torrents".
	DisableMetainfoCache bool
	// Called to instantiate storage for each added torrent. Provided backends
	// are in $REPO/data. If not set, the "file" implementation is used.
	TorrentDataOpener
	DisableEncryption bool `long:"disable-encryption"`
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"io/ioutil"
	"os"
	"path/filepath"

	"gopkg.in/yaml.v2"
)

type dfoConfig struct {
	RepoDir   string
	HomeDir   string
	WorkDir   string
	GitRepo   string
	Noop      bool
	Verbose   bool
	Backup    bool
	UpdateGit bool
}

func (c *dfoConfig) loadConfig() error {
	homeDir := os.Getenv("HOME")

	configLocation := filepath.Join(homeDir, ".dfo/config.yaml")
	configBytes, err := ioutil.ReadFile(configLocation)
	if err != nil {
		// Not required to have a config.yaml
		if os.IsNotExist(err) {
			return nil
		}
		return err
	}

	err = yaml.Unmarshal(configBytes, c)
	return err
}

func (c *dfoConfig) setDefaults() {
	c.HomeDir = os.Getenv("HOME")
	c.Backup = true
	c.WorkDir = filepath.Join(c.HomeDir, ".dfo")
	c.RepoDir = filepath.Join(c.WorkDir, "dotfiles")
	c.UpdateGit = true
}

func (c *dfoConfig) initFromParams() {

	flag.StringVar(&c.WorkDir, "workdir", c.WorkDir, "Work directory for dfo (will be used to store backups and dotfiles git repo)")
	flag.StringVar(&c.GitRepo, "gitrepo", c.GitRepo, "Remote git repo that holds your dotfiles (in the same format git would take it)")
	flag.BoolVar(&c.Noop, "noop", c.Noop, "Run in noop mode (just do a dry-run)")
	flag.BoolVar(&c.Verbose, "verbose", c.Verbose, "Verbose output")
	flag.BoolVar(&c.Backup, "backup", c.Backup, "Perform backups of files that are updated")
	flag.BoolVar(&c.UpdateGit, "updategit", c.UpdateGit, "Do a 'git pull' and update submodules of the git repo")

	flag.Parse()
}
<commit_msg>Remove hardcoded config location<commit_after>package main

import (
	"flag"
	"io/ioutil"
	"os"
	"path/filepath"

	"gopkg.in/yaml.v2"
)

type dfoConfig struct {
	RepoDir   string // Directory where to store dotfiles repo
	HomeDir   string // User's home directory. Relative target paths will be relative to this
	WorkDir   string // dfo's work directory (~/.dfo)
	GitRepo   string // Git repository that stores user's dotfiles
	Noop      bool   // Run dfo in noop mode
	Verbose   bool   // Run dfo in verbose mode
	Backup    bool   // Make backups of files before replacing them
	UpdateGit bool   // Update dotfiles repo from origin before applying any changes
}

func (c *dfoConfig) loadConfig() error {
	configLocation := filepath.Join(c.WorkDir, "config.yaml")
	configBytes, err := ioutil.ReadFile(configLocation)
	if err != nil {
		// Not required to have a config.yaml
		if os.IsNotExist(err) {
			return nil
		}
		return err
	}

	err = yaml.Unmarshal(configBytes, c)
	return err
}

func (c *dfoConfig) setDefaults() {
	c.HomeDir = os.Getenv("HOME")
	c.Backup = true
	c.WorkDir = filepath.Join(c.HomeDir, ".dfo")
	c.RepoDir = filepath.Join(c.WorkDir, "dotfiles")
	c.UpdateGit = true
}

func (c *dfoConfig) initFromParams() {

	flag.StringVar(&c.WorkDir, "workdir", c.WorkDir, "Work directory for dfo (will be used to store backups and dotfiles git repo)")
	flag.StringVar(&c.GitRepo, "gitrepo", c.GitRepo, "Remote git repo that holds your dotfiles (in the same format git would take it)")
	flag.BoolVar(&c.Noop, "noop", c.Noop, "Run in noop mode (just do a dry-run)")
	flag.BoolVar(&c.Verbose, "verbose", c.Verbose, "Verbose output")
	flag.BoolVar(&c.Backup, "backup", c.Backup, "Perform backups of files that are updated")
	flag.BoolVar(&c.UpdateGit, "updategit", c.UpdateGit, "Do a 'git pull' and update submodules of the git repo")

	flag.Parse()
}
<|endoftext|>


<commit_before>// Copyright 2016 Afshin Darian. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package forest

import (
	"encoding/json"
	"io/ioutil"

	"github.com/ursiform/logger"
)

const ConfigFile = "bear.json"

type ServiceConfig struct {
	Address      string `json:"address,omitempty"`
	LogLevelName string `json:"loglevel,omitempty"`
	LogRequests  bool   `json:"logrequests,omitempty"`
	Name         string `json:"name,omitempty"`
	Version      string `json:"version,omitempty"`
}

type AppConfig struct {
	CookiePath   string
	File         string
	LogLevel     int
	PoweredBy    string
	Debug        bool           `json:"debug,omitempty"`
	LogLevelName string         `json:"loglevel,omitempty"`
	Service      *ServiceConfig `json:"service,omitempty"`
}

func loadConfig(app *App) error {
	data, err := ioutil.ReadFile(app.Config.File)
	if err == nil {
		err = json.Unmarshal(data, app.Config)
	}
	if app.Config.Service == nil {
		app.Config.Service = &ServiceConfig{}
	}
	if len(app.Config.LogLevelName) == 0 {
		app.Config.LogLevelName = "listen"
	}
	println("loglevel=" + app.Config.LogLevelName)
	level, ok := logger.LogLevel[app.Config.LogLevelName]
	if !ok {
		app.Config.LogLevelName = "debug"
		app.Config.LogLevel = logger.Debug
		logger.MustError("loglevel=\"%s\" in %s is invalid; using \"%s\"",
			app.Config.LogLevelName, app.Config.File, "debug")
	} else {
		app.Config.LogLevel = level
	}
	return err
}
<commit_msg>remove debug statement<commit_after>// Copyright 2016 Afshin Darian. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package forest

import (
	"encoding/json"
	"io/ioutil"

	"github.com/ursiform/logger"
)

const ConfigFile = "bear.json"

type ServiceConfig struct {
	Address      string `json:"address,omitempty"`
	LogLevelName string `json:"loglevel,omitempty"`
	LogRequests  bool   `json:"logrequests,omitempty"`
	Name         string `json:"name,omitempty"`
	Version      string `json:"version,omitempty"`
}

type AppConfig struct {
	CookiePath   string
	File         string
	LogLevel     int
	PoweredBy    string
	Debug        bool           `json:"debug,omitempty"`
	LogLevelName string         `json:"loglevel,omitempty"`
	Service      *ServiceConfig `json:"service,omitempty"`
}

func loadConfig(app *App) error {
	data, err := ioutil.ReadFile(app.Config.File)
	if err == nil {
		err = json.Unmarshal(data, app.Config)
	}
	if app.Config.Service == nil {
		app.Config.Service = &ServiceConfig{}
	}
	if len(app.Config.LogLevelName) == 0 {
		app.Config.LogLevelName = "listen"
	}
	level, ok := logger.LogLevel[app.Config.LogLevelName]
	if !ok {
		app.Config.LogLevelName = "debug"
		app.Config.LogLevel = logger.Debug
		logger.MustError("loglevel=\"%s\" in %s is invalid; using \"%s\"",
			app.Config.LogLevelName, app.Config.File, "debug")
	} else {
		app.Config.LogLevel = level
	}
	return err
}
<|endoftext|>


<commit_before>package goConfig

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"strconv"
	"strings"

	"github.com/pkg/errors"
)

// Settings default
type Settings struct {
	// Path sets default config path
	Path string
	// File name of default config file
	File string
	// Tag set the main tag
	Tag string
	// TagDefault set tag default
	TagDefault string
	// EnviromentVarSeparator separe names on enviroment variables
	EnviromentVarSeparator string
}

// Setup Pointer to internal variables
var Setup *Settings

func init() {
	Setup = &Settings{
		Path:                   "./",
		File:                   "config.json",
		Tag:                    "cfg",
		TagDefault:             "cfgDefault",
		EnviromentVarSeparator: "_",
	}
}

// LoadJSON config file
func LoadJSON(config interface{}) (err error) {
	configFile := Setup.Path + Setup.File
	file, err := os.Open(configFile)
	if err != nil {
		return
	}
	defer file.Close()

	decoder := json.NewDecoder(file)
	err = decoder.Decode(&config)
	if err != nil {
		return
	}

	return
}

// Load config file
func Load(config interface{}) (err error) {

	err = LoadJSON(config)
	if err != nil {
		return
	}

	err = parseTags(config, "")
	if err != nil {
		return
	}

	return
}

// Save config file
func Save(config interface{}) (err error) {
	_, err = os.Stat(Setup.Path)
	if os.IsNotExist(err) {
		os.Mkdir(Setup.Path, 0700)
	} else if err != nil {
		return
	}

	configFile := Setup.Path + Setup.File

	_, err = os.Stat(configFile)
	if err != nil {
		return
	}

	b, err := json.MarshalIndent(config, "", "\t")
	if err != nil {
		return
	}

	err = ioutil.WriteFile(configFile, b, 0644)
	if err != nil {
		return
	}
	return
}

// Getenv get enviroment variable
func Getenv(env string) (r string) {
	r = os.Getenv(env)
	return
}

func parseTags(s interface{}, superTag string) (err error) {

	st := reflect.TypeOf(s)
	vt := reflect.ValueOf(s)

	if st.Kind() != reflect.Ptr {
		err = errors.New("Not a pointer")
		return
	}

	refField := st.Elem()
	if refField.Kind() != reflect.Struct {
		err = errors.New("Not a struct")
		return
	}

	refValue := vt.Elem()
	for i := 0; i < refField.NumField(); i++ {
		field := refField.Field(i)
		value := refValue.Field(i)
		kind := field.Type.Kind()

		if field.PkgPath != "" {
			continue
		}

		env := ""
		t := field.Tag.Get(Setup.Tag)
		if t == "-" {
			continue
		}

		if t == "" {
			t = strings.ToUpper(field.Name)
		}

		if superTag != "" {
			t = superTag + Setup.EnviromentVarSeparator + t
		}
		fmt.Println("t:", t)

		env = os.Getenv(t)

		if env == "" && kind != reflect.Struct {
			continue
		}

		switch kind {
		case reflect.Struct:
			err = parseTags(value.Addr().Interface(), t)
			if err != nil {
				return
			}
		case reflect.String:
			//value.SetString("TEST")
			value.SetString(env)
		case reflect.Int:
			//value.SetInt(999)
			var intEnv int64
			intEnv, err = strconv.ParseInt(env, 10, 64)
			if err != nil {
				return
			}
			value.SetInt(intEnv)
		default:
			err = errors.New("Type not supported " + kind.String())
		}

		fmt.Println("name:", field.Name,
			"| cfg:", field.Tag.Get(Setup.Tag),
			"| cfgDefault:", field.Tag.Get(Setup.TagDefault),
			"| type:", field.Type)

	}
	return
}
<commit_msg>reduce cyclomatic complexity<commit_after>package goConfig

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"strconv"
	"strings"

	"github.com/pkg/errors"
)

// Settings default
type Settings struct {
	// Path sets default config path
	Path string
	// File name of default config file
	File string
	// Tag set the main tag
	Tag string
	// TagDefault set tag default
	TagDefault string
	// TagDisabled used to not process an input
	TagDisabled string
	// EnviromentVarSeparator separe names on enviroment variables
	EnviromentVarSeparator string
}

// Setup Pointer to internal variables
var Setup *Settings

func init() {
	Setup = &Settings{
		Path:                   "./",
		File:                   "config.json",
		Tag:                    "cfg",
		TagDefault:             "cfgDefault",
		TagDisabled:            "-",
		EnviromentVarSeparator: "_",
	}
}

// LoadJSON config file
func LoadJSON(config interface{}) (err error) {
	configFile := Setup.Path + Setup.File
	file, err := os.Open(configFile)
	if err != nil {
		return
	}
	defer file.Close()

	decoder := json.NewDecoder(file)
	err = decoder.Decode(&config)
	if err != nil {
		return
	}

	return
}

// Load config file
func Load(config interface{}) (err error) {

	err = LoadJSON(config)
	if err != nil {
		return
	}

	err = parseTags(config, "")
	if err != nil {
		return
	}

	return
}

// Save config file
func Save(config interface{}) (err error) {
	_, err = os.Stat(Setup.Path)
	if os.IsNotExist(err) {
		os.Mkdir(Setup.Path, 0700)
	} else if err != nil {
		return
	}

	configFile := Setup.Path + Setup.File

	_, err = os.Stat(configFile)
	if err != nil {
		return
	}

	b, err := json.MarshalIndent(config, "", "\t")
	if err != nil {
		return
	}

	err = ioutil.WriteFile(configFile, b, 0644)
	if err != nil {
		return
	}
	return
}

// Getenv get enviroment variable
func Getenv(env string) (r string) {
	r = os.Getenv(env)
	return
}

func parseTags(s interface{}, superTag string) (err error) {

	st := reflect.TypeOf(s)

	if st.Kind() != reflect.Ptr {
		err = errors.New("Not a pointer")
		return
	}

	refField := st.Elem()
	if refField.Kind() != reflect.Struct {
		err = errors.New("Not a struct")
		return
	}

	//vt := reflect.ValueOf(s)
	refValue := reflect.ValueOf(s).Elem()
	for i := 0; i < refField.NumField(); i++ {
		field := refField.Field(i)
		value := refValue.Field(i)
		kind := field.Type.Kind()

		if field.PkgPath != "" {
			continue
		}

		t := field.Tag.Get(Setup.Tag)
		if t == Setup.TagDisabled {
			continue
		}

		if t == "" {
			t = strings.ToUpper(field.Name)
		}

		if superTag != "" {
			t = superTag + Setup.EnviromentVarSeparator + t
		}

		env := os.Getenv(t)

		if env == "" && kind != reflect.Struct {
			continue
		}

		switch kind {
		case reflect.Struct:
			err = parseTags(value.Addr().Interface(), t)
			if err != nil {
				return
			}
		case reflect.String:
			//value.SetString("TEST")
			value.SetString(env)
		case reflect.Int:
			//value.SetInt(999)
			var intEnv int64
			intEnv, err = strconv.ParseInt(env, 10, 64)
			if err != nil {
				return
			}
			value.SetInt(intEnv)
		default:
			err = errors.New("Type not supported " + kind.String())
		}

		fmt.Println("name:", field.Name,
			"| cfg:", field.Tag.Get(Setup.Tag),
			"| cfgDefault:", field.Tag.Get(Setup.TagDefault),
			"| type:", field.Type)

	}
	return
}
<|endoftext|>


<commit_before>package pop

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"text/template"

	"github.com/pkg/errors"

	"github.com/markbates/going/defaults"
	"gopkg.in/yaml.v2"
)

var lookupPaths = []string{"", "./config", "/config", "../", "../config", "../..", "../../config"}

// ConfigName is the name of the YAML databases config file
var ConfigName = "database.yml"

func init() {
	ap := os.Getenv("APP_PATH")
	if ap != "" {
		AddLookupPaths(ap)
	}
	ap = os.Getenv("POP_PATH")
	if ap != "" {
		AddLookupPaths(ap)
	}
	LoadConfigFile()
}

// LoadConfigFile loads a POP config file from the configured lookup paths
func LoadConfigFile() error {
	path, err := findConfigPath()
	if err != nil {
		return errors.WithStack(err)
	}
	Connections = map[string]*Connection{}
	if Debug {
		fmt.Printf("[POP]: Loading config file from %s\n", path)
	}
	f, err := os.Open(path)
	if err != nil {
		return errors.WithStack(err)
	}
	return LoadFrom(f)
}

// LookupPaths returns the current configuration lookup paths
func LookupPaths() []string {
	return lookupPaths
}

// AddLookupPaths add paths to the current lookup paths list
func AddLookupPaths(paths ...string) error {
	lookupPaths = append(paths, lookupPaths...)
	return LoadConfigFile()
}

func findConfigPath() (string, error) {
	for _, p := range LookupPaths() {
		path, _ := filepath.Abs(filepath.Join(p, ConfigName))
		if _, err := os.Stat(path); err == nil {
			return path, err
		}
	}
	return "", errors.New("[POP]: Tried to load configuration file, but couldn't find it")
}

// LoadFrom reads a configuration from the reader and sets up the connections
func LoadFrom(r io.Reader) error {
	tmpl := template.New("test")
	tmpl.Funcs(map[string]interface{}{
		"envOr": func(s1, s2 string) string {
			return defaults.String(os.Getenv(s1), s2)
		},
		"env": func(s1 string) string {
			return os.Getenv(s1)
		},
	})
	b, err := ioutil.ReadAll(r)
	if err != nil {
		return errors.WithStack(err)
	}
	t, err := tmpl.Parse(string(b))
	if err != nil {
		return errors.Wrap(err, "couldn't parse config template")
	}

	var bb bytes.Buffer
	err = t.Execute(&bb, nil)
	if err != nil {
		return errors.Wrap(err, "couldn't execute config template")
	}

	deets := map[string]*ConnectionDetails{}
	err = yaml.Unmarshal(bb.Bytes(), &deets)
	if err != nil {
		return errors.Wrap(err, "couldn't unmarshal config to yaml")
	}
	for n, d := range deets {
		con, err := NewConnection(d)
		if err != nil {
			return err
		}
		Connections[n] = con
	}
	return nil
}
<commit_msg>fixed some logging<commit_after>package pop

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"text/template"

	"github.com/pkg/errors"

	"github.com/markbates/going/defaults"
	"gopkg.in/yaml.v2"
)

var lookupPaths = []string{"", "./config", "/config", "../", "../config", "../..", "../../config"}

// ConfigName is the name of the YAML databases config file
var ConfigName = "database.yml"

func init() {
	ap := os.Getenv("APP_PATH")
	if ap != "" {
		AddLookupPaths(ap)
	}
	ap = os.Getenv("POP_PATH")
	if ap != "" {
		AddLookupPaths(ap)
	}
	LoadConfigFile()
}

// LoadConfigFile loads a POP config file from the configured lookup paths
func LoadConfigFile() error {
	path, err := findConfigPath()
	if err != nil {
		return errors.WithStack(err)
	}
	Connections = map[string]*Connection{}
	Log("Loading config file from %s\n", path)
	f, err := os.Open(path)
	if err != nil {
		return errors.WithStack(err)
	}
	return LoadFrom(f)
}

// LookupPaths returns the current configuration lookup paths
func LookupPaths() []string {
	return lookupPaths
}

// AddLookupPaths add paths to the current lookup paths list
func AddLookupPaths(paths ...string) error {
	lookupPaths = append(paths, lookupPaths...)
	return LoadConfigFile()
}

func findConfigPath() (string, error) {
	for _, p := range LookupPaths() {
		path, _ := filepath.Abs(filepath.Join(p, ConfigName))
		if _, err := os.Stat(path); err == nil {
			return path, err
		}
	}
	return "", errors.New("tried to load pop configuration file, but couldn't find it")
}

// LoadFrom reads a configuration from the reader and sets up the connections
func LoadFrom(r io.Reader) error {
	tmpl := template.New("test")
	tmpl.Funcs(map[string]interface{}{
		"envOr": func(s1, s2 string) string {
			return defaults.String(os.Getenv(s1), s2)
		},
		"env": func(s1 string) string {
			return os.Getenv(s1)
		},
	})
	b, err := ioutil.ReadAll(r)
	if err != nil {
		return errors.WithStack(err)
	}
	t, err := tmpl.Parse(string(b))
	if err != nil {
		return errors.Wrap(err, "couldn't parse config template")
	}

	var bb bytes.Buffer
	err = t.Execute(&bb, nil)
	if err != nil {
		return errors.Wrap(err, "couldn't execute config template")
	}

	deets := map[string]*ConnectionDetails{}
	err = yaml.Unmarshal(bb.Bytes(), &deets)
	if err != nil {
		return errors.Wrap(err, "couldn't unmarshal config to yaml")
	}
	for n, d := range deets {
		con, err := NewConnection(d)
		if err != nil {
			return err
		}
		Connections[n] = con
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/gcfg"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
)

type Configuration struct {
	ImageName                   string
	EnableUserImageName         bool
	MountHomeTo                 string
	EnableUserMountHomeTo       bool
	ContainerUsername           string
	EnableUserContainerUsername bool
	Shell                       string
	EnableUserShell             bool
	EnableUserConfig            bool
	MountHome                   bool
	EnableUserMountHome 	    bool
	MountTmp                    bool
	EnableUserMountTmp	    bool
	MountDockerSocket           bool
	EnableUserMountDockerSocket bool
	DockerSocket                string
	EnableUserDockerSocket	    bool
	Entrypoint                  string
	EnableUserEntrypoint        bool
}

func (c Configuration) Dump() string {
	return fmt.Sprintf("ImageName %s MountHomeTo %s ContainerUsername %s Shell %s DockerSocket %s", c.ImageName, c.MountHomeTo, c.ContainerUsername, c.Shell, c.DockerSocket)
}

type configInterpolation struct {
	Home string
	User string
}

var defaultConfig = Configuration{
	ImageName:           "busybox",
	MountHomeTo:         "%h",
	ContainerUsername:   "%u",
	Shell:               "/bin/ash",
	DockerSocket:        "/var/run/docker.sock",
	Entrypoint:	     "internal",
}

func loadAllConfig(user string, homedir string) (config Configuration, err error) {
	globalconfig, err := loadConfig(loadableFile("/etc/dockersh"), user)
	if err != nil {
		fmt.Fprintf(os.Stderr, "could not load config: %v", err)
		return config, errors.New("could not load config")
	}
	if globalconfig.EnableUserConfig == true {
		localconfig, err := loadConfig(loadableFile(fmt.Sprintf("%s/.dockersh", homedir)), user)
		if err != nil {
			fmt.Fprintf(os.Stderr, "could not load config: %v", err)
			return config, errors.New("could not load config")
		}
		return mergeConfigs(mergeConfigs(defaultConfig, globalconfig, false), localconfig, true), nil
	} else {
		return mergeConfigs(defaultConfig, globalconfig, false), nil
	}

}

type loadableFile string

func (fn loadableFile) Getcontents() []byte {
	localConfigFile, err := os.Open(string(fn))
	if err != nil {
	}
	b, err := ioutil.ReadAll(localConfigFile)
	localConfigFile.Close()
	return b
}

func loadConfig(filename loadableFile, user string) (config Configuration, err error) {
	bytes := filename.Getcontents()
	if err != nil {
		return
	}
	return (loadConfigFromString(bytes, user))
}

func mergeConfigs(old Configuration, new Configuration, blacklist bool) (ret Configuration) {
	var m = make(map[string]bool)
	if (!blacklist || old.EnableUserShell) && new.Shell != "" {
		old.Shell = new.Shell
	}
	if (!blacklist || old.EnableUserContainerUsername) && new.ContainerUsername != "" {
		old.ContainerUsername = new.ContainerUsername
	}
	if (!blacklist || old.EnableUserImageName) && new.ImageName != "" {
		old.ImageName = new.ImageName
	}
	if (!blacklist || old.EnableUserMountHomeTo) && new.MountHomeTo != "" {
		old.MountHomeTo = new.MountHomeTo
	}
	if (!blacklist || old.EnableUserDockerSocket) && new.DockerSocket != "" {
		old.DockerSocket = new.DockerSocket
	}
	if (!blacklist || old.EnableUserMountHome) && new.MountHome == true {
		old.MountHome = true
	}
	if (!blacklist || old.EnableUserMountTmp) && new.MountTmp == true {
		old.MountTmp = true
	}
	if (!blacklist || old.EnableUserMountDockerSocket) && new.MountDockerSocket == true {
		old.MountDockerSocket = true
	}
	if (!blacklist || old.EnableUserEntrypoint) && new.Entrypoint != "" {
		old.Entrypoint = new.Entrypoint
	}
        if !blacklist && new.EnableUserConfig == true {
		old.EnableUserConfig = true
	}
	return old
}

func loadConfigFromString(bytes []byte, user string) (config Configuration, err error) {
	inicfg := struct {
		Dockersh Configuration
		User     map[string]*Configuration
	}{}
	err = gcfg.ReadStringInto(&inicfg, string(bytes))
	if err != nil {
		return
	}
	if inicfg.User[user] == nil {
		return inicfg.Dockersh, nil
	}
	return mergeConfigs(inicfg.Dockersh, *inicfg.User[user], false), nil
}
<commit_msg>Remove now unused variable<commit_after>package main

import (
	"code.google.com/p/gcfg"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
)

type Configuration struct {
	ImageName                   string
	EnableUserImageName         bool
	MountHomeTo                 string
	EnableUserMountHomeTo       bool
	ContainerUsername           string
	EnableUserContainerUsername bool
	Shell                       string
	EnableUserShell             bool
	EnableUserConfig            bool
	MountHome                   bool
	EnableUserMountHome 	    bool
	MountTmp                    bool
	EnableUserMountTmp	    bool
	MountDockerSocket           bool
	EnableUserMountDockerSocket bool
	DockerSocket                string
	EnableUserDockerSocket	    bool
	Entrypoint                  string
	EnableUserEntrypoint        bool
}

func (c Configuration) Dump() string {
	return fmt.Sprintf("ImageName %s MountHomeTo %s ContainerUsername %s Shell %s DockerSocket %s", c.ImageName, c.MountHomeTo, c.ContainerUsername, c.Shell, c.DockerSocket)
}

type configInterpolation struct {
	Home string
	User string
}

var defaultConfig = Configuration{
	ImageName:           "busybox",
	MountHomeTo:         "%h",
	ContainerUsername:   "%u",
	Shell:               "/bin/ash",
	DockerSocket:        "/var/run/docker.sock",
	Entrypoint:	     "internal",
}

func loadAllConfig(user string, homedir string) (config Configuration, err error) {
	globalconfig, err := loadConfig(loadableFile("/etc/dockersh"), user)
	if err != nil {
		fmt.Fprintf(os.Stderr, "could not load config: %v", err)
		return config, errors.New("could not load config")
	}
	if globalconfig.EnableUserConfig == true {
		localconfig, err := loadConfig(loadableFile(fmt.Sprintf("%s/.dockersh", homedir)), user)
		if err != nil {
			fmt.Fprintf(os.Stderr, "could not load config: %v", err)
			return config, errors.New("could not load config")
		}
		return mergeConfigs(mergeConfigs(defaultConfig, globalconfig, false), localconfig, true), nil
	} else {
		return mergeConfigs(defaultConfig, globalconfig, false), nil
	}

}

type loadableFile string

func (fn loadableFile) Getcontents() []byte {
	localConfigFile, err := os.Open(string(fn))
	if err != nil {
	}
	b, err := ioutil.ReadAll(localConfigFile)
	localConfigFile.Close()
	return b
}

func loadConfig(filename loadableFile, user string) (config Configuration, err error) {
	bytes := filename.Getcontents()
	if err != nil {
		return
	}
	return (loadConfigFromString(bytes, user))
}

func mergeConfigs(old Configuration, new Configuration, blacklist bool) (ret Configuration) {
	if (!blacklist || old.EnableUserShell) && new.Shell != "" {
		old.Shell = new.Shell
	}
	if (!blacklist || old.EnableUserContainerUsername) && new.ContainerUsername != "" {
		old.ContainerUsername = new.ContainerUsername
	}
	if (!blacklist || old.EnableUserImageName) && new.ImageName != "" {
		old.ImageName = new.ImageName
	}
	if (!blacklist || old.EnableUserMountHomeTo) && new.MountHomeTo != "" {
		old.MountHomeTo = new.MountHomeTo
	}
	if (!blacklist || old.EnableUserDockerSocket) && new.DockerSocket != "" {
		old.DockerSocket = new.DockerSocket
	}
	if (!blacklist || old.EnableUserMountHome) && new.MountHome == true {
		old.MountHome = true
	}
	if (!blacklist || old.EnableUserMountTmp) && new.MountTmp == true {
		old.MountTmp = true
	}
	if (!blacklist || old.EnableUserMountDockerSocket) && new.MountDockerSocket == true {
		old.MountDockerSocket = true
	}
	if (!blacklist || old.EnableUserEntrypoint) && new.Entrypoint != "" {
		old.Entrypoint = new.Entrypoint
	}
        if !blacklist && new.EnableUserConfig == true {
		old.EnableUserConfig = true
	}
	return old
}

func loadConfigFromString(bytes []byte, user string) (config Configuration, err error) {
	inicfg := struct {
		Dockersh Configuration
		User     map[string]*Configuration
	}{}
	err = gcfg.ReadStringInto(&inicfg, string(bytes))
	if err != nil {
		return
	}
	if inicfg.User[user] == nil {
		return inicfg.Dockersh, nil
	}
	return mergeConfigs(inicfg.Dockersh, *inicfg.User[user], false), nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net"
	"net/http"
	"os"
	"strings"

	"github.com/codegangsta/cli"
)

const VERSION = "0.1"

func main() {
	app := cli.NewApp()
	app.Name = "groku"
	app.Version = VERSION
	app.Usage = "roku CLI remote"
	app.Commands = commands()
	app.Commands = append(app.Commands, discover())
	app.Run(os.Args)
}

func findRoku() string {
	ssdp, _ := net.ResolveUDPAddr("udp", "239.255.255.250:1900")
	addr, _ := net.ResolveUDPAddr("udp", ":0")
	socket, _ := net.ListenUDP("udp", addr)

	socket.WriteToUDP([]byte("M-SEARCH * HTTP/1.1\r\n"+
		"HOST: 239.255.255.250:1900\r\n"+
		"MAN: \"ssdp:discover\"\r\n"+
		"ST: roku:ecp\r\n"+
		"MX: 3 \r\n\r\n"), ssdp)

	answerBytes := make([]byte, 1024)
	socket.ReadFromUDP(answerBytes[:])

	ret := strings.Split(string(answerBytes), "\r\n")
	return strings.TrimPrefix(ret[len(ret)-3], "LOCATION: ")
}

func commands() []cli.Command {
	cmds := []cli.Command{}
	for _, cmd := range []string{
		"Home",
		"Rev",
		"Fwd",
		"Select",
		"Left",
		"Right",
		"Down",
		"Up",
		"Back",
		"Info",
		"Backspace",
		"Search",
		"Enter",
	} {
		cmds = append(cmds, cli.Command{
			Name:  strings.ToLower(cmd),
			Usage: strings.ToLower(cmd),
			Action: func(c *cli.Context) {
				http.PostForm(fmt.Sprintf("%vkeypress/%v", findRoku(), cmd), nil)
			},
		})
	}
	cmds = append(cmds, cli.Command{
		Name:  "replay",
		Usage: "replay",
		Action: func(c *cli.Context) {
			http.PostForm(fmt.Sprintf("%vkeypress/%v", findRoku(), "InstantReplay"), nil)
		},
	})
	cmds = append(cmds, cli.Command{
		Name:  "play",
		Usage: "play/pause",
		Action: func(c *cli.Context) {
			http.PostForm(fmt.Sprintf("%vkeypress/%v", findRoku(), "Play"), nil)
		},
	})
	return cmds
}

func discover() cli.Command {
	return cli.Command{
		Name:  "discover",
		Usage: "discover roku on your local network",
		Action: func(c *cli.Context) {
			fmt.Println("Found roku at", findRoku())
		},
	}
}
<commit_msg>Small refactor<commit_after>package main

import (
	"fmt"
	"net"
	"net/http"
	"os"
	"strings"

	"github.com/codegangsta/cli"
)

const VERSION = "0.1"

func main() {
	app := cli.NewApp()
	app.Name = "groku"
	app.Version = VERSION
	app.Usage = "roku CLI remote"
	app.Commands = commands()
	app.Run(os.Args)
}

func findRoku() string {
	ssdp, _ := net.ResolveUDPAddr("udp", "239.255.255.250:1900")
	addr, _ := net.ResolveUDPAddr("udp", ":0")
	socket, _ := net.ListenUDP("udp", addr)

	socket.WriteToUDP([]byte("M-SEARCH * HTTP/1.1\r\n"+
		"HOST: 239.255.255.250:1900\r\n"+
		"MAN: \"ssdp:discover\"\r\n"+
		"ST: roku:ecp\r\n"+
		"MX: 3 \r\n\r\n"), ssdp)

	answerBytes := make([]byte, 1024)
	socket.ReadFromUDP(answerBytes[:])

	ret := strings.Split(string(answerBytes), "\r\n")
	return strings.TrimPrefix(ret[len(ret)-3], "LOCATION: ")
}

func commands() []cli.Command {
	cmds := []cli.Command{}
	for _, cmd := range []string{
		"Home",
		"Rev",
		"Fwd",
		"Select",
		"Left",
		"Right",
		"Down",
		"Up",
		"Back",
		"Info",
		"Backspace",
		"Search",
		"Enter",
	} {
		cmds = append(cmds, cli.Command{
			Name:  strings.ToLower(cmd),
			Usage: strings.ToLower(cmd),
			Action: func(c *cli.Context) {
				http.PostForm(fmt.Sprintf("%vkeypress/%v", findRoku(), cmd), nil)
			},
		})
	}
	cmds = append(cmds, cli.Command{
		Name:  "replay",
		Usage: "replay",
		Action: func(c *cli.Context) {
			http.PostForm(fmt.Sprintf("%vkeypress/%v", findRoku(), "InstantReplay"), nil)
		},
	})
	cmds = append(cmds, cli.Command{
		Name:  "play",
		Usage: "play/pause",
		Action: func(c *cli.Context) {
			http.PostForm(fmt.Sprintf("%vkeypress/%v", findRoku(), "Play"), nil)
		},
	})
	cmds = append(cmds, cli.Command{
		Name:  "discover",
		Usage: "discover roku on your local network",
		Action: func(c *cli.Context) {
			fmt.Println("Found roku at", findRoku())
		},
	})
	return cmds
}
<|endoftext|>


<commit_before>// Copyright 2015-2018 HenryLee. All Rights Reserved.
//
// 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 tp

import (
	"errors"
	"math"
	"net"
	"strconv"
	"time"

	"github.com/henrylee2cn/cfgo"
	"github.com/henrylee2cn/teleport/socket"
)

// PeerConfig peer config
// NOTE:
//  yaml tag is used for github.com/henrylee2cn/cfgo
//  ini tag is used for github.com/henrylee2cn/ini
type PeerConfig struct {
	Network            string        `yaml:"network"              ini:"network"              comment:"Network; tcp, tcp4, tcp6, unix, unixpacket or quic"`
	LocalIP            string        `yaml:"local_ip"             ini:"local_ip"             comment:"Local IP"`
	ListenPort         uint16        `yaml:"listen_port"          ini:"listen_port"          comment:"Listen port; for server role"`
	DefaultDialTimeout time.Duration `yaml:"default_dial_timeout" ini:"default_dial_timeout" comment:"Default maximum duration for dialing; for client role; ns,µs,ms,s,m,h"`
	RedialTimes        int32         `yaml:"redial_times"         ini:"redial_times"         comment:"The maximum times of attempts to redial, after the connection has been unexpectedly broken; for client role"`
	RedialInterval     time.Duration `yaml:"redial_interval"      ini:"redial_interval"      comment:"Interval of redialing each time, default 100ms; for client role; ns,µs,ms,s,m,h"`
	DefaultBodyCodec   string        `yaml:"default_body_codec"   ini:"default_body_codec"   comment:"Default body codec type id"`
	DefaultSessionAge  time.Duration `yaml:"default_session_age"  ini:"default_session_age"  comment:"Default session max age, if less than or equal to 0, no time limit; ns,µs,ms,s,m,h"`
	DefaultContextAge  time.Duration `yaml:"default_context_age"  ini:"default_context_age"  comment:"Default CALL or PUSH context max age, if less than or equal to 0, no time limit; ns,µs,ms,s,m,h"`
	SlowCometDuration  time.Duration `yaml:"slow_comet_duration"  ini:"slow_comet_duration"  comment:"Slow operation alarm threshold; ns,µs,ms,s ..."`
	PrintDetail        bool          `yaml:"print_detail"         ini:"print_detail"         comment:"Is print body and metadata or not"`
	CountTime          bool          `yaml:"count_time"           ini:"count_time"           comment:"Is count cost time or not"`

	localAddr         net.Addr
	listenAddrStr     string
	slowCometDuration time.Duration
	checked           bool
}

var _ cfgo.Config = new(PeerConfig)

// Reload Bi-directionally synchronizes config between YAML file and memory.
func (p *PeerConfig) Reload(bind cfgo.BindFunc) error {
	err := bind()
	if err != nil {
		return err
	}
	p.checked = false
	return p.check()
}

func (p *PeerConfig) check() error {
	if p.checked {
		return nil
	}
	p.checked = true
	if len(p.LocalIP) == 0 {
		p.LocalIP = "0.0.0.0"
	}
	var err error
	switch p.Network {
	default:
		return errors.New("Invalid network config, refer to the following: tcp, tcp4, tcp6, unix, unixpacket or quic.")
	case "":
		p.Network = "tcp"
		fallthrough
	case "tcp", "tcp4", "tcp6":
		p.localAddr, err = net.ResolveTCPAddr(p.Network, net.JoinHostPort(p.LocalIP, "0"))
	case "unix", "unixpacket":
		p.localAddr, err = net.ResolveUnixAddr(p.Network, net.JoinHostPort(p.LocalIP, "0"))
	case "quic":
		p.localAddr, err = net.ResolveUDPAddr("udp", net.JoinHostPort(p.LocalIP, "0"))
	}
	if err != nil {
		return err
	}
	p.listenAddrStr = net.JoinHostPort(p.LocalIP, strconv.FormatUint(uint64(p.ListenPort), 10))
	p.slowCometDuration = math.MaxInt64
	if p.SlowCometDuration > 0 {
		p.slowCometDuration = p.SlowCometDuration
	}
	if len(p.DefaultBodyCodec) == 0 {
		p.DefaultBodyCodec = "json"
	}
	if p.RedialTimes < 0 {
		p.RedialTimes = 0
	}
	if p.RedialInterval <= 0 {
		p.RedialInterval = time.Millisecond * 100
	}
	return nil
}

// DefaultProtoFunc gets the default builder of socket communication protocol
//  func DefaultProtoFunc() tp.ProtoFunc
var DefaultProtoFunc = socket.DefaultProtoFunc

// SetDefaultProtoFunc sets the default builder of socket communication protocol
//  func SetDefaultProtoFunc(protoFunc tp.ProtoFunc)
var SetDefaultProtoFunc = socket.SetDefaultProtoFunc

// GetReadLimit gets the message size upper limit of reading.
//  GetReadLimit() uint32
var GetReadLimit = socket.MessageSizeLimit

// SetReadLimit sets max message size.
// If maxSize<=0, set it to max uint32.
//  func SetReadLimit(maxMessageSize uint32)
var SetReadLimit = socket.SetMessageSizeLimit

// SetSocketKeepAlive sets whether the operating system should send
// keepalive messages on the connection.
// NOTE: If have not called the function, the system defaults are used.
//  func SetSocketKeepAlive(keepalive bool)
var SetSocketKeepAlive = socket.SetKeepAlive

// SetSocketKeepAlivePeriod sets period between keep alives.
// NOTE: if d<0, don't change the value.
//  func SetSocketKeepAlivePeriod(d time.Duration)
var SetSocketKeepAlivePeriod = socket.SetKeepAlivePeriod

// SocketReadBuffer returns the size of the operating system's
// receive buffer associated with the connection.
// NOTE: if using the system default value, bytes=-1 and isDefault=true.
//  func SocketReadBuffer() (bytes int, isDefault bool)
var SocketReadBuffer = socket.ReadBuffer

// SetSocketReadBuffer sets the size of the operating system's
// receive buffer associated with the connection.
// NOTE: if bytes<0, don't change the value.
//  func SetSocketReadBuffer(bytes int)
var SetSocketReadBuffer = socket.SetReadBuffer

// SocketWriteBuffer returns the size of the operating system's
// transmit buffer associated with the connection.
// NOTE: if using the system default value, bytes=-1 and isDefault=true.
//  func SocketWriteBuffer() (bytes int, isDefault bool)
var SocketWriteBuffer = socket.WriteBuffer

// SetSocketWriteBuffer sets the size of the operating system's
// transmit buffer associated with the connection.
// NOTE: if bytes<0, don't change the value.
//  func SetSocketWriteBuffer(bytes int)
var SetSocketWriteBuffer = socket.SetWriteBuffer

// SetSocketNoDelay controls whether the operating system should delay
// packet transmission in hopes of sending fewer packets (Nagle's
// algorithm).  The default is true (no delay), meaning that data is
// sent as soon as possible after a Write.
//  func SetSocketNoDelay(noDelay bool)
var SetSocketNoDelay = socket.SetNoDelay
<commit_msg>feat(PeerConfig): add ListenerAddr method<commit_after>// Copyright 2015-2018 HenryLee. All Rights Reserved.
//
// 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 tp

import (
	"errors"
	"math"
	"net"
	"strconv"
	"time"

	"github.com/henrylee2cn/cfgo"
	"github.com/henrylee2cn/teleport/socket"
)

// PeerConfig peer config
// NOTE:
//  yaml tag is used for github.com/henrylee2cn/cfgo
//  ini tag is used for github.com/henrylee2cn/ini
type PeerConfig struct {
	Network            string        `yaml:"network"              ini:"network"              comment:"Network; tcp, tcp4, tcp6, unix, unixpacket or quic"`
	LocalIP            string        `yaml:"local_ip"             ini:"local_ip"             comment:"Local IP"`
	ListenPort         uint16        `yaml:"listen_port"          ini:"listen_port"          comment:"Listen port; for server role"`
	DefaultDialTimeout time.Duration `yaml:"default_dial_timeout" ini:"default_dial_timeout" comment:"Default maximum duration for dialing; for client role; ns,µs,ms,s,m,h"`
	RedialTimes        int32         `yaml:"redial_times"         ini:"redial_times"         comment:"The maximum times of attempts to redial, after the connection has been unexpectedly broken; for client role"`
	RedialInterval     time.Duration `yaml:"redial_interval"      ini:"redial_interval"      comment:"Interval of redialing each time, default 100ms; for client role; ns,µs,ms,s,m,h"`
	DefaultBodyCodec   string        `yaml:"default_body_codec"   ini:"default_body_codec"   comment:"Default body codec type id"`
	DefaultSessionAge  time.Duration `yaml:"default_session_age"  ini:"default_session_age"  comment:"Default session max age, if less than or equal to 0, no time limit; ns,µs,ms,s,m,h"`
	DefaultContextAge  time.Duration `yaml:"default_context_age"  ini:"default_context_age"  comment:"Default CALL or PUSH context max age, if less than or equal to 0, no time limit; ns,µs,ms,s,m,h"`
	SlowCometDuration  time.Duration `yaml:"slow_comet_duration"  ini:"slow_comet_duration"  comment:"Slow operation alarm threshold; ns,µs,ms,s ..."`
	PrintDetail        bool          `yaml:"print_detail"         ini:"print_detail"         comment:"Is print body and metadata or not"`
	CountTime          bool          `yaml:"count_time"           ini:"count_time"           comment:"Is count cost time or not"`

	localAddr         net.Addr
	listenAddrStr     string
	slowCometDuration time.Duration
	checked           bool
}

var _ cfgo.Config = new(PeerConfig)

// ListenerAddr returns the listener address.
func (p *PeerConfig) ListenerAddr() string {
	p.check()
	return p.listenAddrStr
}

// Reload Bi-directionally synchronizes config between YAML file and memory.
func (p *PeerConfig) Reload(bind cfgo.BindFunc) error {
	err := bind()
	if err != nil {
		return err
	}
	p.checked = false
	return p.check()
}

func (p *PeerConfig) check() error {
	if p.checked {
		return nil
	}
	p.checked = true
	if len(p.LocalIP) == 0 {
		p.LocalIP = "0.0.0.0"
	}
	var err error
	switch p.Network {
	default:
		return errors.New("Invalid network config, refer to the following: tcp, tcp4, tcp6, unix, unixpacket or quic")
	case "":
		p.Network = "tcp"
		fallthrough
	case "tcp", "tcp4", "tcp6":
		p.localAddr, err = net.ResolveTCPAddr(p.Network, net.JoinHostPort(p.LocalIP, "0"))
	case "unix", "unixpacket":
		p.localAddr, err = net.ResolveUnixAddr(p.Network, net.JoinHostPort(p.LocalIP, "0"))
	case "quic":
		p.localAddr, err = net.ResolveUDPAddr("udp", net.JoinHostPort(p.LocalIP, "0"))
	}
	if err != nil {
		return err
	}
	p.listenAddrStr = net.JoinHostPort(p.LocalIP, strconv.FormatUint(uint64(p.ListenPort), 10))
	p.slowCometDuration = math.MaxInt64
	if p.SlowCometDuration > 0 {
		p.slowCometDuration = p.SlowCometDuration
	}
	if len(p.DefaultBodyCodec) == 0 {
		p.DefaultBodyCodec = "json"
	}
	if p.RedialTimes < 0 {
		p.RedialTimes = 0
	}
	if p.RedialInterval <= 0 {
		p.RedialInterval = time.Millisecond * 100
	}
	return nil
}

// DefaultProtoFunc gets the default builder of socket communication protocol
//  func DefaultProtoFunc() tp.ProtoFunc
var DefaultProtoFunc = socket.DefaultProtoFunc

// SetDefaultProtoFunc sets the default builder of socket communication protocol
//  func SetDefaultProtoFunc(protoFunc tp.ProtoFunc)
var SetDefaultProtoFunc = socket.SetDefaultProtoFunc

// GetReadLimit gets the message size upper limit of reading.
//  GetReadLimit() uint32
var GetReadLimit = socket.MessageSizeLimit

// SetReadLimit sets max message size.
// If maxSize<=0, set it to max uint32.
//  func SetReadLimit(maxMessageSize uint32)
var SetReadLimit = socket.SetMessageSizeLimit

// SetSocketKeepAlive sets whether the operating system should send
// keepalive messages on the connection.
// NOTE: If have not called the function, the system defaults are used.
//  func SetSocketKeepAlive(keepalive bool)
var SetSocketKeepAlive = socket.SetKeepAlive

// SetSocketKeepAlivePeriod sets period between keep alives.
// NOTE: if d<0, don't change the value.
//  func SetSocketKeepAlivePeriod(d time.Duration)
var SetSocketKeepAlivePeriod = socket.SetKeepAlivePeriod

// SocketReadBuffer returns the size of the operating system's
// receive buffer associated with the connection.
// NOTE: if using the system default value, bytes=-1 and isDefault=true.
//  func SocketReadBuffer() (bytes int, isDefault bool)
var SocketReadBuffer = socket.ReadBuffer

// SetSocketReadBuffer sets the size of the operating system's
// receive buffer associated with the connection.
// NOTE: if bytes<0, don't change the value.
//  func SetSocketReadBuffer(bytes int)
var SetSocketReadBuffer = socket.SetReadBuffer

// SocketWriteBuffer returns the size of the operating system's
// transmit buffer associated with the connection.
// NOTE: if using the system default value, bytes=-1 and isDefault=true.
//  func SocketWriteBuffer() (bytes int, isDefault bool)
var SocketWriteBuffer = socket.WriteBuffer

// SetSocketWriteBuffer sets the size of the operating system's
// transmit buffer associated with the connection.
// NOTE: if bytes<0, don't change the value.
//  func SetSocketWriteBuffer(bytes int)
var SetSocketWriteBuffer = socket.SetWriteBuffer

// SetSocketNoDelay controls whether the operating system should delay
// packet transmission in hopes of sending fewer packets (Nagle's
// algorithm).  The default is true (no delay), meaning that data is
// sent as soon as possible after a Write.
//  func SetSocketNoDelay(noDelay bool)
var SetSocketNoDelay = socket.SetNoDelay
<|endoftext|>


<commit_before>package common

import (
	"fmt"

	"github.com/yahoo/coname/proto"
)

// VerifyUpdate returns nil iff replacing entry current (nil if none) with next
// is justified given the evidence in update. Globally deterministic.
func VerifyUpdate(current *proto.Entry, update *proto.SignedEntryUpdate, next *proto.Entry) error {
	if current != nil {
		if current.UpdateKey == nil {
			return fmt.Errorf("VerifyUpdate: current.UpdateKey is nil")
		}
		if !VerifySignature(current.UpdateKey, update.Update.PreservedEncoding, update.OldSig) {
			return fmt.Errorf("VerifyUpdate: replacing an entry requires authorization from the old key, but signature verification failed", next.Version, current.Version)
		}
		if next.Version < current.Version {
			return fmt.Errorf("VerifyUpdate: entry version must not decrease (got %d < %d)", next.Version, current.Version)
		}
	}
	if next.UpdateKey == nil {
		return fmt.Errorf("VerifyUpdate: next.UpdateKey is nil")
	}
	if !VerifySignature(next.UpdateKey, update.Update.PreservedEncoding, update.NewSig) {
		return fmt.Errorf("VerifyUpdate: update needs to be accepted by the new key, but signature verification failed", next.Version, current.Version)
	}
	return nil
}
<commit_msg>common/policy.go: fix Errorf calls in<commit_after>package common

import (
	"fmt"

	"github.com/yahoo/coname/proto"
)

// VerifyUpdate returns nil iff replacing entry current (nil if none) with next
// is justified given the evidence in update. Globally deterministic.
func VerifyUpdate(current *proto.Entry, update *proto.SignedEntryUpdate) error {
	next := &update.Update.NewEntry
	if current != nil {
		if current.UpdateKey == nil {
			return fmt.Errorf("VerifyUpdate: current.UpdateKey is nil")
		}
		if !VerifySignature(current.UpdateKey, update.Update.PreservedEncoding, update.OldSig) {
			return fmt.Errorf("VerifyUpdate: replacing an entry requires authorization from the old key, but signature verification failed")
		}
		if next.Version < current.Version {
			return fmt.Errorf("VerifyUpdate: entry version must not decrease (got %d < %d)", next.Version, current.Version)
		}
	}
	if next.UpdateKey == nil {
		return fmt.Errorf("VerifyUpdate: next.UpdateKey is nil")
	}
	if !VerifySignature(next.UpdateKey, update.Update.PreservedEncoding, update.NewSig) {
		return fmt.Errorf("VerifyUpdate: update needs to be accepted by the new key, but signature verification failed")
	}
	return nil
}
<|endoftext|>