<commit_before>package redismanager

import (
	"strings"
	"time"

	"github.com/garyburd/redigo/redis"
	"github.com/pajlada/pajbot2/common"
	"github.com/pajlada/pajbot2/helper"
)

// RedisManager keeps the pool of redis connections
type RedisManager struct {
	Pool *redis.Pool
}

// Init connects to redis and returns redis client
func Init(config *common.Config) *RedisManager {
	r := &RedisManager{}
	pool := redis.NewPool(func() (redis.Conn, error) {
		c, err := redis.Dial("tcp", config.RedisHost)
		if err != nil {
			log.Fatal("An error occured while connecting to redis: ", err)
			return nil, err
		}
		if config.RedisDatabase >= 0 {
			_, err = c.Do("SELECT", config.RedisDatabase)
			if err != nil {
				log.Fatal("Error while selecting redis db:", err)
				return nil, err
			}
		}
		return c, err
	}, 69)
	// forsenGASM
	r.Pool = pool
	log.Debug("connected to redis")
	return r
}

// UpdateGlobalUser sets global values for a user (in other words, values that transcend channels)
// Only globally banned users and admins have a level in global redis
func (r *RedisManager) UpdateGlobalUser(channel string, user *common.User, u *common.GlobalUser) {
	conn := r.Pool.Get()
	conn.Send("HSET", "global:lastactive", user.Name, time.Now().Unix())

	// Don't update the channel if the channel is empty (i.e. a whisper)
	if channel != "" {
		conn.Send("HSET", "global:channel", user.Name, channel)
	}
	conn.Flush()
	conn.Close()
}

// GetGlobalUser fills in the user and u objects with values from the users global values
func (r *RedisManager) GetGlobalUser(channel string, user *common.User, u *common.GlobalUser) {
	conn := r.Pool.Get()
	defer conn.Close()
	exist, err := conn.Do("HEXISTS", "global:lastactive", user.Name)
	e, _ := redis.Bool(exist, err)
	if e {
		conn.Send("HGET", "global:level", user.Name)
		conn.Send("HGET", "global:lastactive", user.Name)
		conn.Send("HGET", "global:channel", user.Name)
		conn.Flush()
		// can this be done in a loop somehow?
		// Level
		res, err := conn.Receive()
		level, _ := redis.Int(res, err) // will be 0 unless user is admin or globally banned
		if level > user.Level {
			// XXX: Should this set u.Level instead? not sure!
			user.Level = level
		}
		// LastActive
		res, err = conn.Receive()
		t, _ := redis.String(res, err)
		u.LastActive, _ = time.Parse(time.UnixDate, t)
		// Channel
		res, err = conn.Receive()
		u.Channel, _ = redis.String(res, err)
	} else {
		r.UpdateGlobalUser(channel, user, u)
		r.GetGlobalUser(channel, user, u)
	}
	r.UpdateGlobalUser(channel, user, u)
}

// IsValidUser checks if the user is in the database
func (r *RedisManager) IsValidUser(channel string, _user string) bool {
	conn := r.Pool.Get()
	defer conn.Close()
	user := strings.ToLower(_user)
	res, err := redis.Bool(conn.Do("HEXISTS", channel+":users:lastseen", user))
	if err != nil {
		log.Error(err)
	}
	return res
}

// SetPoints sets the amount of points a user has in the given channel
func (r *RedisManager) SetPoints(channel string, user *common.User) {
	conn := r.Pool.Get()
	defer conn.Close()
	conn.Send("ZADD", channel+":users:points", user.Points, user.Name)
	conn.Flush()
}

// IncrPoints increases the points of a user in the given channel
func (r *RedisManager) IncrPoints(channel string, user string, incrby int) {
	conn := r.Pool.Get()
	defer conn.Close()
	conn.Send("ZINCRBY", channel+":users:points", incrby, user)
	conn.Flush()
}

func (r *RedisManager) newUser(channel string, user *common.User) {
	conn := r.Pool.Get()
	defer conn.Close()
	conn.Send("HSET", channel+":users:lastseen", user.Name, time.Now().Unix())
	conn.Send("ZADD", channel+":users:points", user.Points, user.Name)

	// Why is this called?
	conn.Send("HSET", channel+":users:level", user.Name, r.getLevel(createLevel(0, 1), user))

	conn.Flush()
}

// SetLevel sets the users level in the given channel
func (r *RedisManager) SetLevel(channel string, user *common.User, level int) {
	conn := r.Pool.Get()
	defer conn.Close()
	conn.Send("HSET", channel+":users:level", user.Name, createLevel(uint32(level), 0)) // XXX: Make sure the flags are right
	conn.Flush()
}

// ResetLevel resets a users level to 0/default XXX
func (r *RedisManager) ResetLevel(channel string, user *common.User) {
	conn := r.Pool.Get()
	defer conn.Close()
	conn.Send("HSET", channel+":users:level", user.Name, r.getLevel(createLevel(0, 1), user))
	conn.Flush()
}

// UpdateUser saves data about a user in redis
func (r *RedisManager) UpdateUser(channel string, user *common.User, oldUser *common.User) {
	conn := r.Pool.Get()
	defer conn.Close()
	if user.Name == channel {
		r.SetLevel(channel, user, 1500)
	}
	conn.Send("HSET", channel+":users:lastseen", user.Name, time.Now().Unix())
	conn.Send("HSET", channel+":users:lastactive", user.Name, time.Now().Unix())

	// Update total message count if needed
	if user.TotalMessageCount != oldUser.TotalMessageCount {
		conn.Send("ZADD", channel+":users:total_message_count", user.TotalMessageCount, user.Name)
	}

	// Update online message count if needed
	if user.OnlineMessageCount != oldUser.OnlineMessageCount {
		conn.Send("ZADD", channel+":users:online_message_count", user.OnlineMessageCount, user.Name)
	}

	// Update offline message count if needed
	if user.OfflineMessageCount != oldUser.OfflineMessageCount {
		conn.Send("ZADD", channel+":users:offline_message_count", user.OfflineMessageCount, user.Name)
	}

	if user.Points != oldUser.Points {
		r.IncrPoints(channel, user.Name, user.Points-oldUser.Points)
	}

	conn.Flush()
}

// LoadUser returns the user object, all default values if user doesnt exist
func (r *RedisManager) LoadUser(channel string, user string) common.User {
	conn := r.Pool.Get()
	defer conn.Close()
	u := common.User{}
	if r.IsValidUser(channel, user) {
		u.Name = strings.ToLower(user)
		u.DisplayName = user
		r.GetUser(channel, &u)
	}
	return u
}

// GetUser fills out missing fields of the given User object
// and creates new user in redis if the user doesnt exist
func (r *RedisManager) GetUser(channel string, user *common.User) {
	conn := r.Pool.Get()
	defer conn.Close()
	exist, err := conn.Do("HEXISTS", channel+":users:lastseen", user.Name)
	e, _ := redis.Bool(exist, err)
	if e {
		conn.Send("HGET", channel+":users:level", user.Name)
		conn.Send("ZSCORE", channel+":users:points", user.Name)
		conn.Send("HGET", channel+":users:lastseen", user.Name)
		conn.Send("ZSCORE", channel+":users:total_message_count", user.Name)
		conn.Send("ZSCORE", channel+":users:online_message_count", user.Name)
		conn.Send("ZSCORE", channel+":users:offline_message_count", user.Name)
		conn.Flush()
		// can this be done in a loop somehow?
		// Level
		res, err := conn.Receive()
		level, _ := redis.Uint64(res, err)
		user.Level = r.getLevel(level, user)
		// Points
		res, err = conn.Receive()
		user.Points, _ = redis.Int(res, err)
		// LastSeen
		res, err = conn.Receive()
		lastseen, _ := redis.String(res, err)
		user.LastSeen, _ = time.Parse(time.UnixDate, lastseen)
		// TotalMessageCount
		res, err = conn.Receive()
		user.TotalMessageCount, _ = redis.Int(res, err)
		// OnlineMessageCount
		res, err = conn.Receive()
		user.OnlineMessageCount, _ = redis.Int(res, err)
		// OfflineMessageCount
		res, err = conn.Receive()
		user.OfflineMessageCount, _ = redis.Int(res, err)
	} else {
		r.newUser(channel, user)
		r.GetUser(channel, user)
	}
}

// Flags for user level values
const (
	// Specifies whether the level was set automatically or not.
	// If the level was set automatically, that means it will always be
	// re-evaluated
	LevelFlagAutomatic = 1 << iota
)

/*
First 32 bits specifies the level Value
Last 32 bits specifies the level Flags
*/
func (r *RedisManager) getLevel(levelCombined uint64, user *common.User) int {
	// Split up the values from levelCombined
	levelFlags, levelValue := helper.SplitUint64(levelCombined)

	// Returns the users Global Level if its higher than the Channel Level
	if user.Level > int(levelValue) {
		return user.Level
	}

	// If the level was set manually, return that level
	if !helper.CheckFlag(levelFlags, LevelFlagAutomatic) {
		return int(levelValue)
	}

	// Otherwise, return the automatic level that's appropriate for the user
	if user.ChannelOwner {
		return 1500
	} else if user.Mod {
		return 500
	} else if user.Sub {
		return 250
	}

	// Normal user
	return 100
}

func createLevel(levelValue uint32, levelFlags uint32) uint64 {
	// XXX: Make sure this is correct
	return helper.CombineUint32(levelFlags, levelValue)
}
<commit_msg>fixed whispers<commit_after>package redismanager

import (
	"strings"
	"time"

	"github.com/garyburd/redigo/redis"
	"github.com/pajlada/pajbot2/common"
	"github.com/pajlada/pajbot2/helper"
)

// RedisManager keeps the pool of redis connections
type RedisManager struct {
	Pool *redis.Pool
}

// Init connects to redis and returns redis client
func Init(config *common.Config) *RedisManager {
	r := &RedisManager{}
	pool := redis.NewPool(func() (redis.Conn, error) {
		c, err := redis.Dial("tcp", config.RedisHost)
		if err != nil {
			log.Fatal("An error occured while connecting to redis: ", err)
			return nil, err
		}
		if config.RedisDatabase >= 0 {
			_, err = c.Do("SELECT", config.RedisDatabase)
			if err != nil {
				log.Fatal("Error while selecting redis db:", err)
				return nil, err
			}
		}
		return c, err
	}, 69)
	// forsenGASM
	r.Pool = pool
	log.Debug("connected to redis")
	return r
}

// UpdateGlobalUser sets global values for a user (in other words, values that transcend channels)
// Only globally banned users and admins have a level in global redis
func (r *RedisManager) UpdateGlobalUser(channel string, user *common.User, u *common.GlobalUser) {
	conn := r.Pool.Get()
	conn.Send("HSET", "global:lastactive", user.Name, time.Now().Unix())

	// Don't update the channel if the channel is empty (i.e. a whisper)
	if channel != "" {
		conn.Send("HSET", "global:channel", user.Name, channel)
	}
	conn.Flush()
	conn.Close()
}

// GetGlobalUser fills in the user and u objects with values from the users global values
func (r *RedisManager) GetGlobalUser(channel string, user *common.User, u *common.GlobalUser) {
	conn := r.Pool.Get()
	defer conn.Close()
	exist, err := conn.Do("HEXISTS", "global:lastactive", user.Name)
	e, _ := redis.Bool(exist, err)
	if e {
		conn.Send("HGET", "global:level", user.Name)
		conn.Send("HGET", "global:lastactive", user.Name)
		conn.Send("HGET", "global:channel", user.Name)
		conn.Flush()
		// can this be done in a loop somehow?
		// Level
		res, err := conn.Receive()
		level, _ := redis.Int(res, err) // will be 0 unless user is admin or globally banned
		if level > user.Level {
			// XXX: Should this set u.Level instead? not sure!
			user.Level = level
		}
		// LastActive
		res, err = conn.Receive()
		t, _ := redis.String(res, err)
		u.LastActive, _ = time.Parse(time.UnixDate, t)
		// Channel
		res, err = conn.Receive()
		u.Channel, _ = redis.String(res, err)
	} else {
		r.UpdateGlobalUser(u.Channel, user, u)
		r.GetGlobalUser(channel, user, u)
	}
	r.UpdateGlobalUser(channel, user, u)
}

// IsValidUser checks if the user is in the database
func (r *RedisManager) IsValidUser(channel string, _user string) bool {
	conn := r.Pool.Get()
	defer conn.Close()
	user := strings.ToLower(_user)
	res, err := redis.Bool(conn.Do("HEXISTS", channel+":users:lastseen", user))
	if err != nil {
		log.Error(err)
	}
	return res
}

// SetPoints sets the amount of points a user has in the given channel
func (r *RedisManager) SetPoints(channel string, user *common.User) {
	conn := r.Pool.Get()
	defer conn.Close()
	conn.Send("ZADD", channel+":users:points", user.Points, user.Name)
	conn.Flush()
}

// IncrPoints increases the points of a user in the given channel
func (r *RedisManager) IncrPoints(channel string, user string, incrby int) {
	conn := r.Pool.Get()
	defer conn.Close()
	conn.Send("ZINCRBY", channel+":users:points", incrby, user)
	conn.Flush()
}

func (r *RedisManager) newUser(channel string, user *common.User) {
	conn := r.Pool.Get()
	defer conn.Close()
	conn.Send("HSET", channel+":users:lastseen", user.Name, time.Now().Unix())
	conn.Send("ZADD", channel+":users:points", user.Points, user.Name)

	// Why is this called?
	conn.Send("HSET", channel+":users:level", user.Name, r.getLevel(createLevel(0, 1), user))

	conn.Flush()
}

// SetLevel sets the users level in the given channel
func (r *RedisManager) SetLevel(channel string, user *common.User, level int) {
	conn := r.Pool.Get()
	defer conn.Close()
	conn.Send("HSET", channel+":users:level", user.Name, createLevel(uint32(level), 0)) // XXX: Make sure the flags are right
	conn.Flush()
}

// ResetLevel resets a users level to 0/default XXX
func (r *RedisManager) ResetLevel(channel string, user *common.User) {
	conn := r.Pool.Get()
	defer conn.Close()
	conn.Send("HSET", channel+":users:level", user.Name, r.getLevel(createLevel(0, 1), user))
	conn.Flush()
}

// UpdateUser saves data about a user in redis
func (r *RedisManager) UpdateUser(channel string, user *common.User, oldUser *common.User) {
	conn := r.Pool.Get()
	defer conn.Close()
	if user.Name == channel {
		r.SetLevel(channel, user, 1500)
	}
	conn.Send("HSET", channel+":users:lastseen", user.Name, time.Now().Unix())
	conn.Send("HSET", channel+":users:lastactive", user.Name, time.Now().Unix())

	// Update total message count if needed
	if user.TotalMessageCount != oldUser.TotalMessageCount {
		conn.Send("ZADD", channel+":users:total_message_count", user.TotalMessageCount, user.Name)
	}

	// Update online message count if needed
	if user.OnlineMessageCount != oldUser.OnlineMessageCount {
		conn.Send("ZADD", channel+":users:online_message_count", user.OnlineMessageCount, user.Name)
	}

	// Update offline message count if needed
	if user.OfflineMessageCount != oldUser.OfflineMessageCount {
		conn.Send("ZADD", channel+":users:offline_message_count", user.OfflineMessageCount, user.Name)
	}

	if user.Points != oldUser.Points {
		r.IncrPoints(channel, user.Name, user.Points-oldUser.Points)
	}

	conn.Flush()
}

// LoadUser returns the user object, all default values if user doesnt exist
func (r *RedisManager) LoadUser(channel string, user string) common.User {
	conn := r.Pool.Get()
	defer conn.Close()
	u := common.User{}
	if r.IsValidUser(channel, user) {
		u.Name = strings.ToLower(user)
		u.DisplayName = user
		r.GetUser(channel, &u)
	}
	return u
}

// GetUser fills out missing fields of the given User object
// and creates new user in redis if the user doesnt exist
func (r *RedisManager) GetUser(channel string, user *common.User) {
	conn := r.Pool.Get()
	defer conn.Close()
	exist, err := conn.Do("HEXISTS", channel+":users:lastseen", user.Name)
	e, _ := redis.Bool(exist, err)
	if e {
		conn.Send("HGET", channel+":users:level", user.Name)
		conn.Send("ZSCORE", channel+":users:points", user.Name)
		conn.Send("HGET", channel+":users:lastseen", user.Name)
		conn.Send("ZSCORE", channel+":users:total_message_count", user.Name)
		conn.Send("ZSCORE", channel+":users:online_message_count", user.Name)
		conn.Send("ZSCORE", channel+":users:offline_message_count", user.Name)
		conn.Flush()
		// can this be done in a loop somehow?
		// Level
		res, err := conn.Receive()
		level, _ := redis.Uint64(res, err)
		user.Level = r.getLevel(level, user)
		// Points
		res, err = conn.Receive()
		user.Points, _ = redis.Int(res, err)
		// LastSeen
		res, err = conn.Receive()
		lastseen, _ := redis.String(res, err)
		user.LastSeen, _ = time.Parse(time.UnixDate, lastseen)
		// TotalMessageCount
		res, err = conn.Receive()
		user.TotalMessageCount, _ = redis.Int(res, err)
		// OnlineMessageCount
		res, err = conn.Receive()
		user.OnlineMessageCount, _ = redis.Int(res, err)
		// OfflineMessageCount
		res, err = conn.Receive()
		user.OfflineMessageCount, _ = redis.Int(res, err)
	} else {
		r.newUser(channel, user)
		r.GetUser(channel, user)
	}
}

// Flags for user level values
const (
	// Specifies whether the level was set automatically or not.
	// If the level was set automatically, that means it will always be
	// re-evaluated
	LevelFlagAutomatic = 1 << iota
)

/*
First 32 bits specifies the level Value
Last 32 bits specifies the level Flags
*/
func (r *RedisManager) getLevel(levelCombined uint64, user *common.User) int {
	// Split up the values from levelCombined
	levelFlags, levelValue := helper.SplitUint64(levelCombined)

	// Returns the users Global Level if its higher than the Channel Level
	if user.Level > int(levelValue) {
		return user.Level
	}

	// If the level was set manually, return that level
	if !helper.CheckFlag(levelFlags, LevelFlagAutomatic) {
		return int(levelValue)
	}

	// Otherwise, return the automatic level that's appropriate for the user
	if user.ChannelOwner {
		return 1500
	} else if user.Mod {
		return 500
	} else if user.Sub {
		return 250
	}

	// Normal user
	return 100
}

func createLevel(levelValue uint32, levelFlags uint32) uint64 {
	// XXX: Make sure this is correct
	return helper.CombineUint32(levelFlags, levelValue)
}
<|endoftext|>


<commit_before>package convert

import (
	"fmt"
)

func Example_usage() {
	// Convert 1 statute mile to nautical miles
	nautical := StatuteToNauticalMiles(1)
	fmt.Printf("%.2f\n", nautical)

	// Convert 1 nautical mile to statute miles
	statute := NauticalToStatuteMiles(1)
	fmt.Printf("%.2f\n", statute)

	// Output:
	// 1.15
	// 0.87
}
<commit_msg>Added example.<commit_after>package convert

import (
	"fmt"
)

func Example_usage() {
	// Convert 1 statute mile to nautical miles
	nautical := StatuteToNauticalMiles(1)
	fmt.Printf("%.2f\n", nautical)

	// Convert 1 nautical mile to statute miles
	statute := NauticalToStatuteMiles(1)
	fmt.Printf("%.2f\n", statute)

	// Convert 1 gallon of gas (100LL) to pounds.
	lbs := GallonsOfGasToPounds(1)
	fmt.Printf("%.2f\n", lbs)

	// Output:
	// 1.15
	// 0.87
	// 6.00
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"

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

func resourceAwsCloudFrontPublicKey() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsCloudFrontPublicKeyCreate,
		Read:   resourceAwsCloudFrontPublicKeyRead,
		Update: resourceAwsCloudFrontPublicKeyUpdate,
		Delete: resourceAwsCloudFrontPublicKeyDelete,

		Schema: map[string]*schema.Schema{
			"name": {
				Type:          schema.TypeString,
				Optional:      true,
				Computed:      true,
				ForceNew:      true,
				ConflictsWith: []string{"name_prefix"},
				ValidateFunc:  validateCloudFrontPublicKeyName,
			},
			"name_prefix": {
				Type:          schema.TypeString,
				Optional:      true,
				Computed:      true,
				ForceNew:      true,
				ConflictsWith: []string{"name"},
				ValidateFunc:  validateCloudFrontPublicKeyNamePrefix,
			},
			"encoded_key": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"comment": {
				Type:     schema.TypeString,
				Optional: true,
			},
			"etag": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"location": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"id": {
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}
<commit_msg>add create func for cloudfront_pubkey<commit_after>package aws

import (
	"fmt"
	"log"

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

func resourceAwsCloudFrontPublicKey() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsCloudFrontPublicKeyCreate,
		Read:   resourceAwsCloudFrontPublicKeyRead,
		Update: resourceAwsCloudFrontPublicKeyUpdate,
		Delete: resourceAwsCloudFrontPublicKeyDelete,

		Schema: map[string]*schema.Schema{
			"name": {
				Type:          schema.TypeString,
				Optional:      true,
				Computed:      true,
				ForceNew:      true,
				ConflictsWith: []string{"name_prefix"},
				ValidateFunc:  validateCloudFrontPublicKeyName,
			},
			"name_prefix": {
				Type:          schema.TypeString,
				Optional:      true,
				Computed:      true,
				ForceNew:      true,
				ConflictsWith: []string{"name"},
				ValidateFunc:  validateCloudFrontPublicKeyNamePrefix,
			},
			"encoded_key": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"comment": {
				Type:     schema.TypeString,
				Optional: true,
			},
			"etag": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"id": {
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

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

	if v, ok := d.GetOk("name"); ok {
		d.Set("name", v.(string))
	} else if v, ok := d.GetOk("name_prefix"); ok {
		d.Set("name", resource.PrefixedUniqueId(v.(string)))
	} else {
		d.Set("name", resource.PrefixedUniqueId("tf-"))
	}

	request := &cloudfront.CreatePublicKeyInput{
		PublicKeyConfig: expandPublicKeyConfig(d),
	}

	log.Println("[DEBUG] Create CloudFront PublicKey:", request)

	output, err := conn.CreatePublicKey(request)
	if err != nil {
		return fmt.Errorf("error creating CloudFront PublicKey: %s", err)
	}

	d.SetId(aws.StringValue(output.PublicKey.Id))
	return resourceAwsCloudFrontPublicKeyRead(d, meta)
}

func expandPublicKeyConfig(d *schema.ResourceData) *cloudfront.PublicKeyConfig {
	publicKeyConfig := &cloudfront.PublicKeyConfig{
		CallerReference: aws.String(resource.UniqueId()),
		EncodedKey:      aws.String(d.Get("encoded_key").(string)),
		Name:            aws.String(d.Get("name").(string)),
	}

	if v, ok := d.GetOk("comment"); ok {
		publicKeyConfig.Comment = aws.String(v.(string))
	}

	return publicKeyConfig
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"regexp"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	events "github.com/aws/aws-sdk-go/service/cloudwatchevents"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/helper/structure"
	"github.com/hashicorp/terraform/helper/validation"
)

func resourceAwsCloudWatchEventRule() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsCloudWatchEventRuleCreate,
		Read:   resourceAwsCloudWatchEventRuleRead,
		Update: resourceAwsCloudWatchEventRuleUpdate,
		Delete: resourceAwsCloudWatchEventRuleDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:          schema.TypeString,
				Optional:      true,
				Computed:      true,
				ForceNew:      true,
				ConflictsWith: []string{"name_prefix"},
				ValidateFunc:  validateCloudWatchEventRuleName,
			},
			"name_prefix": {
				Type:         schema.TypeString,
				Optional:     true,
				ForceNew:     true,
				ValidateFunc: validateCloudWatchEventRuleName,
			},
			"schedule_expression": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringLenBetween(0, 256),
			},
			"event_pattern": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validateEventPatternValue(),
				StateFunc: func(v interface{}) string {
					json, _ := structure.NormalizeJsonString(v.(string))
					return json
				},
			},
			"description": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringLenBetween(0, 512),
			},
			"role_arn": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringLenBetween(0, 1600),
			},
			"is_enabled": {
				Type:     schema.TypeBool,
				Optional: true,
				Default:  true,
			},
			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"tags": tagsSchema(),
		},
	}
}

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

	var name string
	if v, ok := d.GetOk("name"); ok {
		name = v.(string)
	} else if v, ok := d.GetOk("name_prefix"); ok {
		name = resource.PrefixedUniqueId(v.(string))
	} else {
		name = resource.UniqueId()
	}

	input, err := buildPutRuleInputStruct(d, name)
	if err != nil {
		return fmt.Errorf("Creating CloudWatch Event Rule failed: %s", err)
	}
	log.Printf("[DEBUG] Creating CloudWatch Event Rule: %s", input)

	// IAM Roles take some time to propagate
	var out *events.PutRuleOutput
	err = resource.Retry(30*time.Second, func() *resource.RetryError {
		var err error
		out, err = conn.PutRule(input)
		pattern := regexp.MustCompile(`cannot be assumed by principal '[a-z]+\.amazonaws\.com'\.$`)
		if err != nil {
			if awsErr, ok := err.(awserr.Error); ok {
				if awsErr.Code() == "ValidationException" && pattern.MatchString(awsErr.Message()) {
					log.Printf("[DEBUG] Retrying creation of CloudWatch Event Rule %q", *input.Name)
					return resource.RetryableError(err)
				}
			}
			return resource.NonRetryableError(err)
		}
		return nil
	})
	if err != nil {
		return fmt.Errorf("Creating CloudWatch Event Rule failed: %s", err)
	}

	d.Set("arn", out.RuleArn)
	d.SetId(*input.Name)

	log.Printf("[INFO] CloudWatch Event Rule %q created", *out.RuleArn)

	if err := setTagsCloudWatchEvents(conn, d, aws.StringValue(out.RuleArn)); err != nil {
		return fmt.Errorf("Error creating tags for %s: %s", d.Id(), err)
	}

	return resourceAwsCloudWatchEventRuleUpdate(d, meta)
}

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

	input := events.DescribeRuleInput{
		Name: aws.String(d.Id()),
	}
	log.Printf("[DEBUG] Reading CloudWatch Event Rule: %s", input)
	out, err := conn.DescribeRule(&input)
	if awsErr, ok := err.(awserr.Error); ok {
		if awsErr.Code() == "ResourceNotFoundException" {
			log.Printf("[WARN] Removing CloudWatch Event Rule %q because it's gone.", d.Id())
			d.SetId("")
			return nil
		}
	}
	if err != nil {
		return err
	}
	log.Printf("[DEBUG] Found Event Rule: %s", out)

	d.Set("arn", out.Arn)
	d.Set("description", out.Description)
	if out.EventPattern != nil {
		pattern, err := structure.NormalizeJsonString(*out.EventPattern)
		if err != nil {
			return fmt.Errorf("event pattern contains an invalid JSON: %s", err)
		}
		d.Set("event_pattern", pattern)
	}
	d.Set("name", out.Name)
	d.Set("role_arn", out.RoleArn)
	d.Set("schedule_expression", out.ScheduleExpression)

	boolState, err := getBooleanStateFromString(*out.State)
	if err != nil {
		return err
	}
	log.Printf("[DEBUG] Setting boolean state: %t", boolState)
	d.Set("is_enabled", boolState)
	d.Set("tags", saveTagsCloudWatchEvents(conn, d, aws.StringValue(out.Arn)))

	return nil
}

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

	if d.HasChange("is_enabled") && d.Get("is_enabled").(bool) {
		log.Printf("[DEBUG] Enabling CloudWatch Event Rule %q", d.Id())
		_, err := conn.EnableRule(&events.EnableRuleInput{
			Name: aws.String(d.Id()),
		})
		if err != nil {
			return err
		}
		log.Printf("[DEBUG] CloudWatch Event Rule (%q) enabled", d.Id())
	}

	input, err := buildPutRuleInputStruct(d, d.Id())
	if err != nil {
		return fmt.Errorf("Updating CloudWatch Event Rule failed: %s", err)
	}
	log.Printf("[DEBUG] Updating CloudWatch Event Rule: %s", input)

	// IAM Roles take some time to propagate
	err = resource.Retry(30*time.Second, func() *resource.RetryError {
		_, err := conn.PutRule(input)
		pattern := regexp.MustCompile(`cannot be assumed by principal '[a-z]+\.amazonaws\.com'\.$`)
		if err != nil {
			if awsErr, ok := err.(awserr.Error); ok {
				if awsErr.Code() == "ValidationException" && pattern.MatchString(awsErr.Message()) {
					log.Printf("[DEBUG] Retrying update of CloudWatch Event Rule %q", *input.Name)
					return resource.RetryableError(err)
				}
			}
			return resource.NonRetryableError(err)
		}
		return nil
	})
	if err != nil {
		return fmt.Errorf("Updating CloudWatch Event Rule failed: %s", err)
	}

	if d.HasChange("is_enabled") && !d.Get("is_enabled").(bool) {
		log.Printf("[DEBUG] Disabling CloudWatch Event Rule %q", d.Id())
		_, err := conn.DisableRule(&events.DisableRuleInput{
			Name: aws.String(d.Id()),
		})
		if err != nil {
			return err
		}
		log.Printf("[DEBUG] CloudWatch Event Rule (%q) disabled", d.Id())
	}

	if d.HasChange("tags") {
		if err := setTagsCloudWatchEvents(conn, d, d.Get("arn").(string)); err != nil {
			return fmt.Errorf("Error updating tags for %s: %s", d.Id(), err)
		}
	}

	return resourceAwsCloudWatchEventRuleRead(d, meta)
}

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

	log.Printf("[INFO] Deleting CloudWatch Event Rule: %s", d.Id())
	_, err := conn.DeleteRule(&events.DeleteRuleInput{
		Name: aws.String(d.Id()),
	})
	if err != nil {
		return fmt.Errorf("Error deleting CloudWatch Event Rule: %s", err)
	}
	log.Println("[INFO] CloudWatch Event Rule deleted")

	return nil
}

func buildPutRuleInputStruct(d *schema.ResourceData, name string) (*events.PutRuleInput, error) {
	input := events.PutRuleInput{
		Name: aws.String(name),
	}
	if v, ok := d.GetOk("description"); ok {
		input.Description = aws.String(v.(string))
	}
	if v, ok := d.GetOk("event_pattern"); ok {
		pattern, err := structure.NormalizeJsonString(v)
		if err != nil {
			return nil, fmt.Errorf("event pattern contains an invalid JSON: %s", err)
		}
		input.EventPattern = aws.String(pattern)
	}
	if v, ok := d.GetOk("role_arn"); ok {
		input.RoleArn = aws.String(v.(string))
	}
	if v, ok := d.GetOk("schedule_expression"); ok {
		input.ScheduleExpression = aws.String(v.(string))
	}

	input.State = aws.String(getStringStateFromBoolean(d.Get("is_enabled").(bool)))

	return &input, nil
}

// State is represented as (ENABLED|DISABLED) in the API
func getBooleanStateFromString(state string) (bool, error) {
	if state == "ENABLED" {
		return true, nil
	} else if state == "DISABLED" {
		return false, nil
	}
	// We don't just blindly trust AWS as they tend to return
	// unexpected values in similar cases (different casing etc.)
	return false, fmt.Errorf("Failed converting state %q into boolean", state)
}

// State is represented as (ENABLED|DISABLED) in the API
func getStringStateFromBoolean(isEnabled bool) string {
	if isEnabled {
		return "ENABLED"
	}
	return "DISABLED"
}

func validateEventPatternValue() schema.SchemaValidateFunc {
	return func(v interface{}, k string) (ws []string, errors []error) {
		json, err := structure.NormalizeJsonString(v)
		if err != nil {
			errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err))

			// Invalid JSON? Return immediately,
			// there is no need to collect other
			// errors.
			return
		}

		// Check whether the normalized JSON is within the given length.
		if len(json) > 2048 {
			errors = append(errors, fmt.Errorf(
				"%q cannot be longer than %d characters: %q", k, 2048, json))
		}
		return
	}
}
<commit_msg>fix setting tags to state<commit_after>package aws

import (
	"fmt"
	"log"
	"regexp"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	events "github.com/aws/aws-sdk-go/service/cloudwatchevents"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/helper/structure"
	"github.com/hashicorp/terraform/helper/validation"
)

func resourceAwsCloudWatchEventRule() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsCloudWatchEventRuleCreate,
		Read:   resourceAwsCloudWatchEventRuleRead,
		Update: resourceAwsCloudWatchEventRuleUpdate,
		Delete: resourceAwsCloudWatchEventRuleDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:          schema.TypeString,
				Optional:      true,
				Computed:      true,
				ForceNew:      true,
				ConflictsWith: []string{"name_prefix"},
				ValidateFunc:  validateCloudWatchEventRuleName,
			},
			"name_prefix": {
				Type:         schema.TypeString,
				Optional:     true,
				ForceNew:     true,
				ValidateFunc: validateCloudWatchEventRuleName,
			},
			"schedule_expression": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringLenBetween(0, 256),
			},
			"event_pattern": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validateEventPatternValue(),
				StateFunc: func(v interface{}) string {
					json, _ := structure.NormalizeJsonString(v.(string))
					return json
				},
			},
			"description": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringLenBetween(0, 512),
			},
			"role_arn": {
				Type:         schema.TypeString,
				Optional:     true,
				ValidateFunc: validation.StringLenBetween(0, 1600),
			},
			"is_enabled": {
				Type:     schema.TypeBool,
				Optional: true,
				Default:  true,
			},
			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"tags": tagsSchema(),
		},
	}
}

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

	var name string
	if v, ok := d.GetOk("name"); ok {
		name = v.(string)
	} else if v, ok := d.GetOk("name_prefix"); ok {
		name = resource.PrefixedUniqueId(v.(string))
	} else {
		name = resource.UniqueId()
	}

	input, err := buildPutRuleInputStruct(d, name)
	if err != nil {
		return fmt.Errorf("Creating CloudWatch Event Rule failed: %s", err)
	}
	log.Printf("[DEBUG] Creating CloudWatch Event Rule: %s", input)

	// IAM Roles take some time to propagate
	var out *events.PutRuleOutput
	err = resource.Retry(30*time.Second, func() *resource.RetryError {
		var err error
		out, err = conn.PutRule(input)
		pattern := regexp.MustCompile(`cannot be assumed by principal '[a-z]+\.amazonaws\.com'\.$`)
		if err != nil {
			if awsErr, ok := err.(awserr.Error); ok {
				if awsErr.Code() == "ValidationException" && pattern.MatchString(awsErr.Message()) {
					log.Printf("[DEBUG] Retrying creation of CloudWatch Event Rule %q", *input.Name)
					return resource.RetryableError(err)
				}
			}
			return resource.NonRetryableError(err)
		}
		return nil
	})
	if err != nil {
		return fmt.Errorf("Creating CloudWatch Event Rule failed: %s", err)
	}

	d.Set("arn", out.RuleArn)
	d.SetId(*input.Name)

	log.Printf("[INFO] CloudWatch Event Rule %q created", *out.RuleArn)

	if err := setTagsCloudWatchEvents(conn, d, aws.StringValue(out.RuleArn)); err != nil {
		return fmt.Errorf("Error creating tags for %s: %s", d.Id(), err)
	}

	return resourceAwsCloudWatchEventRuleUpdate(d, meta)
}

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

	input := events.DescribeRuleInput{
		Name: aws.String(d.Id()),
	}
	log.Printf("[DEBUG] Reading CloudWatch Event Rule: %s", input)
	out, err := conn.DescribeRule(&input)
	if awsErr, ok := err.(awserr.Error); ok {
		if awsErr.Code() == "ResourceNotFoundException" {
			log.Printf("[WARN] Removing CloudWatch Event Rule %q because it's gone.", d.Id())
			d.SetId("")
			return nil
		}
	}
	if err != nil {
		return err
	}
	log.Printf("[DEBUG] Found Event Rule: %s", out)

	d.Set("arn", out.Arn)
	d.Set("description", out.Description)
	if out.EventPattern != nil {
		pattern, err := structure.NormalizeJsonString(*out.EventPattern)
		if err != nil {
			return fmt.Errorf("event pattern contains an invalid JSON: %s", err)
		}
		d.Set("event_pattern", pattern)
	}
	d.Set("name", out.Name)
	d.Set("role_arn", out.RoleArn)
	d.Set("schedule_expression", out.ScheduleExpression)

	boolState, err := getBooleanStateFromString(*out.State)
	if err != nil {
		return err
	}
	log.Printf("[DEBUG] Setting boolean state: %t", boolState)
	d.Set("is_enabled", boolState)
	if err := saveTagsCloudWatchEvents(conn, d, aws.StringValue(out.Arn)); err != nil {
		return fmt.Errorf("error setting tags: %s", err)
	}
	return nil
}

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

	if d.HasChange("is_enabled") && d.Get("is_enabled").(bool) {
		log.Printf("[DEBUG] Enabling CloudWatch Event Rule %q", d.Id())
		_, err := conn.EnableRule(&events.EnableRuleInput{
			Name: aws.String(d.Id()),
		})
		if err != nil {
			return err
		}
		log.Printf("[DEBUG] CloudWatch Event Rule (%q) enabled", d.Id())
	}

	input, err := buildPutRuleInputStruct(d, d.Id())
	if err != nil {
		return fmt.Errorf("Updating CloudWatch Event Rule failed: %s", err)
	}
	log.Printf("[DEBUG] Updating CloudWatch Event Rule: %s", input)

	// IAM Roles take some time to propagate
	err = resource.Retry(30*time.Second, func() *resource.RetryError {
		_, err := conn.PutRule(input)
		pattern := regexp.MustCompile(`cannot be assumed by principal '[a-z]+\.amazonaws\.com'\.$`)
		if err != nil {
			if awsErr, ok := err.(awserr.Error); ok {
				if awsErr.Code() == "ValidationException" && pattern.MatchString(awsErr.Message()) {
					log.Printf("[DEBUG] Retrying update of CloudWatch Event Rule %q", *input.Name)
					return resource.RetryableError(err)
				}
			}
			return resource.NonRetryableError(err)
		}
		return nil
	})
	if err != nil {
		return fmt.Errorf("Updating CloudWatch Event Rule failed: %s", err)
	}

	if d.HasChange("is_enabled") && !d.Get("is_enabled").(bool) {
		log.Printf("[DEBUG] Disabling CloudWatch Event Rule %q", d.Id())
		_, err := conn.DisableRule(&events.DisableRuleInput{
			Name: aws.String(d.Id()),
		})
		if err != nil {
			return err
		}
		log.Printf("[DEBUG] CloudWatch Event Rule (%q) disabled", d.Id())
	}

	if d.HasChange("tags") {
		if err := setTagsCloudWatchEvents(conn, d, d.Get("arn").(string)); err != nil {
			return fmt.Errorf("Error updating tags for %s: %s", d.Id(), err)
		}
	}

	return resourceAwsCloudWatchEventRuleRead(d, meta)
}

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

	log.Printf("[INFO] Deleting CloudWatch Event Rule: %s", d.Id())
	_, err := conn.DeleteRule(&events.DeleteRuleInput{
		Name: aws.String(d.Id()),
	})
	if err != nil {
		return fmt.Errorf("Error deleting CloudWatch Event Rule: %s", err)
	}
	log.Println("[INFO] CloudWatch Event Rule deleted")

	return nil
}

func buildPutRuleInputStruct(d *schema.ResourceData, name string) (*events.PutRuleInput, error) {
	input := events.PutRuleInput{
		Name: aws.String(name),
	}
	if v, ok := d.GetOk("description"); ok {
		input.Description = aws.String(v.(string))
	}
	if v, ok := d.GetOk("event_pattern"); ok {
		pattern, err := structure.NormalizeJsonString(v)
		if err != nil {
			return nil, fmt.Errorf("event pattern contains an invalid JSON: %s", err)
		}
		input.EventPattern = aws.String(pattern)
	}
	if v, ok := d.GetOk("role_arn"); ok {
		input.RoleArn = aws.String(v.(string))
	}
	if v, ok := d.GetOk("schedule_expression"); ok {
		input.ScheduleExpression = aws.String(v.(string))
	}

	input.State = aws.String(getStringStateFromBoolean(d.Get("is_enabled").(bool)))

	return &input, nil
}

// State is represented as (ENABLED|DISABLED) in the API
func getBooleanStateFromString(state string) (bool, error) {
	if state == "ENABLED" {
		return true, nil
	} else if state == "DISABLED" {
		return false, nil
	}
	// We don't just blindly trust AWS as they tend to return
	// unexpected values in similar cases (different casing etc.)
	return false, fmt.Errorf("Failed converting state %q into boolean", state)
}

// State is represented as (ENABLED|DISABLED) in the API
func getStringStateFromBoolean(isEnabled bool) string {
	if isEnabled {
		return "ENABLED"
	}
	return "DISABLED"
}

func validateEventPatternValue() schema.SchemaValidateFunc {
	return func(v interface{}, k string) (ws []string, errors []error) {
		json, err := structure.NormalizeJsonString(v)
		if err != nil {
			errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err))

			// Invalid JSON? Return immediately,
			// there is no need to collect other
			// errors.
			return
		}

		// Check whether the normalized JSON is within the given length.
		if len(json) > 2048 {
			errors = append(errors, fmt.Errorf(
				"%q cannot be longer than %d characters: %q", k, 2048, json))
		}
		return
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math"
	"math/big"
	"net/http"
	"os"
	"path"
	"strings"

	"archive/tar"
	"crypto/rand"

	"github.com/fsouza/go-dockerclient"
	"golang.org/x/net/webdav"
)

const (
	VERSION_TAG        = "v1"
	DOCKER_TAR_PREFIX  = "rootfs/"
	OWNER_PERM_RW      = 0600
	CONTENT_URL_PREFIX = "/api/" + VERSION_TAG + "/content/"
	METADATA_URL_PATH  = "/api/" + VERSION_TAG + "/metadata"
)

func handleTarStream(reader io.ReadCloser, destination string) {
	tr := tar.NewReader(reader)
	if tr != nil {
		err := processTarStream(tr, destination)
		if err != nil {
			log.Print(err)
		}
	} else {
		log.Printf("Unable to create image tar reader")
	}
	reader.Close()
}

func processTarStream(tr *tar.Reader, destination string) error {
	for {
		hdr, err := tr.Next()
		if err != nil {
			if err == io.EOF {
				return nil
			}
			return fmt.Errorf("Unable to extract container: %v\n", err)
		}

		hdrInfo := hdr.FileInfo()

		path := path.Join(destination, strings.TrimPrefix(hdr.Name, DOCKER_TAR_PREFIX))
		// Overriding permissions to allow writing content
		mode := hdrInfo.Mode() | OWNER_PERM_RW

		switch hdr.Typeflag {
		case tar.TypeDir:
			if err := os.Mkdir(path, mode); err != nil {
				if !os.IsExist(err) {
					return fmt.Errorf("Unable to create directory: %v", err)
				}
				err = os.Chmod(path, mode)
				if err != nil {
					return fmt.Errorf("Unable to update directory mode: %v", err)
				}
			}
		case tar.TypeReg, tar.TypeRegA:
			file, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, mode)
			if err != nil {
				return fmt.Errorf("Unable to create file: %v", err)
			}
			if _, err := io.Copy(file, tr); err != nil {
				file.Close()
				return fmt.Errorf("Unable to write into file: %v", err)
			}
			file.Close()
		default:
			// For now we're skipping anything else. Special device files and
			// symlinks are not needed or anyway probably incorrect.
		}
	}
}

func generateRandomName() string {
	n, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64))
	if err != nil {
		log.Fatalf("Unable to generate random container name: %v\n", err)
	}
	return fmt.Sprintf("image-inspector-%016x", n)
}

func main() {
	uri := flag.String("docker", "unix:///var/run/docker.sock", "Daemon socket to connect to")
	image := flag.String("image", "", "Docker image to inspect")
	path := flag.String("path", "", "Destination path for the image files")
	serve := flag.String("serve", "", "Host and port where to serve the image with webdav")

	flag.Parse()

	if *uri == "" {
		log.Fatalf("Docker socket connection must be specified")
	}
	if *image == "" {
		log.Fatalf("Docker image to inspect must be specified")
	}

	client, err := docker.NewClient(*uri)
	if err != nil {
		log.Fatalf("Unable to connect to docker daemon: %v\n", err)
	}

	log.Printf("Pulling image %s", *image)
	imagePullOption := docker.PullImageOptions{Repository: *image}
	imagePullAuth := docker.AuthConfiguration{} // TODO: support authentication
	if err := client.PullImage(imagePullOption, imagePullAuth); err != nil {
		log.Fatalf("Unable to pull docker image: %v\n", err)
	}

	// For security purpose we don't define any entrypoint and command
	container, err := client.CreateContainer(docker.CreateContainerOptions{
		Name: generateRandomName(),
		Config: &docker.Config{
			Image:      *image,
			Entrypoint: []string{""},
			Cmd:        []string{""},
		},
	})
	if err != nil {
		log.Fatalf("Unable to create docker container: %v\n", err)
	}

	containerMetadata, err := client.InspectContainer(container.ID)
	if err != nil {
		log.Fatalf("Unable to get docker container information: %v\n", err)
	}

	imageMetadata, err := client.InspectImage(containerMetadata.Image)
	if err != nil {
		log.Fatalf("Unable to get docker image information: %v\n", err)
	}

	if path != nil && *path != "" {
		err = os.Mkdir(*path, 0755)
		if err != nil {
			if !os.IsExist(err) {
				log.Fatalf("Unable to create destination path: %v\n", err)
			}
		}
	} else {
		// forcing to use /var/tmp because often it's not an in-memory tmpfs
		*path, err = ioutil.TempDir("/var/tmp", "image-inspector-")
		if err != nil {
			log.Fatalf("Unable to create temporary path: %v\n", err)
		}
	}

	reader, writer := io.Pipe()
	go handleTarStream(reader, *path)

	log.Printf("Extracting image %s to %s", *image, *path)
	_ = client.CopyFromContainer(docker.CopyFromContainerOptions{
		Container:    container.ID,
		OutputStream: writer,
		Resource:     "/",
	})

	_ = client.RemoveContainer(docker.RemoveContainerOptions{
		ID: container.ID,
	})

	if serve != nil && *serve != "" {
		log.Printf("Serving image content %s on webdav://%s%s", *path, *serve, CONTENT_URL_PREFIX)

		http.Handle(CONTENT_URL_PREFIX, webdav.StripPrefix(CONTENT_URL_PREFIX, &webdav.Handler{
			FileSystem: webdav.Dir(*path),
			LockSystem: webdav.NewMemLS(),
		}))

		http.HandleFunc(METADATA_URL_PATH, func(w http.ResponseWriter, r *http.Request) {
			body, err := json.Marshal(imageMetadata)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			w.Write(body)
		})

		log.Fatal(http.ListenAndServe(*serve, nil))
	}
}
<commit_msg>skipping image pull when image is available<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"math"
	"math/big"
	"net/http"
	"os"
	"path"
	"strings"

	"archive/tar"
	"crypto/rand"

	"github.com/fsouza/go-dockerclient"
	"golang.org/x/net/webdav"
)

const (
	VERSION_TAG        = "v1"
	DOCKER_TAR_PREFIX  = "rootfs/"
	OWNER_PERM_RW      = 0600
	CONTENT_URL_PREFIX = "/api/" + VERSION_TAG + "/content/"
	METADATA_URL_PATH  = "/api/" + VERSION_TAG + "/metadata"
)

func handleTarStream(reader io.ReadCloser, destination string) {
	tr := tar.NewReader(reader)
	if tr != nil {
		err := processTarStream(tr, destination)
		if err != nil {
			log.Print(err)
		}
	} else {
		log.Printf("Unable to create image tar reader")
	}
	reader.Close()
}

func processTarStream(tr *tar.Reader, destination string) error {
	for {
		hdr, err := tr.Next()
		if err != nil {
			if err == io.EOF {
				return nil
			}
			return fmt.Errorf("Unable to extract container: %v\n", err)
		}

		hdrInfo := hdr.FileInfo()

		path := path.Join(destination, strings.TrimPrefix(hdr.Name, DOCKER_TAR_PREFIX))
		// Overriding permissions to allow writing content
		mode := hdrInfo.Mode() | OWNER_PERM_RW

		switch hdr.Typeflag {
		case tar.TypeDir:
			if err := os.Mkdir(path, mode); err != nil {
				if !os.IsExist(err) {
					return fmt.Errorf("Unable to create directory: %v", err)
				}
				err = os.Chmod(path, mode)
				if err != nil {
					return fmt.Errorf("Unable to update directory mode: %v", err)
				}
			}
		case tar.TypeReg, tar.TypeRegA:
			file, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, mode)
			if err != nil {
				return fmt.Errorf("Unable to create file: %v", err)
			}
			if _, err := io.Copy(file, tr); err != nil {
				file.Close()
				return fmt.Errorf("Unable to write into file: %v", err)
			}
			file.Close()
		default:
			// For now we're skipping anything else. Special device files and
			// symlinks are not needed or anyway probably incorrect.
		}
	}
}

func generateRandomName() string {
	n, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64))
	if err != nil {
		log.Fatalf("Unable to generate random container name: %v\n", err)
	}
	return fmt.Sprintf("image-inspector-%016x", n)
}

func main() {
	uri := flag.String("docker", "unix:///var/run/docker.sock", "Daemon socket to connect to")
	image := flag.String("image", "", "Docker image to inspect")
	path := flag.String("path", "", "Destination path for the image files")
	serve := flag.String("serve", "", "Host and port where to serve the image with webdav")

	flag.Parse()

	if *uri == "" {
		log.Fatalf("Docker socket connection must be specified")
	}
	if *image == "" {
		log.Fatalf("Docker image to inspect must be specified")
	}

	client, err := docker.NewClient(*uri)
	if err != nil {
		log.Fatalf("Unable to connect to docker daemon: %v\n", err)
	}

	if _, err := client.InspectImage(*image); err != nil {
		log.Printf("Pulling image %s", *image)
		imagePullOption := docker.PullImageOptions{Repository: *image}
		imagePullAuth := docker.AuthConfiguration{} // TODO: support authentication
		if err := client.PullImage(imagePullOption, imagePullAuth); err != nil {
			log.Fatalf("Unable to pull docker image: %v\n", err)
		}
	} else {
		log.Printf("Image %s is available, skipping image pull", *image)
	}

	// For security purpose we don't define any entrypoint and command
	container, err := client.CreateContainer(docker.CreateContainerOptions{
		Name: generateRandomName(),
		Config: &docker.Config{
			Image:      *image,
			Entrypoint: []string{""},
			Cmd:        []string{""},
		},
	})
	if err != nil {
		log.Fatalf("Unable to create docker container: %v\n", err)
	}

	containerMetadata, err := client.InspectContainer(container.ID)
	if err != nil {
		log.Fatalf("Unable to get docker container information: %v\n", err)
	}

	imageMetadata, err := client.InspectImage(containerMetadata.Image)
	if err != nil {
		log.Fatalf("Unable to get docker image information: %v\n", err)
	}

	if path != nil && *path != "" {
		err = os.Mkdir(*path, 0755)
		if err != nil {
			if !os.IsExist(err) {
				log.Fatalf("Unable to create destination path: %v\n", err)
			}
		}
	} else {
		// forcing to use /var/tmp because often it's not an in-memory tmpfs
		*path, err = ioutil.TempDir("/var/tmp", "image-inspector-")
		if err != nil {
			log.Fatalf("Unable to create temporary path: %v\n", err)
		}
	}

	reader, writer := io.Pipe()
	go handleTarStream(reader, *path)

	log.Printf("Extracting image %s to %s", *image, *path)
	_ = client.CopyFromContainer(docker.CopyFromContainerOptions{
		Container:    container.ID,
		OutputStream: writer,
		Resource:     "/",
	})

	_ = client.RemoveContainer(docker.RemoveContainerOptions{
		ID: container.ID,
	})

	if serve != nil && *serve != "" {
		log.Printf("Serving image content %s on webdav://%s%s", *path, *serve, CONTENT_URL_PREFIX)

		http.Handle(CONTENT_URL_PREFIX, webdav.StripPrefix(CONTENT_URL_PREFIX, &webdav.Handler{
			FileSystem: webdav.Dir(*path),
			LockSystem: webdav.NewMemLS(),
		}))

		http.HandleFunc(METADATA_URL_PATH, func(w http.ResponseWriter, r *http.Request) {
			body, err := json.Marshal(imageMetadata)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			w.Write(body)
		})

		log.Fatal(http.ListenAndServe(*serve, nil))
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 The etcd 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 integration

import (
	"context"
	"reflect"
	"strings"
	"testing"

	"go.etcd.io/etcd/v3/integration"
	"go.etcd.io/etcd/v3/pkg/testutil"
	"go.etcd.io/etcd/v3/pkg/types"
)

func TestMemberList(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	capi := clus.RandClient()

	resp, err := capi.MemberList(context.Background())
	if err != nil {
		t.Fatalf("failed to list member %v", err)
	}

	if len(resp.Members) != 3 {
		t.Errorf("number of members = %d, want %d", len(resp.Members), 3)
	}
}

func TestMemberAdd(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	capi := clus.RandClient()

	urls := []string{"http://127.0.0.1:1234"}
	resp, err := capi.MemberAdd(context.Background(), urls)
	if err != nil {
		t.Fatalf("failed to add member %v", err)
	}

	if !reflect.DeepEqual(resp.Member.PeerURLs, urls) {
		t.Errorf("urls = %v, want %v", urls, resp.Member.PeerURLs)
	}
}

func TestMemberAddWithExistingURLs(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	capi := clus.RandClient()

	resp, err := capi.MemberList(context.Background())
	if err != nil {
		t.Fatalf("failed to list member %v", err)
	}

	existingURL := resp.Members[0].PeerURLs[0]
	_, err = capi.MemberAdd(context.Background(), []string{existingURL})
	expectedErrKeywords := "Peer URLs already exists"
	if err == nil {
		t.Fatalf("expecting add member to fail, got no error")
	}
	if !strings.Contains(err.Error(), expectedErrKeywords) {
		t.Errorf("expecting error to contain %s, got %s", expectedErrKeywords, err.Error())
	}
}

func TestMemberRemove(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	capi := clus.Client(1)
	resp, err := capi.MemberList(context.Background())
	if err != nil {
		t.Fatalf("failed to list member %v", err)
	}

	rmvID := resp.Members[0].ID
	// indexes in capi member list don't necessarily match cluster member list;
	// find member that is not the client to remove
	for _, m := range resp.Members {
		mURLs, _ := types.NewURLs(m.PeerURLs)
		if !reflect.DeepEqual(mURLs, clus.Members[1].ServerConfig.PeerURLs) {
			rmvID = m.ID
			break
		}
	}

	_, err = capi.MemberRemove(context.Background(), rmvID)
	if err != nil {
		t.Fatalf("failed to remove member %v", err)
	}

	resp, err = capi.MemberList(context.Background())
	if err != nil {
		t.Fatalf("failed to list member %v", err)
	}

	if len(resp.Members) != 2 {
		t.Errorf("number of members = %d, want %d", len(resp.Members), 2)
	}
}

func TestMemberUpdate(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	capi := clus.RandClient()
	resp, err := capi.MemberList(context.Background())
	if err != nil {
		t.Fatalf("failed to list member %v", err)
	}

	urls := []string{"http://127.0.0.1:1234"}
	_, err = capi.MemberUpdate(context.Background(), resp.Members[0].ID, urls)
	if err != nil {
		t.Fatalf("failed to update member %v", err)
	}

	resp, err = capi.MemberList(context.Background())
	if err != nil {
		t.Fatalf("failed to list member %v", err)
	}

	if !reflect.DeepEqual(resp.Members[0].PeerURLs, urls) {
		t.Errorf("urls = %v, want %v", urls, resp.Members[0].PeerURLs)
	}
}

func TestMemberAddUpdateWrongURLs(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer clus.Terminate(t)

	capi := clus.RandClient()
	tt := [][]string{
		// missing protocol scheme
		{"://127.0.0.1:2379"},
		// unsupported scheme
		{"mailto://127.0.0.1:2379"},
		// not conform to host:port
		{"http://127.0.0.1"},
		// contain a path
		{"http://127.0.0.1:2379/path"},
		// first path segment in URL cannot contain colon
		{"127.0.0.1:1234"},
		// URL scheme must be http, https, unix, or unixs
		{"localhost:1234"},
	}
	for i := range tt {
		_, err := capi.MemberAdd(context.Background(), tt[i])
		if err == nil {
			t.Errorf("#%d: MemberAdd err = nil, but error", i)
		}
		_, err = capi.MemberUpdate(context.Background(), 0, tt[i])
		if err == nil {
			t.Errorf("#%d: MemberUpdate err = nil, but error", i)
		}
	}
}

func TestMemberAddForLearner(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	capi := clus.RandClient()

	urls := []string{"http://127.0.0.1:1234"}
	resp, err := capi.MemberAddAsLearner(context.Background(), urls)
	if err != nil {
		t.Fatalf("failed to add member %v", err)
	}

	if !resp.Member.IsLearner {
		t.Errorf("Added a member as learner, got resp.Member.IsLearner = %v", resp.Member.IsLearner)
	}
}

func TestMemberPromoteForLearner(t *testing.T) {
	// TODO test not ready learner promotion.
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)
	// TODO change the random client to client that talk to leader directly.
	capi := clus.RandClient()

	urls := []string{"http://127.0.0.1:1234"}
	isLearner := true
	resp, err := capi.MemberAddAsLearner(context.Background(), urls)
	if err != nil {
		t.Fatalf("failed to add member %v", err)
	}

	if !resp.Member.IsLearner {
		t.Errorf("Added a member as learner, got resp.Member.IsLearner = %v", resp.Member.IsLearner)
	}

	learners, err := clus.GetLearnerMembers()
	if err != nil {
		t.Fatalf("failed to get the learner members in cluster: %v", err)
	}
	if len(learners) != 1 {
		t.Errorf("Added 1 learner node to cluster, got %d", len(learners))
	}
	_, err = capi.MemberPromote(context.Background(), resp.Member.ID)

	if err != nil {
		t.Fatalf("failed to promote member error: %v", err)
	}

	learners, err = clus.GetLearnerMembers()
	if err != nil {
		t.Fatalf("failed to get the number of learners in cluster: %v", err)
	}
	if len(learners) != 0 {
		t.Errorf("learner promoted, expect 0 learner, got %d", len(learners))
	}

}
<commit_msg>clientv3/integration: fix cluster tests<commit_after>// Copyright 2016 The etcd 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 integration

import (
	"context"
	"reflect"
	"strings"
	"testing"

	"go.etcd.io/etcd/v3/integration"
	"go.etcd.io/etcd/v3/pkg/testutil"
	"go.etcd.io/etcd/v3/pkg/types"
)

func TestMemberList(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	capi := clus.RandClient()

	resp, err := capi.MemberList(context.Background())
	if err != nil {
		t.Fatalf("failed to list member %v", err)
	}

	if len(resp.Members) != 3 {
		t.Errorf("number of members = %d, want %d", len(resp.Members), 3)
	}
}

func TestMemberAdd(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	capi := clus.RandClient()

	urls := []string{"http://127.0.0.1:1234"}
	resp, err := capi.MemberAdd(context.Background(), urls)
	if err != nil {
		t.Fatalf("failed to add member %v", err)
	}

	if !reflect.DeepEqual(resp.Member.PeerURLs, urls) {
		t.Errorf("urls = %v, want %v", urls, resp.Member.PeerURLs)
	}
}

func TestMemberAddWithExistingURLs(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	capi := clus.RandClient()

	resp, err := capi.MemberList(context.Background())
	if err != nil {
		t.Fatalf("failed to list member %v", err)
	}

	existingURL := resp.Members[0].PeerURLs[0]
	_, err = capi.MemberAdd(context.Background(), []string{existingURL})
	expectedErrKeywords := "Peer URLs already exists"
	if err == nil {
		t.Fatalf("expecting add member to fail, got no error")
	}
	if !strings.Contains(err.Error(), expectedErrKeywords) {
		t.Errorf("expecting error to contain %s, got %s", expectedErrKeywords, err.Error())
	}
}

func TestMemberRemove(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	capi := clus.Client(1)
	resp, err := capi.MemberList(context.Background())
	if err != nil {
		t.Fatalf("failed to list member %v", err)
	}

	rmvID := resp.Members[0].ID
	// indexes in capi member list don't necessarily match cluster member list;
	// find member that is not the client to remove
	for _, m := range resp.Members {
		mURLs, _ := types.NewURLs(m.PeerURLs)
		if !reflect.DeepEqual(mURLs, clus.Members[1].ServerConfig.PeerURLs) {
			rmvID = m.ID
			break
		}
	}

	_, err = capi.MemberRemove(context.Background(), rmvID)
	if err != nil {
		t.Fatalf("failed to remove member %v", err)
	}

	resp, err = capi.MemberList(context.Background())
	if err != nil {
		t.Fatalf("failed to list member %v", err)
	}

	if len(resp.Members) != 2 {
		t.Errorf("number of members = %d, want %d", len(resp.Members), 2)
	}
}

func TestMemberUpdate(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	capi := clus.RandClient()
	resp, err := capi.MemberList(context.Background())
	if err != nil {
		t.Fatalf("failed to list member %v", err)
	}

	urls := []string{"http://127.0.0.1:1234"}
	_, err = capi.MemberUpdate(context.Background(), resp.Members[0].ID, urls)
	if err != nil {
		t.Fatalf("failed to update member %v", err)
	}

	resp, err = capi.MemberList(context.Background())
	if err != nil {
		t.Fatalf("failed to list member %v", err)
	}

	if !reflect.DeepEqual(resp.Members[0].PeerURLs, urls) {
		t.Errorf("urls = %v, want %v", urls, resp.Members[0].PeerURLs)
	}
}

func TestMemberAddUpdateWrongURLs(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
	defer clus.Terminate(t)

	capi := clus.RandClient()
	tt := [][]string{
		// missing protocol scheme
		{"://127.0.0.1:2379"},
		// unsupported scheme
		{"mailto://127.0.0.1:2379"},
		// not conform to host:port
		{"http://127.0.0.1"},
		// contain a path
		{"http://127.0.0.1:2379/path"},
		// first path segment in URL cannot contain colon
		{"127.0.0.1:1234"},
		// URL scheme must be http, https, unix, or unixs
		{"localhost:1234"},
	}
	for i := range tt {
		_, err := capi.MemberAdd(context.Background(), tt[i])
		if err == nil {
			t.Errorf("#%d: MemberAdd err = nil, but error", i)
		}
		_, err = capi.MemberUpdate(context.Background(), 0, tt[i])
		if err == nil {
			t.Errorf("#%d: MemberUpdate err = nil, but error", i)
		}
	}
}

func TestMemberAddForLearner(t *testing.T) {
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	capi := clus.RandClient()

	urls := []string{"http://127.0.0.1:1234"}
	resp, err := capi.MemberAddAsLearner(context.Background(), urls)
	if err != nil {
		t.Fatalf("failed to add member %v", err)
	}

	if !resp.Member.IsLearner {
		t.Errorf("Added a member as learner, got resp.Member.IsLearner = %v", resp.Member.IsLearner)
	}

	numberOfLearners := 0
	for _, m := range resp.Members {
		if m.IsLearner {
			numberOfLearners++
		}
	}
	if numberOfLearners != 1 {
		t.Errorf("Added 1 learner node to cluster, got %d", numberOfLearners)
	}
}

func TestMemberPromoteForLearner(t *testing.T) {
	// TODO test not ready learner promotion.
	defer testutil.AfterTest(t)

	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)
	// TODO change the random client to client that talk to leader directly.
	capi := clus.RandClient()

	urls := []string{"http://127.0.0.1:1234"}
	memberAddResp, err := capi.MemberAddAsLearner(context.Background(), urls)
	if err != nil {
		t.Fatalf("failed to add member %v", err)
	}

	if !memberAddResp.Member.IsLearner {
		t.Fatalf("Added a member as learner, got resp.Member.IsLearner = %v", memberAddResp.Member.IsLearner)
	}
	learnerID := memberAddResp.Member.ID

	numberOfLearners := 0
	for _, m := range memberAddResp.Members {
		if m.IsLearner {
			numberOfLearners++
		}
	}
	if numberOfLearners != 1 {
		t.Fatalf("Added 1 learner node to cluster, got %d", numberOfLearners)
	}

	memberPromoteResp, err := capi.MemberPromote(context.Background(), learnerID)
	if err != nil {
		t.Fatalf("failed to promote member: %v", err)
	}

	numberOfLearners = 0
	for _, m := range memberPromoteResp.Members {
		if m.IsLearner {
			numberOfLearners++
		}
	}
	if numberOfLearners != 0 {
		t.Errorf("learner promoted, expect 0 learner, got %d", numberOfLearners)
	}
}
<|endoftext|>


<commit_before>package replication

import (
	"encoding/hex"
	"fmt"
	"io"
)

// we don't parse all event, so some we will use GenericEvent instead
type GenericEvent struct {
	Data []byte
}

func (e *GenericEvent) Dump(w io.Writer) {
	fmt.Fprintf(w, "Event data: \n%s", hex.Dump(e.Data))
	fmt.Fprintln(w)
}

func (e *GenericEvent) Decode(data []byte) error {
	e.Data = make([]byte, len(data))
	copy(e.Data, data)

	return nil
}

//below events are generic events, maybe later I will consider handle some.

type StartEventV3 struct {
	Version         uint16
	ServerVersion   [50]byte
	CreateTimestamp uint32
}

type StopEvent struct{}

type LoadEvent struct {
	SlaveProxyID uint32
	ExecTime     uint32
	SkipLines    uint32
	TableNameLen uint8
	SchemaLen    uint8
	NumFileds    uint32
	FieldTerm    uint8
	EnclosedBy   uint8
	LineTerm     uint8
	LineStart    uint8
	EscapedBy    uint8
	OptFlags     uint8
	EmptyFlags   uint8

	//len = 1 * NumFields
	FieldNameLengths []byte

	//len = sum(FieldNameLengths) + NumFields
	//array of nul-terminated strings
	FieldNames []byte

	//len = TableNameLen + 1, nul-terminated string
	TableName []byte

	//len = SchemaLen + 1, nul-terminated string
	SchemaName []byte

	//string.NUL
	FileName []byte
}

type NewLoadEvent struct {
	SlaveProxyID  uint32
	ExecTime      uint32
	SkipLines     uint32
	TableNameLen  uint8
	SchemaLen     uint8
	NumFields     uint32
	FieldTermLen  uint8
	FieldTerm     []byte
	EnclosedByLen uint8
	EnclosedBy    []byte
	LineTermLen   uint8
	LineTerm      []byte
	LineStartLen  uint8
	LineStart     []byte
	EscapedByLen  uint8
	EscapedBy     []byte
	OptFlags      uint8

	//len = 1 * NumFields
	FieldNameLengths []byte

	//len = sum(FieldNameLengths) + NumFields
	//array of nul-terminated strings
	FieldNames []byte

	//len = TableNameLen, nul-terminated string
	TableName []byte

	//len = SchemaLen, nul-terminated string
	SchemaName []byte

	//string.EOF
	FileName []byte
}

type CreateFileEvent struct {
	FileID    uint32
	BlockData []byte
}

type AppendBlockEvent struct {
	FileID    uint32
	BlockData []byte
}

type ExecLoadEvent struct {
	FileID uint32
}

type BeginLoadQueryEvent struct {
	FileID    uint32
	BlockData []byte
}

type ExecuteLoadQueryEvent struct {
	SlaveProxyID     uint32
	ExecutionTime    uint32
	SchemaLength     uint8
	ErrorCode        uint16
	StatusVarsLength uint16

	FileID           uint32
	StartPos         uint32
	EndPos           uint32
	DupHandlingFlags uint8
}

type DeleteFileEvent struct {
	FileID uint32
}

type RandEvent struct {
	Seed1 uint64
	Seed2 uint64
}

type IntVarEvent struct {
	Type  uint8
	Value uint64
}

type UserVarEvent struct {
	NameLength uint32
	Name       []byte
	IsNull     uint8

	//if not is null
	Type        uint8
	Charset     uint32
	ValueLength uint32
	Value       []byte

	//if more data
	Flags uint8
}

type IncidentEvent struct {
	Type          uint16
	MessageLength uint8
	Message       []byte
}

type HeartbeatEvent struct {
}
<commit_msg>comment unnecessary struct<commit_after>package replication

import (
	"encoding/hex"
	"fmt"
	"io"
)

// we don't parse all event, so some we will use GenericEvent instead
type GenericEvent struct {
	Data []byte
}

func (e *GenericEvent) Dump(w io.Writer) {
	fmt.Fprintf(w, "Event data: \n%s", hex.Dump(e.Data))
	fmt.Fprintln(w)
}

func (e *GenericEvent) Decode(data []byte) error {
	e.Data = make([]byte, len(data))
	copy(e.Data, data)

	return nil
}

//below events are generic events, maybe later I will consider handle some.

// type StartEventV3 struct {
// 	Version         uint16
// 	ServerVersion   [50]byte
// 	CreateTimestamp uint32
// }

// type StopEvent struct{}

// type LoadEvent struct {
// 	SlaveProxyID uint32
// 	ExecTime     uint32
// 	SkipLines    uint32
// 	TableNameLen uint8
// 	SchemaLen    uint8
// 	NumFileds    uint32
// 	FieldTerm    uint8
// 	EnclosedBy   uint8
// 	LineTerm     uint8
// 	LineStart    uint8
// 	EscapedBy    uint8
// 	OptFlags     uint8
// 	EmptyFlags   uint8

// 	//len = 1 * NumFields
// 	FieldNameLengths []byte

// 	//len = sum(FieldNameLengths) + NumFields
// 	//array of nul-terminated strings
// 	FieldNames []byte

// 	//len = TableNameLen + 1, nul-terminated string
// 	TableName []byte

// 	//len = SchemaLen + 1, nul-terminated string
// 	SchemaName []byte

// 	//string.NUL
// 	FileName []byte
// }

// type NewLoadEvent struct {
// 	SlaveProxyID  uint32
// 	ExecTime      uint32
// 	SkipLines     uint32
// 	TableNameLen  uint8
// 	SchemaLen     uint8
// 	NumFields     uint32
// 	FieldTermLen  uint8
// 	FieldTerm     []byte
// 	EnclosedByLen uint8
// 	EnclosedBy    []byte
// 	LineTermLen   uint8
// 	LineTerm      []byte
// 	LineStartLen  uint8
// 	LineStart     []byte
// 	EscapedByLen  uint8
// 	EscapedBy     []byte
// 	OptFlags      uint8

// 	//len = 1 * NumFields
// 	FieldNameLengths []byte

// 	//len = sum(FieldNameLengths) + NumFields
// 	//array of nul-terminated strings
// 	FieldNames []byte

// 	//len = TableNameLen, nul-terminated string
// 	TableName []byte

// 	//len = SchemaLen, nul-terminated string
// 	SchemaName []byte

// 	//string.EOF
// 	FileName []byte
// }

// type CreateFileEvent struct {
// 	FileID    uint32
// 	BlockData []byte
// }

// type AppendBlockEvent struct {
// 	FileID    uint32
// 	BlockData []byte
// }

// type ExecLoadEvent struct {
// 	FileID uint32
// }

// type BeginLoadQueryEvent struct {
// 	FileID    uint32
// 	BlockData []byte
// }

// type ExecuteLoadQueryEvent struct {
// 	SlaveProxyID     uint32
// 	ExecutionTime    uint32
// 	SchemaLength     uint8
// 	ErrorCode        uint16
// 	StatusVarsLength uint16

// 	FileID           uint32
// 	StartPos         uint32
// 	EndPos           uint32
// 	DupHandlingFlags uint8
// }

// type DeleteFileEvent struct {
// 	FileID uint32
// }

// type RandEvent struct {
// 	Seed1 uint64
// 	Seed2 uint64
// }

// type IntVarEvent struct {
// 	Type  uint8
// 	Value uint64
// }

// type UserVarEvent struct {
// 	NameLength uint32
// 	Name       []byte
// 	IsNull     uint8

// 	//if not is null
// 	Type        uint8
// 	Charset     uint32
// 	ValueLength uint32
// 	Value       []byte

// 	//if more data
// 	Flags uint8
// }

// type IncidentEvent struct {
// 	Type          uint16
// 	MessageLength uint8
// 	Message       []byte
// }

// type HeartbeatEvent struct {
// }
<|endoftext|>


<commit_before>package interaction

import (
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"socialapi/models"
	"socialapi/workers/api/modules/helpers"
)

func prepareInteraction(u *url.URL, req *models.Interaction) (*models.Interaction, error) {
	messageId, err := helpers.GetURIInt64(u, "id")
	if err != nil {
		return nil, errors.New("Couldnt get mesage id from URI")
	}

	if req.AccountId == 0 {
		return nil, errors.New("AccountId is not set")
	}

	interactionType := u.Query().Get("type")
	//if interaction is not in the allowed interations
	if _, ok := models.AllowedInteractions[interactionType]; !ok {
		return nil, errors.New(fmt.Sprintf("interaction not allowed - %s", interactionType))
	}

	req.MessageId = messageId
	req.TypeConstant = interactionType
	return req, nil
}

func Add(u *url.URL, h http.Header, req *models.Interaction) (int, http.Header, interface{}, error) {
	var err error
	req, err = prepareInteraction(u, req)
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	// to-do check uniqness before saving
	if err := req.Create(); err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	return helpers.NewOKResponse(req)
}

func Delete(u *url.URL, h http.Header, req *models.Interaction) (int, http.Header, interface{}, error) {
	var err error
	req, err = prepareInteraction(u, req)
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	if err := req.Delete(); err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	// yes it is deleted but not removed completely from our system
	return helpers.NewOKResponse(nil)
}

func List(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	messageId, err := helpers.GetURIInt64(u, "id")
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	query := helpers.GetQuery(u)
	if query.Type == "" {
		query.Type = "like"
	}

	i := models.NewInteraction()
	// set message id
	i.MessageId = messageId

	list, err := i.List(query)
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	return helpers.HandleResultAndError(
		models.AccountOldsIdByIds(list),
	)
}
<commit_msg>Social: change function name<commit_after>package interaction

import (
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"socialapi/models"
	"socialapi/workers/api/modules/helpers"
)

func prepareInteraction(u *url.URL, req *models.Interaction) (*models.Interaction, error) {
	messageId, err := helpers.GetURIInt64(u, "id")
	if err != nil {
		return nil, errors.New("Couldnt get mesage id from URI")
	}

	if req.AccountId == 0 {
		return nil, errors.New("AccountId is not set")
	}

	interactionType := u.Query().Get("type")
	//if interaction is not in the allowed interations
	if _, ok := models.AllowedInteractions[interactionType]; !ok {
		return nil, errors.New(fmt.Sprintf("interaction not allowed - %s", interactionType))
	}

	req.MessageId = messageId
	req.TypeConstant = interactionType
	return req, nil
}

func Add(u *url.URL, h http.Header, req *models.Interaction) (int, http.Header, interface{}, error) {
	var err error
	req, err = prepareInteraction(u, req)
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	// to-do check uniqness before saving
	if err := req.Create(); err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	return helpers.NewOKResponse(req)
}

func Delete(u *url.URL, h http.Header, req *models.Interaction) (int, http.Header, interface{}, error) {
	var err error
	req, err = prepareInteraction(u, req)
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	if err := req.Delete(); err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	// yes it is deleted but not removed completely from our system
	return helpers.NewOKResponse(nil)
}

func List(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	messageId, err := helpers.GetURIInt64(u, "id")
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	query := helpers.GetQuery(u)
	if query.Type == "" {
		query.Type = "like"
	}

	i := models.NewInteraction()
	// set message id
	i.MessageId = messageId

	list, err := i.List(query)
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	return helpers.HandleResultAndError(
		models.FetchAccountOldsIdByIdsFromCache(list),
	)
}
<|endoftext|>


<commit_before>/*
 * MinIO Client (C) 2020 MinIO, Inc.
 *
 * 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 cmd

import (
	"fmt"
	"sort"
	"strings"
	"time"

	"github.com/dustin/go-humanize"
	"github.com/fatih/color"
	"github.com/minio/cli"
	json "github.com/minio/mc/pkg/colorjson"
	"github.com/minio/mc/pkg/probe"
	"github.com/minio/minio/pkg/console"
	"github.com/minio/minio/pkg/madmin"
)

var adminBandwidthInfoCmdFlags = []cli.Flag{
	cli.StringFlag{
		Name:  "unit",
		Value: "b",
		Usage: "[b|bi|B|Bi] Display bandwidth in bits (IEC [bi] or SI [b]) or bytes (IEC [Bi] or SI [B])",
	},
}

var adminBwInfoCmd = cli.Command{
	Name:         "bandwidth",
	Usage:        "Show bandwidth info for buckets on the MinIO server in bits or bytes per second. Ki,Bi,Mi,Gi represent IEC units.",
	Action:       mainAdminBwInfo,
	Before:       setGlobalsFromContext,
	OnUsageError: onUsageError,
	Flags:        append(globalFlags, adminBandwidthInfoCmdFlags...),
	CustomHelpTemplate: `NAME:
  {{.HelpName}} - {{.Usage}}

USAGE:
  {{.HelpName}} FLAGS TARGET

FLAGS:
  {{range .VisibleFlags}}{{.}}
  {{end}}
EXAMPLES:
  1. Show the bandwidth usage for all the buckets in a MinIO server setup
     {{.Prompt}} {{.HelpName}} play/
  2. Show the bandwidth usage for the bucket 'source-bucket' in a MinIO server setup
     {{.Prompt}} {{.HelpName}} play/source-bucket
`,
}

func printTable(report madmin.Report, bits bool, iec bool) {
	bucketMaxLength := 63
	bucketColLength := 6
	var bucketKeys []string
	for bucket := range report.Report.BucketStats {
		if len(bucket) <= bucketMaxLength && len(bucket) > bucketColLength {
			bucketColLength = len(bucket)
		}
		bucketKeys = append(bucketKeys, bucket)
	}
	sort.Strings(bucketKeys)
	dspOrder := []col{colGreen} // Header
	for i := 0; i < len(report.Report.BucketStats); i++ {
		dspOrder = append(dspOrder, colGrey)
	}
	var printColors []*color.Color
	for _, c := range dspOrder {
		printColors = append(printColors, getPrintCol(c))
	}
	unit := "BitsPerSecond"
	if !bits {
		unit = "BytesPerSecond"
	}
	cellText := make([][]string, len(report.Report.BucketStats)+1) // 1 for the header
	tbl := console.NewTable(printColors, []bool{false, false, false}, 5)
	bucketTitle := fmt.Sprintf("%-16v", "Bucket")
	cellText[0] = []string{
		bucketTitle,
		"Max Bandwidth " + unit,
		"Current Bandwidth " + unit,
	}
	tbl.HeaderRowSeparator = true
	index := 1

	for _, bucket := range bucketKeys {
		values := report.Report.BucketStats[bucket]
		if len(bucket) > bucketMaxLength {
			bucket = bucket[:bucketMaxLength] + ".."
		}
		var mul uint64
		mul = 1
		if bits {
			mul = 8
		}
		limit := humanize.Bytes(uint64(values.LimitInBytesPerSecond) * mul)
		current := humanize.Bytes(uint64(values.CurrentBandwidthInBytesPerSecond) * mul)
		if iec {
			limit = humanize.IBytes(uint64(values.LimitInBytesPerSecond) * mul)
			current = humanize.IBytes(uint64(values.CurrentBandwidthInBytesPerSecond) * mul)
		}
		if bits {
			limit = strings.ToLower(limit)
			current = strings.ToLower(current)
		}
		cellText[index] = []string{
			bucket,
			limit,
			current,
		}
		index++
	}
	if len(report.Report.BucketStats) > 0 {
		err := tbl.DisplayTable(cellText)
		if err != nil {
			console.Error(err)
		}
	}
}
func checkAdminBwInfoSyntax(ctx *cli.Context) {
	u := ctx.String("unit")
	if u != "bi" &&
		u != "b" &&
		u != "Bi" &&
		u != "B" &&
		u != "" {
		cli.ShowCommandHelpAndExit(ctx, "bandwidth", globalErrorExitStatus)
	}
	if len(ctx.Args()) > 1 || len(ctx.Args()) == 0 {
		cli.ShowCommandHelpAndExit(ctx, "bandwidth", globalErrorExitStatus)
	}
}

func mainAdminBwInfo(ctx *cli.Context) {
	checkAdminBwInfoSyntax(ctx)
	aliasURL, bucket := getAliasAndBucket(ctx)
	client := getClient(aliasURL)
	reportCh := client.GetBucketBandwidth(globalContext, bucket)
	firstPrint := true
	bandwidthUnitsString := ctx.String("unit")
	for {
		select {
		case report := <-reportCh:
			if len(report.Report.BucketStats) == 0 {
				continue
			}
			if report.Err != nil {
				if strings.Contains(report.Err.Error(), "EOF") {
					continue
				}
				console.Error(report.Err)
			}
			printBandwidth(report, firstPrint, bandwidthUnitsString == "bi" || bandwidthUnitsString == "b",
				bandwidthUnitsString == "bi" || bandwidthUnitsString == "Bi")
			firstPrint = false
		case <-globalContext.Done():
			return
		}
	}
}

func printBandwidth(report madmin.Report, firstPrint bool, bits bool, iec bool) {
	rewindLines := len(report.Report.BucketStats) + 4
	if firstPrint {
		rewindLines = 0
	}
	if globalJSON {
		reportJSON, e := json.MarshalIndent(report, "", "  ")
		fatalIf(probe.NewError(e), "Unable to marshal to JSON")
		console.Println(string(reportJSON))
		time.Sleep(1 * time.Second)
		return
	}
	if len(report.Report.BucketStats) > 0 {
		console.RewindLines(rewindLines)
		// For the next iteration, rewind lines
		printTable(report, bits, iec)
	}
	time.Sleep(1 * time.Second)
}
<commit_msg>improve bandwidth monitor UI (#3680)<commit_after>/*
 * MinIO Client (C) 2020 MinIO, Inc.
 *
 * 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 cmd

import (
	"fmt"
	"sort"
	"strings"
	"time"

	"github.com/dustin/go-humanize"
	"github.com/fatih/color"
	"github.com/minio/cli"
	json "github.com/minio/mc/pkg/colorjson"
	"github.com/minio/mc/pkg/probe"
	"github.com/minio/minio/pkg/console"
	"github.com/minio/minio/pkg/madmin"
)

var adminBandwidthInfoCmdFlags = []cli.Flag{
	cli.StringFlag{
		Name:  "unit",
		Value: "b",
		Usage: "[b|bi|B|Bi] Display bandwidth in bits (IEC [bi] or SI [b]) or bytes (IEC [Bi] or SI [B])",
	},
}

var adminBwInfoCmd = cli.Command{
	Name:         "bandwidth",
	Usage:        "Show bandwidth info for buckets on the MinIO server in bits or bytes per second. Ki,Bi,Mi,Gi represent IEC units.",
	Action:       mainAdminBwInfo,
	Before:       setGlobalsFromContext,
	OnUsageError: onUsageError,
	Flags:        append(globalFlags, adminBandwidthInfoCmdFlags...),
	CustomHelpTemplate: `NAME:
  {{.HelpName}} - {{.Usage}}

USAGE:
  {{.HelpName}} FLAGS TARGET

FLAGS:
  {{range .VisibleFlags}}{{.}}
  {{end}}
EXAMPLES:
  1. Show the bandwidth usage for all the buckets in a MinIO server setup
     {{.Prompt}} {{.HelpName}} play/
  2. Show the bandwidth usage for the bucket 'source-bucket' in a MinIO server setup
     {{.Prompt}} {{.HelpName}} play/source-bucket
`,
}

func printTable(report madmin.Report, bits bool, iec bool) {
	bucketMaxLength := 63
	bucketColLength := 6
	var bucketKeys []string
	for bucket := range report.Report.BucketStats {
		if len(bucket) <= bucketMaxLength && len(bucket) > bucketColLength {
			bucketColLength = len(bucket)
		}
		bucketKeys = append(bucketKeys, bucket)
	}
	sort.Strings(bucketKeys)
	dspOrder := []col{colGreen} // Header
	for i := 0; i < len(report.Report.BucketStats); i++ {
		dspOrder = append(dspOrder, colGrey)
	}
	var printColors []*color.Color
	for _, c := range dspOrder {
		printColors = append(printColors, getPrintCol(c))
	}

	cellText := make([][]string, len(report.Report.BucketStats)+1) // 1 for the header
	tbl := console.NewTable(printColors, []bool{false, false, false}, 0)
	bucketTitle := fmt.Sprintf("%-16v", "Bucket")
	cellText[0] = []string{
		bucketTitle,
		"Configured Max Bandwidth",
		"Current Bandwidth",
	}
	tbl.HeaderRowSeparator = true
	index := 1

	for _, bucket := range bucketKeys {
		values := report.Report.BucketStats[bucket]
		if len(bucket) > bucketMaxLength {
			bucket = bucket[:bucketMaxLength] + ".."
		}
		var mul uint64
		mul = 1
		if bits {
			mul = 8
		}
		limit := humanize.Bytes(uint64(values.LimitInBytesPerSecond) * mul)
		current := humanize.Bytes(uint64(values.CurrentBandwidthInBytesPerSecond) * mul)
		if iec {
			limit = humanize.IBytes(uint64(values.LimitInBytesPerSecond)*mul) + "/sec"
			current = humanize.IBytes(uint64(values.CurrentBandwidthInBytesPerSecond)*mul) + "/sec"
		}
		if bits {
			limit = strings.ToLower(limit) + "/sec"
			current = strings.ToLower(current) + "/sec"
		}
		if values.LimitInBytesPerSecond == 0 {
			limit = "N/A" // N/A means cluster bandwidth is not configured
		}
		cellText[index] = []string{
			bucket,
			limit,
			current,
		}
		index++
	}
	if len(report.Report.BucketStats) > 0 {
		err := tbl.DisplayTable(cellText)
		if err != nil {
			console.Error(err)
		}
	}
}
func checkAdminBwInfoSyntax(ctx *cli.Context) {
	u := ctx.String("unit")
	if u != "bi" &&
		u != "b" &&
		u != "Bi" &&
		u != "B" &&
		u != "" {
		cli.ShowCommandHelpAndExit(ctx, "bandwidth", globalErrorExitStatus)
	}
	if len(ctx.Args()) > 1 || len(ctx.Args()) == 0 {
		cli.ShowCommandHelpAndExit(ctx, "bandwidth", globalErrorExitStatus)
	}
}

func mainAdminBwInfo(ctx *cli.Context) {
	checkAdminBwInfoSyntax(ctx)
	aliasURL, bucket := getAliasAndBucket(ctx)
	client := getClient(aliasURL)
	reportCh := client.GetBucketBandwidth(globalContext, bucket)
	firstPrint := true
	bandwidthUnitsString := ctx.String("unit")
	for {
		select {
		case report := <-reportCh:
			if len(report.Report.BucketStats) == 0 {
				continue
			}
			if report.Err != nil {
				if strings.Contains(report.Err.Error(), "EOF") {
					continue
				}
				console.Error(report.Err)
			}
			printBandwidth(report, firstPrint, bandwidthUnitsString == "bi" || bandwidthUnitsString == "b",
				bandwidthUnitsString == "bi" || bandwidthUnitsString == "Bi")
			firstPrint = false
		case <-globalContext.Done():
			return
		}
	}
}

func printBandwidth(report madmin.Report, firstPrint bool, bits bool, iec bool) {
	rewindLines := len(report.Report.BucketStats) + 4
	if firstPrint {
		rewindLines = 0
	}
	if globalJSON {
		reportJSON, e := json.MarshalIndent(report, "", "  ")
		fatalIf(probe.NewError(e), "Unable to marshal to JSON")
		console.Println(string(reportJSON))
		time.Sleep(1 * time.Second)
		return
	}
	if len(report.Report.BucketStats) > 0 {
		console.RewindLines(rewindLines)
		// For the next iteration, rewind lines
		printTable(report, bits, iec)
	}
	time.Sleep(1 * time.Second)
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes 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 run

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/spf13/cobra"

	"github.com/kubernetes-incubator/apiserver-builder/cmd/apiserver-boot/boot/build"
	"github.com/kubernetes-incubator/apiserver-builder/cmd/apiserver-boot/boot/util"
)

var localCmd = &cobra.Command{
	Use:   "local",
	Short: "run the etcd, apiserver and controller-manager",
	Long:  `run the etcd, apiserver and controller-manager`,
	Example: `# Regenerate code and build binaries.  Then run them locally.
apiserver-boot run local

# Check the api versions of the locally running server
kubectl --kubeconfig kubeconfig api-versions

# Run locally without rebuilding
apiserver-boot run local --build=false

# Create an instance and fetch it
nano -w samples/<type>.yaml
kubectl --kubeconfig kubeconfig apply -f samples/<type>.yaml
kubectl --kubeconfig kubeconfig get <type>`,
	Run: RunLocal,
}

var etcd string
var config string
var printapiserver bool
var printcontrollermanager bool
var printetcd bool
var buildBin bool

var server string
var controllermanager string

func AddLocal(cmd *cobra.Command) {
	localCmd.Flags().StringVar(&server, "apiserver", "", "path to apiserver binary to run")
	localCmd.Flags().StringVar(&controllermanager, "controller-manager", "", "path to controller-manager binary to run")
	localCmd.Flags().StringVar(&etcd, "etcd", "", "if non-empty, use this etcd instead of starting a new one")

	localCmd.Flags().StringVar(&config, "config", "kubeconfig", "path to the kubeconfig to write for using kubectl")

	localCmd.Flags().BoolVar(&printapiserver, "print-apiserver", true, "if true, pipe the apiserver stdout and stderr")
	localCmd.Flags().BoolVar(&printcontrollermanager, "print-controller-manager", true, "if true, pipe the controller-manager stdout and stderr")
	localCmd.Flags().BoolVar(&printetcd, "printetcd", false, "if true, pipe the etcd stdout and stderr")
	localCmd.Flags().BoolVar(&buildBin, "build", true, "if true, build the binaries before running")

	cmd.AddCommand(localCmd)
}

func RunLocal(cmd *cobra.Command, args []string) {
	if buildBin {
		build.RunBuildExecutables(cmd, args)
	}

	WriteKubeConfig()

	// Start etcd
	if len(etcd) == 0 {
		etcd = "http://localhost:2379"
		etcdCmd := RunEtcd()
		defer etcdCmd.Process.Kill()
	}

	time.Sleep(time.Second * 2)

	// Start apiserver
	go RunApiserver()

	time.Sleep(time.Second * 2)

	// Start controller manager
	go RunControllerManager()

	fmt.Printf("to test the server run `kubectl --kubeconfig %s api-versions`\n", config)
	select {} // wait forever
}

func RunEtcd() *exec.Cmd {
	etcdCmd := exec.Command("etcd")
	if printetcd {
		etcdCmd.Stderr = os.Stderr
		etcdCmd.Stdout = os.Stdout
	}

	fmt.Printf("%s\n", strings.Join(etcdCmd.Args, " "))
	go func() {
		err := etcdCmd.Run()
		if err != nil {
			log.Fatalf("Failed to run etcd %v", err)
			os.Exit(-1)
		}
	}()
	return etcdCmd
}

func RunApiserver() *exec.Cmd {
	if len(server) == 0 {
		server = "bin/apiserver"
	}

	apiserverCmd := exec.Command(server,
		"--delegated-auth=false",
		fmt.Sprintf("--etcd-servers=%s", etcd),
		"--secure-port=9443",
		"--print-bearer-token",
	)
	fmt.Printf("%s\n", strings.Join(apiserverCmd.Args, " "))
	if printapiserver {
		apiserverCmd.Stderr = os.Stderr
		apiserverCmd.Stdout = os.Stdout
	}

	err := apiserverCmd.Run()
	if err != nil {
		log.Fatalf("Failed to run apiserver %v", err)
		os.Exit(-1)
	}

	return apiserverCmd
}

func RunControllerManager() *exec.Cmd {
	if len(controllermanager) == 0 {
		controllermanager = "bin/controller-manager"
	}
	controllerManagerCmd := exec.Command(controllermanager,
		fmt.Sprintf("--kubeconfig=%s", config),
	)
	fmt.Printf("%s\n", strings.Join(controllerManagerCmd.Args, " "))
	if printcontrollermanager {
		controllerManagerCmd.Stderr = os.Stderr
		controllerManagerCmd.Stdout = os.Stdout
	}

	err := controllerManagerCmd.Run()
	if err != nil {
		log.Fatalf("Failed to run controller-manager %v", err)
		os.Exit(-1)
	}

	return controllerManagerCmd
}

func WriteKubeConfig() {
	// Write a kubeconfig
	dir, err := os.Getwd()
	if err != nil {
		log.Fatalf("Cannot get working directory %v", err)
		os.Exit(-1)
	}
	path := filepath.Join(dir, "apiserver.local.config", "certificates", "apiserver")
	util.WriteIfNotFound(config, "kubeconfig-template", configTemplate, path)
}

var configTemplate = `
apiVersion: v1
clusters:
- cluster:
    certificate-authority: {{ . }}.crt
    server: https://localhost:9443
  name: apiserver
contexts:
- context:
    cluster: apiserver
    user: apiserver
  name: apiserver
current-context: apiserver
kind: Config
preferences: {}
users:
- name: apiserver
  user:
    client-certificate: {{ . }}.crt
    client-key: {{ . }}.key
`
<commit_msg>Stop printing the bearer token when starting a server locally<commit_after>/*
Copyright 2016 The Kubernetes 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 run

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/spf13/cobra"

	"github.com/kubernetes-incubator/apiserver-builder/cmd/apiserver-boot/boot/build"
	"github.com/kubernetes-incubator/apiserver-builder/cmd/apiserver-boot/boot/util"
)

var localCmd = &cobra.Command{
	Use:   "local",
	Short: "run the etcd, apiserver and controller-manager",
	Long:  `run the etcd, apiserver and controller-manager`,
	Example: `# Regenerate code and build binaries.  Then run them locally.
apiserver-boot run local

# Check the api versions of the locally running server
kubectl --kubeconfig kubeconfig api-versions

# Run locally without rebuilding
apiserver-boot run local --build=false

# Create an instance and fetch it
nano -w samples/<type>.yaml
kubectl --kubeconfig kubeconfig apply -f samples/<type>.yaml
kubectl --kubeconfig kubeconfig get <type>`,
	Run: RunLocal,
}

var etcd string
var config string
var printapiserver bool
var printcontrollermanager bool
var printetcd bool
var buildBin bool

var server string
var controllermanager string

func AddLocal(cmd *cobra.Command) {
	localCmd.Flags().StringVar(&server, "apiserver", "", "path to apiserver binary to run")
	localCmd.Flags().StringVar(&controllermanager, "controller-manager", "", "path to controller-manager binary to run")
	localCmd.Flags().StringVar(&etcd, "etcd", "", "if non-empty, use this etcd instead of starting a new one")

	localCmd.Flags().StringVar(&config, "config", "kubeconfig", "path to the kubeconfig to write for using kubectl")

	localCmd.Flags().BoolVar(&printapiserver, "print-apiserver", true, "if true, pipe the apiserver stdout and stderr")
	localCmd.Flags().BoolVar(&printcontrollermanager, "print-controller-manager", true, "if true, pipe the controller-manager stdout and stderr")
	localCmd.Flags().BoolVar(&printetcd, "printetcd", false, "if true, pipe the etcd stdout and stderr")
	localCmd.Flags().BoolVar(&buildBin, "build", true, "if true, build the binaries before running")

	cmd.AddCommand(localCmd)
}

func RunLocal(cmd *cobra.Command, args []string) {
	if buildBin {
		build.RunBuildExecutables(cmd, args)
	}

	WriteKubeConfig()

	// Start etcd
	if len(etcd) == 0 {
		etcd = "http://localhost:2379"
		etcdCmd := RunEtcd()
		defer etcdCmd.Process.Kill()
	}

	time.Sleep(time.Second * 2)

	// Start apiserver
	go RunApiserver()

	time.Sleep(time.Second * 2)

	// Start controller manager
	go RunControllerManager()

	fmt.Printf("to test the server run `kubectl --kubeconfig %s api-versions`\n", config)
	select {} // wait forever
}

func RunEtcd() *exec.Cmd {
	etcdCmd := exec.Command("etcd")
	if printetcd {
		etcdCmd.Stderr = os.Stderr
		etcdCmd.Stdout = os.Stdout
	}

	fmt.Printf("%s\n", strings.Join(etcdCmd.Args, " "))
	go func() {
		err := etcdCmd.Run()
		if err != nil {
			log.Fatalf("Failed to run etcd %v", err)
			os.Exit(-1)
		}
	}()
	return etcdCmd
}

func RunApiserver() *exec.Cmd {
	if len(server) == 0 {
		server = "bin/apiserver"
	}

	apiserverCmd := exec.Command(server,
		"--delegated-auth=false",
		fmt.Sprintf("--etcd-servers=%s", etcd),
		"--secure-port=9443",
	)
	fmt.Printf("%s\n", strings.Join(apiserverCmd.Args, " "))
	if printapiserver {
		apiserverCmd.Stderr = os.Stderr
		apiserverCmd.Stdout = os.Stdout
	}

	err := apiserverCmd.Run()
	if err != nil {
		log.Fatalf("Failed to run apiserver %v", err)
		os.Exit(-1)
	}

	return apiserverCmd
}

func RunControllerManager() *exec.Cmd {
	if len(controllermanager) == 0 {
		controllermanager = "bin/controller-manager"
	}
	controllerManagerCmd := exec.Command(controllermanager,
		fmt.Sprintf("--kubeconfig=%s", config),
	)
	fmt.Printf("%s\n", strings.Join(controllerManagerCmd.Args, " "))
	if printcontrollermanager {
		controllerManagerCmd.Stderr = os.Stderr
		controllerManagerCmd.Stdout = os.Stdout
	}

	err := controllerManagerCmd.Run()
	if err != nil {
		log.Fatalf("Failed to run controller-manager %v", err)
		os.Exit(-1)
	}

	return controllerManagerCmd
}

func WriteKubeConfig() {
	// Write a kubeconfig
	dir, err := os.Getwd()
	if err != nil {
		log.Fatalf("Cannot get working directory %v", err)
		os.Exit(-1)
	}
	path := filepath.Join(dir, "apiserver.local.config", "certificates", "apiserver")
	util.WriteIfNotFound(config, "kubeconfig-template", configTemplate, path)
}

var configTemplate = `
apiVersion: v1
clusters:
- cluster:
    certificate-authority: {{ . }}.crt
    server: https://localhost:9443
  name: apiserver
contexts:
- context:
    cluster: apiserver
    user: apiserver
  name: apiserver
current-context: apiserver
kind: Config
preferences: {}
users:
- name: apiserver
  user:
    client-certificate: {{ . }}.crt
    client-key: {{ . }}.key
`
<|endoftext|>