<commit_before>package goinsta

import (
	"encoding/json"
	"fmt"
	"strconv"
)

// Comments allows user to interact with media (item) comments.
// You can Add or Delete by index or by user name.
type Comments struct {
	item     *Item
	endpoint string
	err      error

	Items                          []Comment `json:"comments"`
	CommentCount                   int       `json:"comment_count"`
	Caption                        Caption   `json:"caption"`
	CaptionIsEdited                bool      `json:"caption_is_edited"`
	HasMoreComments                bool      `json:"has_more_comments"`
	HasMoreHeadloadComments        bool      `json:"has_more_headload_comments"`
	MediaHeaderDisplay             string    `json:"media_header_display"`
	DisplayRealtimeTypingIndicator bool      `json:"display_realtime_typing_indicator"`
	NextID                         string    `json:"next_max_id"`
	LastID                         string    `json:"next_min_id"`
	Status                         string    `json:"status"`

	//PreviewComments                []Comment   `json:"preview_comments"`
}

func (c *Comments) setValues() {
	for i := range c.Items {
		c.Items[i].inst = c.item.media.instagram()
	}
}

func newComments(item *Item) *Comments {
	c := &Comments{
		item: item,
	}
	return c
}

func (comments Comments) Error() error {
	return comments.err
}

// Disable disables comments in FeedMedia.
//
// See example: examples/media/commentDisable.go
func (comments *Comments) Disable() error {
	switch comments.item.media.(type) {
	case *StoryMedia:
		return fmt.Errorf("Incompatible type. Cannot use Disable() with StoryMedia type")
	default:
	}

	insta := comments.item.media.instagram()
	data, err := insta.prepareData(
		map[string]interface{}{
			"media_id": comments.item.ID,
		},
	)
	if err != nil {
		return err
	}

	_, err = insta.sendRequest(
		&reqOptions{
			Endpoint: fmt.Sprintf(urlCommentDisable, comments.item.ID),
			Query:    generateSignature(data),
			IsPost:   true,
		},
	)
	return err
}

// Enable enables comments in FeedMedia
//
// See example: examples/media/commentEnable.go
func (comments *Comments) Enable() error {
	switch comments.item.media.(type) {
	case *StoryMedia:
		return fmt.Errorf("Incompatible type. Cannot use Enable() with StoryMedia type")
	default:
	}

	insta := comments.item.media.instagram()
	data, err := insta.prepareData(
		map[string]interface{}{
			"media_id": comments.item.ID,
		},
	)
	if err != nil {
		return err
	}

	_, err = insta.sendRequest(
		&reqOptions{
			Endpoint: fmt.Sprintf(urlCommentEnable, comments.item.ID),
			Query:    generateSignature(data),
			IsPost:   true,
		},
	)
	return err
}

// Next allows comment pagination.
//
// This function support concurrency methods to get comments using Last and Next ID
//
// New comments are stored in Comments.Items
func (comments *Comments) Next() bool {
	if comments.err != nil {
		return false
	}

	item := comments.item
	insta := comments.item.media.instagram()
	data, err := insta.prepareData(
		map[string]interface{}{
			"can_support_threading": true,
			"max_id":                comments.NextID,
			"min_id":                comments.LastID,
		},
	)
	if err != nil {
		comments.err = err
		return false
	}

	endpoint := comments.endpoint

	body, err := insta.sendRequest(
		&reqOptions{
			Endpoint: endpoint,
			Query:    generateSignature(data),
			IsPost:   true,
		},
	)
	if err == nil {
		c := Comments{}
		err = json.Unmarshal(body, &c)
		if err == nil {
			*comments = c
			comments.endpoint = endpoint
			comments.item = item
			if !comments.HasMoreComments || comments.NextID == "" {
				comments.err = ErrNoMore
			}
			comments.setValues()
			return true
		}
	}
	comments.err = err
	return false
}

// Sync prepare Comments to receive comments.
// Use Next to receive comments.
//
// See example: examples/media/commentsSync.go
func (comments *Comments) Sync() {
	endpoint := fmt.Sprintf(urlCommentSync, comments.item.ID)
	comments.endpoint = endpoint
	return
}

// Add push a comment in media.
//
// If parent media is a Story this function will send a private message
// replying the Instagram story.
//
// See example: examples/media/commentsAdd.go
func (comments *Comments) Add(text string) (err error) {
	var opt *reqOptions
	item := comments.item
	insta := item.media.instagram()

	switch item.media.(type) {
	case *StoryMedia:
		to, err := prepareRecipients(item)
		if err != nil {
			return err
		}

		query := insta.prepareDataQuery(
			map[string]interface{}{
				"recipient_users": to,
				"action":          "send_item",
				"media_id":        item.ID,
				"client_context":  generateUUID(),
				"text":            text,
				"entry":           "reel",
				"reel_id":         item.User.ID,
			},
		)
		opt = &reqOptions{
			Connection: "keep-alive",
			Endpoint:   fmt.Sprintf("%s?media_type=%s", urlReplyStory, item.MediaToString()),
			Query:      query,
			IsPost:     true,
		}
	case *FeedMedia: // normal media
		var data string
		data, err = insta.prepareData(
			map[string]interface{}{
				"comment_text": text,
			},
		)
		opt = &reqOptions{
			Endpoint: fmt.Sprintf(urlCommentAdd, item.Pk),
			Query:    generateSignature(data),
			IsPost:   true,
		}
	}
	if err != nil {
		return err
	}

	// ignoring response
	_, err = insta.sendRequest(opt)
	return err
}

// Del deletes comment.
func (comments *Comments) Del(comment *Comment) error {
	insta := comments.item.media.instagram()

	data, err := insta.prepareData()
	if err != nil {
		return err
	}
	id := comment.getid()

	_, err = insta.sendRequest(
		&reqOptions{
			Endpoint: fmt.Sprintf(urlCommentDelete, comments.item.ID, id),
			Query:    generateSignature(data),
			IsPost:   true,
		},
	)
	return err
}

// DelByID removes comment using id.
//
// See example: examples/media/commentsDelByID.go
func (comments *Comments) DelByID(id string) error {
	return comments.Del(&Comment{idstr: id})
}

// DelMine removes all of your comments limited by parsed parameter.
//
// If limit is <= 0 DelMine will delete all your comments.
//
// See example: examples/media/commentsDelMine.go
func (comments *Comments) DelMine(limit int) error {
	i := 0
	if limit <= 0 {
		i = limit - 1
	}
	comments.Sync()

	insta := comments.item.media.instagram()
floop:
	for comments.Next() {
		for _, c := range comments.Items {
			if c.UserID == insta.Account.ID || c.User.ID == insta.Account.ID {
				if i >= limit {
					break floop
				}
				comments.Del(&c)
				i++
			}
		}
	}
	if err := comments.Error(); err != nil && err != ErrNoMore {
		return err
	}
	return nil
}

type Comment struct {
	inst *Instagram

	ID                             int64     `json:"pk"`
	idstr                          string    `json:"-"`
	Text                           string    `json:"text"`
	Type                           int       `json:"type"`
	User                           User      `json:"user"`
	UserID                         int64     `json:"user_id"`
	BitFlags                       int       `json:"bit_flags"`
	ChildCommentCount              int       `json:"child_comment_count"`
	CommentIndex                   int       `json:"comment_index"`
	CommentLikeCount               int       `json:"comment_like_count"`
	ContentType                    string    `json:"content_type"`
	CreatedAt                      int       `json:"created_at"`
	CreatedAtUtc                   int       `json:"created_at_utc"`
	DidReportAsSpam                bool      `json:"did_report_as_spam"`
	HasLikedComment                bool      `json:"has_liked_comment"`
	InlineComposerDisplayCondition string    `json:"inline_composer_display_condition"`
	OtherPreviewUsers              []User    `json:"other_preview_users"`
	PreviewChildComments           []Comment `json:"preview_child_comments"`
	Status                         string    `json:"status"`
}

func (c Comment) getid() string {
	switch {
	case c.ID == 0:
		return c.idstr
	case c.idstr == "":
		return strconv.FormatInt(c.ID, 10)
	}
	return ""
}

// Like likes comment.
func (c *Comment) Like() error {
	data, err := c.inst.prepareData()
	if err != nil {
		return err
	}

	_, err = c.inst.sendRequest(
		&reqOptions{
			Endpoint: fmt.Sprintf(urlCommentLike, c.getid()),
			Query:    generateSignature(data),
			IsPost:   true,
		},
	)
	return err
}

// Unlike unlikes comment.
func (c *Comment) Unlike() error {
	data, err := c.inst.prepareData()
	if err != nil {
		return err
	}

	_, err = c.inst.sendRequest(
		&reqOptions{
			Endpoint: fmt.Sprintf(urlCommentUnlike, c.getid()),
			Query:    generateSignature(data),
			IsPost:   true,
		},
	)
	return err
}
<commit_msg>Fixed comment retrieving error<commit_after>package goinsta

import (
	"encoding/json"
	"fmt"
	"strconv"
)

// Comments allows user to interact with media (item) comments.
// You can Add or Delete by index or by user name.
type Comments struct {
	item     *Item
	endpoint string
	err      error

	Items                          []Comment `json:"comments"`
	CommentCount                   int       `json:"comment_count"`
	Caption                        Caption   `json:"caption"`
	CaptionIsEdited                bool      `json:"caption_is_edited"`
	HasMoreComments                bool      `json:"has_more_comments"`
	HasMoreHeadloadComments        bool      `json:"has_more_headload_comments"`
	ThreadingEnabled               bool      `json:"threading_enabled"`
	MediaHeaderDisplay             string    `json:"media_header_display"`
	InitiateAtTop                  bool      `json:"initiate_at_top"`
	InsertNewCommentToTop          bool      `json:"insert_new_comment_to_top"`
	PreviewComments                []Comment `json:"preview_comments"`
	NextMinID                      string    `json:"next_min_id"`
	CommentLikesEnabled            bool      `json:"comment_likes_enabled"`
	DisplayRealtimeTypingIndicator bool      `json:"display_realtime_typing_indicator"`
	Status                         string    `json:"status"`
	//PreviewComments                []Comment `json:"preview_comments"`
}

func (c *Comments) setValues() {
	for i := range c.Items {
		c.Items[i].setValues(c.item.media.instagram())
	}
}

func newComments(item *Item) *Comments {
	c := &Comments{
		item: item,
	}
	return c
}

func (comments Comments) Error() error {
	return comments.err
}

// Disable disables comments in FeedMedia.
//
// See example: examples/media/commentDisable.go
func (comments *Comments) Disable() error {
	switch comments.item.media.(type) {
	case *StoryMedia:
		return fmt.Errorf("Incompatible type. Cannot use Disable() with StoryMedia type")
	default:
	}

	insta := comments.item.media.instagram()
	data, err := insta.prepareData(
		map[string]interface{}{
			"media_id": comments.item.ID,
		},
	)
	if err != nil {
		return err
	}

	_, err = insta.sendRequest(
		&reqOptions{
			Endpoint: fmt.Sprintf(urlCommentDisable, comments.item.ID),
			Query:    generateSignature(data),
			IsPost:   true,
		},
	)
	return err
}

// Enable enables comments in FeedMedia
//
// See example: examples/media/commentEnable.go
func (comments *Comments) Enable() error {
	switch comments.item.media.(type) {
	case *StoryMedia:
		return fmt.Errorf("Incompatible type. Cannot use Enable() with StoryMedia type")
	default:
	}

	insta := comments.item.media.instagram()
	data, err := insta.prepareData(
		map[string]interface{}{
			"media_id": comments.item.ID,
		},
	)
	if err != nil {
		return err
	}

	_, err = insta.sendRequest(
		&reqOptions{
			Endpoint: fmt.Sprintf(urlCommentEnable, comments.item.ID),
			Query:    generateSignature(data),
			IsPost:   true,
		},
	)
	return err
}

// Next allows comment pagination.
//
// This function support concurrency methods to get comments using Last and Next ID
//
// New comments are stored in Comments.Items
func (comments *Comments) Next() bool {
	if comments.err != nil {
		return false
	}

	item := comments.item
	insta := item.media.instagram()
	endpoint := comments.endpoint

	body, err := insta.sendRequest(
		&reqOptions{
			Endpoint: endpoint,
			Query: map[string]string{
				"can_support_threading": "true",
				"min_id":                comments.NextMinID,
			},
		},
	)
	if err == nil {
		c := Comments{}
		err = json.Unmarshal(body, &c)
		if err == nil {
			*comments = c
			comments.endpoint = endpoint
			comments.item = item
			if !comments.HasMoreComments || comments.NextMinID == "" {
				comments.err = ErrNoMore
			}
			comments.setValues()
			return true
		}
	}
	comments.err = err
	return false
}

// Sync prepare Comments to receive comments.
// Use Next to receive comments.
//
// See example: examples/media/commentsSync.go
func (comments *Comments) Sync() {
	endpoint := fmt.Sprintf(urlCommentSync, comments.item.ID)
	comments.endpoint = endpoint
	return
}

// Add push a comment in media.
//
// If parent media is a Story this function will send a private message
// replying the Instagram story.
//
// See example: examples/media/commentsAdd.go
func (comments *Comments) Add(text string) (err error) {
	var opt *reqOptions
	item := comments.item
	insta := item.media.instagram()

	switch item.media.(type) {
	case *StoryMedia:
		to, err := prepareRecipients(item)
		if err != nil {
			return err
		}

		query := insta.prepareDataQuery(
			map[string]interface{}{
				"recipient_users": to,
				"action":          "send_item",
				"media_id":        item.ID,
				"client_context":  generateUUID(),
				"text":            text,
				"entry":           "reel",
				"reel_id":         item.User.ID,
			},
		)
		opt = &reqOptions{
			Connection: "keep-alive",
			Endpoint:   fmt.Sprintf("%s?media_type=%s", urlReplyStory, item.MediaToString()),
			Query:      query,
			IsPost:     true,
		}
	case *FeedMedia: // normal media
		var data string
		data, err = insta.prepareData(
			map[string]interface{}{
				"comment_text": text,
			},
		)
		opt = &reqOptions{
			Endpoint: fmt.Sprintf(urlCommentAdd, item.Pk),
			Query:    generateSignature(data),
			IsPost:   true,
		}
	}
	if err != nil {
		return err
	}

	// ignoring response
	_, err = insta.sendRequest(opt)
	return err
}

// Del deletes comment.
func (comments *Comments) Del(comment *Comment) error {
	insta := comments.item.media.instagram()

	data, err := insta.prepareData()
	if err != nil {
		return err
	}
	id := comment.getid()

	_, err = insta.sendRequest(
		&reqOptions{
			Endpoint: fmt.Sprintf(urlCommentDelete, comments.item.ID, id),
			Query:    generateSignature(data),
			IsPost:   true,
		},
	)
	return err
}

// DelByID removes comment using id.
//
// See example: examples/media/commentsDelByID.go
func (comments *Comments) DelByID(id string) error {
	return comments.Del(&Comment{idstr: id})
}

// DelMine removes all of your comments limited by parsed parameter.
//
// If limit is <= 0 DelMine will delete all your comments.
//
// See example: examples/media/commentsDelMine.go
func (comments *Comments) DelMine(limit int) error {
	i := 0
	if limit <= 0 {
		i = limit - 1
	}
	comments.Sync()

	insta := comments.item.media.instagram()
floop:
	for comments.Next() {
		for _, c := range comments.Items {
			if c.UserID == insta.Account.ID || c.User.ID == insta.Account.ID {
				if i >= limit {
					break floop
				}
				comments.Del(&c)
				i++
			}
		}
	}
	if err := comments.Error(); err != nil && err != ErrNoMore {
		return err
	}
	return nil
}

type Comment struct {
	inst *Instagram

	ID                             int64     `json:"pk"`
	idstr                          string    `json:"-"`
	Text                           string    `json:"text"`
	Type                           int       `json:"type"`
	User                           User      `json:"user"`
	UserID                         int64     `json:"user_id"`
	BitFlags                       int       `json:"bit_flags"`
	ChildCommentCount              int       `json:"child_comment_count"`
	CommentIndex                   int       `json:"comment_index"`
	CommentLikeCount               int       `json:"comment_like_count"`
	ContentType                    string    `json:"content_type"`
	CreatedAt                      int       `json:"created_at"`
	CreatedAtUtc                   int       `json:"created_at_utc"`
	DidReportAsSpam                bool      `json:"did_report_as_spam"`
	HasLikedComment                bool      `json:"has_liked_comment"`
	InlineComposerDisplayCondition string    `json:"inline_composer_display_condition"`
	OtherPreviewUsers              []User    `json:"other_preview_users"`
	PreviewChildComments           []Comment `json:"preview_child_comments"`
	NextMaxChildCursor             string    `json:"next_max_child_cursor,omitempty"`
	HasMoreTailChildComments       bool      `json:"has_more_tail_child_comments,omitempty"`
	NextMinChildCursor             string    `json:"next_min_child_cursor,omitempty"`
	HasMoreHeadChildComments       bool      `json:"has_more_head_child_comments,omitempty"`
	NumTailChildComments           int       `json:"num_tail_child_comments,omitempty"`
	NumHeadChildComments           int       `json:"num_head_child_comments,omitempty"`
	Status                         string    `json:"status"`
}

func (c *Comment) setValues(inst *Instagram) {
	c.User.inst = inst
	for i := range c.OtherPreviewUsers {
		c.OtherPreviewUsers[i].inst = inst
	}
	for i := range c.PreviewChildComments {
		c.PreviewChildComments[i].setValues(inst)
	}
}

func (c Comment) getid() string {
	switch {
	case c.ID == 0:
		return c.idstr
	case c.idstr == "":
		return strconv.FormatInt(c.ID, 10)
	}
	return ""
}

// Like likes comment.
func (c *Comment) Like() error {
	data, err := c.inst.prepareData()
	if err != nil {
		return err
	}

	_, err = c.inst.sendRequest(
		&reqOptions{
			Endpoint: fmt.Sprintf(urlCommentLike, c.getid()),
			Query:    generateSignature(data),
			IsPost:   true,
		},
	)
	return err
}

// Unlike unlikes comment.
func (c *Comment) Unlike() error {
	data, err := c.inst.prepareData()
	if err != nil {
		return err
	}

	_, err = c.inst.sendRequest(
		&reqOptions{
			Endpoint: fmt.Sprintf(urlCommentUnlike, c.getid()),
			Query:    generateSignature(data),
			IsPost:   true,
		},
	)
	return err
}
<|endoftext|>


<commit_before><commit_msg>Fix RespPeek.MarshalJSON to not stack overflow<commit_after><|endoftext|>


<commit_before>// Copyright (c) - Damien Fontaine <damien.fontaine@lineolia.net>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>

package config

import "strings"

//Server configuration
type Server struct {
	Port int
	URL  string
	Log  struct {
		File  string
		Level string
	}
	SSL struct {
		Key         string
		Certificate string
	}
	Jwt struct {
		Key string
	}
}

//ServerEnvironment configurations
type ServerEnvironment struct {
	Env map[string]Server
}

//UnmarshalYAML implements Unmarshaler. Avoid use of env in the YAML file.
func (se *ServerEnvironment) UnmarshalYAML(unmarshal func(interface{}) error) error {
	var aux struct {
		Env map[string]struct {
			Server Server
		}
	}
	if err := unmarshal(&aux.Env); err != nil {
		return err
	}
	se.Env = make(map[string]Server)
	for env, conf := range aux.Env {
		se.Env[env] = conf.Server
	}
	return nil
}

//GetEnvironment returns a Server configuration for the specified environment in parameter
func (se *ServerEnvironment) GetEnvironment(environment string) interface{} {
	for env, conf := range se.Env {
		if strings.Compare(environment, env) == 0 {
			return conf
		}
	}
	return nil
}

//GetServer returns a Server configurations
func GetServer(source interface{}, environment string) (server Server, err error) {
	var serverEnvironment ServerEnvironment
	i, err := Get(source, environment, &serverEnvironment)
	server = i.(Server)
	return
}
<commit_msg>Add admin email in server config<commit_after>// Copyright (c) - Damien Fontaine <damien.fontaine@lineolia.net>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>

package config

import "strings"

//Server configuration
type Server struct {
	Port  int
	URL   string
	Admin string
	Log   struct {
		File  string
		Level string
	}
	SSL struct {
		Key         string
		Certificate string
	}
	Jwt struct {
		Key string
	}
}

//ServerEnvironment configurations
type ServerEnvironment struct {
	Env map[string]Server
}

//UnmarshalYAML implements Unmarshaler. Avoid use of env in the YAML file.
func (se *ServerEnvironment) UnmarshalYAML(unmarshal func(interface{}) error) error {
	var aux struct {
		Env map[string]struct {
			Server Server
		}
	}
	if err := unmarshal(&aux.Env); err != nil {
		return err
	}
	se.Env = make(map[string]Server)
	for env, conf := range aux.Env {
		se.Env[env] = conf.Server
	}
	return nil
}

//GetEnvironment returns a Server configuration for the specified environment in parameter
func (se *ServerEnvironment) GetEnvironment(environment string) interface{} {
	for env, conf := range se.Env {
		if strings.Compare(environment, env) == 0 {
			return conf
		}
	}
	return nil
}

//GetServer returns a Server configurations
func GetServer(source interface{}, environment string) (server Server, err error) {
	var serverEnvironment ServerEnvironment
	i, err := Get(source, environment, &serverEnvironment)
	server = i.(Server)
	return
}
<|endoftext|>


<commit_before><commit_msg>Zero out mountFile and mountPoint after the event loop exits.<commit_after><|endoftext|>


<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package libkb

import (
	"sync"

	"golang.org/x/net/context"

	keybase1 "github.com/keybase/client/go/protocol/keybase1"
)

type Syncer interface {
	Contextifier
	sync.Locker
	loadFromStorage(keybase1.UID) error
	syncFromServer(keybase1.UID, SessionReader) error
	store(keybase1.UID) error
	needsLogin() bool
}

func RunSyncer(s Syncer, uid keybase1.UID, loggedIn bool, sr SessionReader) (err error) {
	if uid.IsNil() {
		return NotFoundError{"No UID given to syncer"}
	}

	// unnecessary for secret syncer, but possibly useful for tracker syncer.
	s.Lock()
	defer s.Unlock()

	s.G().Log.Debug("+ Syncer.Load(%s)", uid)
	defer func() {
		s.G().Log.Debug("- Syncer.Load(%s) -> %s", uid, ErrToOk(err))
	}()

	if err = s.loadFromStorage(uid); err != nil {
		return
	}

	if s.G().ConnectivityMonitor.IsConnected(context.Background()) != ConnectivityMonitorYes {
		s.G().Log.Debug("| not connected, won't sync with server")
		return
	}

	if s.needsLogin() && !loggedIn {
		s.G().Log.Debug("| Won't sync with server since we're not logged in")
		return
	}
	if err = s.syncFromServer(uid, sr); err != nil {
		return
	}
	if err = s.store(uid); err != nil {
		return
	}

	return
}
<commit_msg>Change connected check to hard no<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package libkb

import (
	"sync"

	"golang.org/x/net/context"

	keybase1 "github.com/keybase/client/go/protocol/keybase1"
)

type Syncer interface {
	Contextifier
	sync.Locker
	loadFromStorage(keybase1.UID) error
	syncFromServer(keybase1.UID, SessionReader) error
	store(keybase1.UID) error
	needsLogin() bool
}

func RunSyncer(s Syncer, uid keybase1.UID, loggedIn bool, sr SessionReader) (err error) {
	if uid.IsNil() {
		return NotFoundError{"No UID given to syncer"}
	}

	// unnecessary for secret syncer, but possibly useful for tracker syncer.
	s.Lock()
	defer s.Unlock()

	s.G().Log.Debug("+ Syncer.Load(%s)", uid)
	defer func() {
		s.G().Log.Debug("- Syncer.Load(%s) -> %s", uid, ErrToOk(err))
	}()

	if err = s.loadFromStorage(uid); err != nil {
		return
	}

	if s.G().ConnectivityMonitor.IsConnected(context.Background()) == ConnectivityMonitorNo {
		s.G().Log.Debug("| not connected, won't sync with server")
		return
	}

	if s.needsLogin() && !loggedIn {
		s.G().Log.Debug("| Won't sync with server since we're not logged in")
		return
	}
	if err = s.syncFromServer(uid, sr); err != nil {
		return
	}
	if err = s.store(uid); err != nil {
		return
	}

	return
}
<|endoftext|>


<commit_before>package main

import (
	"compress/gzip"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"sync"
	"time"

	"github.com/dustin/go-humanize"
)

var (
	verbose     = flag.Bool("v", false, "verbosity")
	concurrency = flag.Int("j", 2,
		"number of concurrent dumps")
	dbName = flag.String("db", "", "which db to dump (default: all)")
	noop   = flag.Bool("n", false, "if true, don't actually write dumps")
)

func init() {
	log.SetFlags(log.Lmicroseconds)
}

func maybeFatal(err error, fmt string, args ...interface{}) {
	if err != nil {
		log.Fatalf(fmt, args...)
	}
}

func listDatabases(u url.URL) []string {
	u.Path = "/_all_dbs"
	res, err := http.Get(u.String())
	maybeFatal(err, "Error listing databases: %v", err)
	defer res.Body.Close()

	rv := []string{}
	d := json.NewDecoder(res.Body)
	err = d.Decode(&rv)
	maybeFatal(err, "Error decoding database list: %v", err)
	return rv
}

func vlog(s string, a ...interface{}) {
	if *verbose {
		log.Printf(s, a...)
	}
}

func compress(w io.Writer) io.WriteCloser {
	z, err := gzip.NewWriterLevel(w, gzip.BestCompression)
	maybeFatal(err, "NewWriterLevel: %v", err)
	return z
}

func dumpOne(dbname, u string) (int64, error) {
	if *noop {
		return 0, nil
	}
	res, err := http.Get(u)
	if err != nil {
		return 0, err
	}
	defer res.Body.Close()

	if res.StatusCode != 200 {
		return 0, fmt.Errorf("HTTP Error: %v", res.Status)
	}

	outf, err := os.Create(dbname + ".json.gz")
	if err != nil {
		return 0, err
	}
	defer outf.Close()

	z := compress(outf)
	defer z.Close()
	return io.Copy(z, res.Body)
}

func dump(wg *sync.WaitGroup, u url.URL, ch <-chan string) {
	defer wg.Done()

	for db := range ch {
		start := time.Now()
		vlog("Dumping %v", db)
		u.Path = "/" + db + "/_dump"
		n, err := dumpOne(db, u.String())
		maybeFatal(err, "Error dumping %v: %v", u.String(), err)

		if !*noop {
			vlog("Dumped %v of %v in %v",
				humanize.Bytes(uint64(n)), db, time.Since(start))
		}
	}
}

func main() {
	flag.Parse()

	if flag.NArg() == 0 {
		log.Fatalf("Seriesly URL required")
	}

	u, err := url.Parse(flag.Arg(0))
	maybeFatal(err, "Parsing %v: %v", flag.Arg(0), err)

	wg := &sync.WaitGroup{}
	ch := make(chan string)

	for i := 0; i < *concurrency; i++ {
		wg.Add(1)
		go dump(wg, *u, ch)
	}

	if *dbName == "" {
		for _, db := range listDatabases(*u) {
			ch <- db
		}
	} else {
		ch <- *dbName
	}
	close(ch)

	wg.Wait()
}
<commit_msg>Added http tracking to dump tool<commit_after>package main

import (
	"compress/gzip"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"sync"
	"syscall"
	"time"

	"github.com/dustin/go-humanize"
	"github.com/dustin/httputil"
)

var (
	verbose     = flag.Bool("v", false, "verbosity")
	concurrency = flag.Int("j", 2,
		"number of concurrent dumps")
	dbName = flag.String("db", "", "which db to dump (default: all)")
	noop   = flag.Bool("n", false, "if true, don't actually write dumps")
)

const sigInfo = syscall.Signal(29)

func init() {
	log.SetFlags(log.Lmicroseconds)
}

func maybeFatal(err error, fmt string, args ...interface{}) {
	if err != nil {
		log.Fatalf(fmt, args...)
	}
}

func listDatabases(u url.URL) []string {
	u.Path = "/_all_dbs"
	res, err := http.Get(u.String())
	maybeFatal(err, "Error listing databases: %v", err)
	defer res.Body.Close()

	rv := []string{}
	d := json.NewDecoder(res.Body)
	err = d.Decode(&rv)
	maybeFatal(err, "Error decoding database list: %v", err)
	return rv
}

func vlog(s string, a ...interface{}) {
	if *verbose {
		log.Printf(s, a...)
	}
}

func compress(w io.Writer) io.WriteCloser {
	z, err := gzip.NewWriterLevel(w, gzip.BestCompression)
	maybeFatal(err, "NewWriterLevel: %v", err)
	return z
}

func dumpOne(dbname, u string) (int64, error) {
	if *noop {
		return 0, nil
	}
	res, err := http.Get(u)
	if err != nil {
		return 0, err
	}
	defer res.Body.Close()

	if res.StatusCode != 200 {
		return 0, fmt.Errorf("HTTP Error: %v", res.Status)
	}

	outf, err := os.Create(dbname + ".json.gz")
	if err != nil {
		return 0, err
	}
	defer outf.Close()

	z := compress(outf)
	defer z.Close()
	return io.Copy(z, res.Body)
}

func dump(wg *sync.WaitGroup, u url.URL, ch <-chan string) {
	defer wg.Done()

	for db := range ch {
		start := time.Now()
		vlog("Dumping %v", db)
		u.Path = "/" + db + "/_dump"
		n, err := dumpOne(db, u.String())
		maybeFatal(err, "Error dumping %v: %v", u.String(), err)

		if !*noop {
			vlog("Dumped %v of %v in %v",
				humanize.Bytes(uint64(n)), db, time.Since(start))
		}
	}
}

func main() {
	flag.Parse()

	httputil.InitHTTPTracker(false)

	if flag.NArg() == 0 {
		log.Fatalf("Seriesly URL required")
	}

	u, err := url.Parse(flag.Arg(0))
	maybeFatal(err, "Parsing %v: %v", flag.Arg(0), err)

	wg := &sync.WaitGroup{}
	ch := make(chan string)

	for i := 0; i < *concurrency; i++ {
		wg.Add(1)
		go dump(wg, *u, ch)
	}

	if *dbName == "" {
		for _, db := range listDatabases(*u) {
			ch <- db
		}
	} else {
		ch <- *dbName
	}
	close(ch)

	wg.Wait()
}
<|endoftext|>


<commit_before><commit_msg>Second round of PR changes.<commit_after><|endoftext|>


<commit_before><commit_msg>update login<commit_after><|endoftext|>


<commit_before>/*

kasper is a lightweight Kafka stream processing library.

*/

package kasper

import (
	"log"
	"sync"
	"time"

	"github.com/Shopify/sarama"
	"github.com/rcrowley/go-metrics"
)

// TopicProcessor desribes kafka topic processor
type TopicProcessor struct {
	config              *TopicProcessorConfig
	containerID         int
	client              sarama.Client
	producer            sarama.AsyncProducer
	offsetManager       sarama.OffsetManager
	partitionProcessors map[int32]*partitionProcessor
	inputTopics         []string
	partitions          []int
	shutdown            chan bool
	waitGroup           sync.WaitGroup
}

// MessageProcessor describes kafka message processor
type MessageProcessor interface {
	// Process message from Kafka input topics.
	// This is the function where you perform all needed actions, like
	// population KV stroage or producing Kafka output messages
	Process(IncomingMessage, Sender, Coordinator)
}

// NewTopicProcessor creates a new TopicProcessor with the given config.
// It requires a factory function that creates MessageProcessor instances and a container id.
// The container id must be a number between 0 and config.ContainerCount - 1.
func NewTopicProcessor(config *TopicProcessorConfig, makeProcessor func() MessageProcessor, containerID int) *TopicProcessor {
	if containerID < 0 || containerID >= config.ContainerCount {
		log.Fatalf("ContainerID expected to be between 0 and %d, got: %d", config.ContainerCount-1, containerID)
	}
	inputTopics := config.InputTopics
	brokerList := config.BrokerList
	for _, topic := range inputTopics {
		_, ok := config.TopicSerdes[topic]
		if !ok {
			log.Fatalf("Could not find Serde for topic '%s'", topic)
		}
	}
	saramaConfig := sarama.NewConfig()
	saramaConfig.Consumer.Offsets.Initial = sarama.OffsetOldest // TODO: make this configurable
	client, err := sarama.NewClient(brokerList, saramaConfig)
	if err != nil {
		log.Fatal(err)
	}
	partitions := config.partitionsForContainer(containerID)
	for _, partition := range partitions {
		_, ok := config.PartitionToContainerID[partition]
		if !ok {
			log.Fatalf("Could not find PartitionToContainerID mapping for partition %d", partition)
		}
	}
	offsetManager, err := sarama.NewOffsetManagerFromClient(config.kafkaConsumerGroup(), client)
	if err != nil {
		log.Fatal(err)
	}
	partitionProcessors := make(map[int32]*partitionProcessor, len(partitions))
	requiredAcks := config.Config.RequiredAcks
	producer := mustSetupProducer(config.BrokerList, config.producerClientID(containerID), requiredAcks)
	topicProcessor := TopicProcessor{
		config,
		containerID,
		client,
		producer,
		offsetManager,
		partitionProcessors,
		inputTopics,
		partitions,
		make(chan bool),
		sync.WaitGroup{},
	}
	for _, partition := range partitions {
		processor := makeProcessor()
		partitionProcessors[int32(partition)] = newPartitionProcessor(&topicProcessor, processor, partition)
	}
	return &topicProcessor
}

// Start launches a deferred routine for topic processing.
func (tp *TopicProcessor) Start() {
	tp.waitGroup.Add(1)
	go func() {
		defer tp.waitGroup.Done()
		tp.runLoop()
	}()
}

func (tp *TopicProcessor) runLoop() {
	consumerChan := tp.getConsumerMessagesChan()
	var tickerChan <-chan time.Time
	var ticker *time.Ticker

	if tp.config.markOffsetsAutomatically() {
		ticker = time.NewTicker(tp.config.AutoMarkOffsetsInterval)
		tickerChan = ticker.C
	} else {
		tickerChan = make(<-chan time.Time)
	}

	tp.waitGroup.Add(1)
	go func() {
		defer tp.waitGroup.Done()
		for err := range tp.producer.Errors() {
			tp.onProducerError(err)
		}
	}()

	for {
		select {
		case consumerMessage := <-consumerChan:
			tp.processConsumerMessage(consumerMessage, tickerChan)
		case msg, more := <-tp.producer.Successes():
			tp.onProducerAck(msg, more)
		case <-tickerChan:
			tp.onTick()
		case <-tp.shutdown:
			tp.onShutdown()
			return
		}
	}
}

func (tp *TopicProcessor) processConsumerMessage(consumerMessage *sarama.ConsumerMessage, tickerChan <-chan time.Time) {
	pp := tp.partitionProcessors[consumerMessage.Partition]
	for {
		if pp.isReadyForMessage(consumerMessage) {
			producerMessages := pp.process(consumerMessage)
			for len(producerMessages) > 0 {
				select {
				case tp.producer.Input() <- producerMessages[0]:
					producerMessages = producerMessages[1:]
				case msg, more := <-tp.producer.Successes():
					tp.onProducerAck(msg, more)
				case <-tickerChan:
					tp.onTick()
				}
			}
			pp.onProcessCompleted()
			break
		} else {
			select {
			case msg, more := <-tp.producer.Successes():
				tp.onProducerAck(msg, more)
			case <-tickerChan:
				tp.onTick()
			}
		}
	}
}

func (tp *TopicProcessor) onShutdown() {
	for _, pp := range tp.partitionProcessors {
		pp.onShutdown()
	}
	err := tp.producer.Close()
	if err != nil {
		log.Fatal(err)
	}
	err = tp.client.Close()
	if err != nil {
		log.Fatal(err)
	}
}

func (tp *TopicProcessor) getConsumerMessagesChan() <-chan *sarama.ConsumerMessage {
	consumerMessagesChan := make(chan *sarama.ConsumerMessage)
	for _, ch := range tp.consumerMessageChannels() {
		tp.waitGroup.Add(1)
		go func(c <-chan *sarama.ConsumerMessage) {
			defer tp.waitGroup.Done()
			for msg := range c {
				consumerMessagesChan <- msg
			}
		}(ch)
	}
	return consumerMessagesChan
}

func (tp *TopicProcessor) onProducerError(error *sarama.ProducerError) {
	log.Fatal(error) /* FIXME Handle this gracefully with a retry count / backoff period */
}

func (tp *TopicProcessor) onTick() {
	for _, pp := range tp.partitionProcessors {
		pp.markOffsetsIfPossible()
	}
}

func (tp *TopicProcessor) consumerMessageChannels() []<-chan *sarama.ConsumerMessage {
	var chans []<-chan *sarama.ConsumerMessage
	for _, partitionProcessor := range tp.partitionProcessors {
		partitionChannels := partitionProcessor.consumerMessageChannels()
		chans = append(chans, partitionChannels...)
	}
	return chans
}

func mustSetupProducer(brokers []string, producerClientID string, requiredAcks sarama.RequiredAcks) sarama.AsyncProducer {
	saramaConfig := sarama.NewConfig()
	saramaConfig.ClientID = producerClientID
	saramaConfig.Producer.Return.Successes = true
	saramaConfig.Producer.Partitioner = sarama.NewManualPartitioner
	saramaConfig.Producer.RequiredAcks = requiredAcks
	saramaConfig.MetricRegistry = metrics.DefaultRegistry

	producer, err := sarama.NewAsyncProducer(brokers, saramaConfig)
	if err != nil {
		log.Fatal(err)
	}

	return producer
}

// Shutdown safely shuts down topic processing, waiting for unfinished jobs
func (tp *TopicProcessor) Shutdown() {
	tp.shutdown <- true
	tp.waitGroup.Wait()
}

func (tp *TopicProcessor) onProducerAck(producerMessage *sarama.ProducerMessage, more bool) {
	if !more {
		return
	}
	incomingMessage := producerMessage.Metadata.(*IncomingMessage)
	pp := tp.partitionProcessors[int32(incomingMessage.Partition)]
	pp.onProducerAck(producerMessage)
}
<commit_msg>Stop ticker on shutdown<commit_after>/*

kasper is a lightweight Kafka stream processing library.

*/

package kasper

import (
	"log"
	"sync"
	"time"

	"github.com/Shopify/sarama"
	"github.com/rcrowley/go-metrics"
)

// TopicProcessor desribes kafka topic processor
type TopicProcessor struct {
	config              *TopicProcessorConfig
	containerID         int
	client              sarama.Client
	producer            sarama.AsyncProducer
	offsetManager       sarama.OffsetManager
	partitionProcessors map[int32]*partitionProcessor
	inputTopics         []string
	partitions          []int
	shutdown            chan bool
	waitGroup           sync.WaitGroup
}

// MessageProcessor describes kafka message processor
type MessageProcessor interface {
	// Process message from Kafka input topics.
	// This is the function where you perform all needed actions, like
	// population KV stroage or producing Kafka output messages
	Process(IncomingMessage, Sender, Coordinator)
}

// NewTopicProcessor creates a new TopicProcessor with the given config.
// It requires a factory function that creates MessageProcessor instances and a container id.
// The container id must be a number between 0 and config.ContainerCount - 1.
func NewTopicProcessor(config *TopicProcessorConfig, makeProcessor func() MessageProcessor, containerID int) *TopicProcessor {
	if containerID < 0 || containerID >= config.ContainerCount {
		log.Fatalf("ContainerID expected to be between 0 and %d, got: %d", config.ContainerCount-1, containerID)
	}
	inputTopics := config.InputTopics
	brokerList := config.BrokerList
	for _, topic := range inputTopics {
		_, ok := config.TopicSerdes[topic]
		if !ok {
			log.Fatalf("Could not find Serde for topic '%s'", topic)
		}
	}
	saramaConfig := sarama.NewConfig()
	saramaConfig.Consumer.Offsets.Initial = sarama.OffsetOldest // TODO: make this configurable
	client, err := sarama.NewClient(brokerList, saramaConfig)
	if err != nil {
		log.Fatal(err)
	}
	partitions := config.partitionsForContainer(containerID)
	for _, partition := range partitions {
		_, ok := config.PartitionToContainerID[partition]
		if !ok {
			log.Fatalf("Could not find PartitionToContainerID mapping for partition %d", partition)
		}
	}
	offsetManager, err := sarama.NewOffsetManagerFromClient(config.kafkaConsumerGroup(), client)
	if err != nil {
		log.Fatal(err)
	}
	partitionProcessors := make(map[int32]*partitionProcessor, len(partitions))
	requiredAcks := config.Config.RequiredAcks
	producer := mustSetupProducer(config.BrokerList, config.producerClientID(containerID), requiredAcks)
	topicProcessor := TopicProcessor{
		config,
		containerID,
		client,
		producer,
		offsetManager,
		partitionProcessors,
		inputTopics,
		partitions,
		make(chan bool),
		sync.WaitGroup{},
	}
	for _, partition := range partitions {
		processor := makeProcessor()
		partitionProcessors[int32(partition)] = newPartitionProcessor(&topicProcessor, processor, partition)
	}
	return &topicProcessor
}

// Start launches a deferred routine for topic processing.
func (tp *TopicProcessor) Start() {
	tp.waitGroup.Add(1)
	go func() {
		defer tp.waitGroup.Done()
		tp.runLoop()
	}()
}

func (tp *TopicProcessor) runLoop() {
	consumerChan := tp.getConsumerMessagesChan()
	var tickerChan <-chan time.Time
	var ticker *time.Ticker

	if tp.config.markOffsetsAutomatically() {
		ticker = time.NewTicker(tp.config.AutoMarkOffsetsInterval)
		tickerChan = ticker.C
	} else {
		tickerChan = make(<-chan time.Time)
	}

	tp.waitGroup.Add(1)
	go func() {
		defer tp.waitGroup.Done()
		for err := range tp.producer.Errors() {
			tp.onProducerError(err)
		}
	}()

	for {
		select {
		case consumerMessage := <-consumerChan:
			tp.processConsumerMessage(consumerMessage, tickerChan)
		case msg, more := <-tp.producer.Successes():
			tp.onProducerAck(msg, more)
		case <-tickerChan:
			tp.onTick()
		case <-tp.shutdown:
			tp.onShutdown(ticker)
			return
		}
	}
}

func (tp *TopicProcessor) processConsumerMessage(consumerMessage *sarama.ConsumerMessage, tickerChan <-chan time.Time) {
	pp := tp.partitionProcessors[consumerMessage.Partition]
	for {
		if pp.isReadyForMessage(consumerMessage) {
			producerMessages := pp.process(consumerMessage)
			for len(producerMessages) > 0 {
				select {
				case tp.producer.Input() <- producerMessages[0]:
					producerMessages = producerMessages[1:]
				case msg, more := <-tp.producer.Successes():
					tp.onProducerAck(msg, more)
				case <-tickerChan:
					tp.onTick()
				}
			}
			pp.onProcessCompleted()
			break
		} else {
			select {
			case msg, more := <-tp.producer.Successes():
				tp.onProducerAck(msg, more)
			case <-tickerChan:
				tp.onTick()
			}
		}
	}
}

func (tp *TopicProcessor) onShutdown(ticker *time.Ticker) {
	if ticker != nil {
		ticker.Stop()
	}
	for _, pp := range tp.partitionProcessors {
		pp.onShutdown()
	}
	err := tp.producer.Close()
	if err != nil {
		log.Fatal(err)
	}
	err = tp.client.Close()
	if err != nil {
		log.Fatal(err)
	}
}

func (tp *TopicProcessor) getConsumerMessagesChan() <-chan *sarama.ConsumerMessage {
	consumerMessagesChan := make(chan *sarama.ConsumerMessage)
	for _, ch := range tp.consumerMessageChannels() {
		tp.waitGroup.Add(1)
		go func(c <-chan *sarama.ConsumerMessage) {
			defer tp.waitGroup.Done()
			for msg := range c {
				consumerMessagesChan <- msg
			}
		}(ch)
	}
	return consumerMessagesChan
}

func (tp *TopicProcessor) onProducerError(error *sarama.ProducerError) {
	log.Fatal(error) /* FIXME Handle this gracefully with a retry count / backoff period */
}

func (tp *TopicProcessor) onTick() {
	for _, pp := range tp.partitionProcessors {
		pp.markOffsetsIfPossible()
	}
}

func (tp *TopicProcessor) consumerMessageChannels() []<-chan *sarama.ConsumerMessage {
	var chans []<-chan *sarama.ConsumerMessage
	for _, partitionProcessor := range tp.partitionProcessors {
		partitionChannels := partitionProcessor.consumerMessageChannels()
		chans = append(chans, partitionChannels...)
	}
	return chans
}

func mustSetupProducer(brokers []string, producerClientID string, requiredAcks sarama.RequiredAcks) sarama.AsyncProducer {
	saramaConfig := sarama.NewConfig()
	saramaConfig.ClientID = producerClientID
	saramaConfig.Producer.Return.Successes = true
	saramaConfig.Producer.Partitioner = sarama.NewManualPartitioner
	saramaConfig.Producer.RequiredAcks = requiredAcks
	saramaConfig.MetricRegistry = metrics.DefaultRegistry

	producer, err := sarama.NewAsyncProducer(brokers, saramaConfig)
	if err != nil {
		log.Fatal(err)
	}

	return producer
}

// Shutdown safely shuts down topic processing, waiting for unfinished jobs
func (tp *TopicProcessor) Shutdown() {
	tp.shutdown <- true
	tp.waitGroup.Wait()
}

func (tp *TopicProcessor) onProducerAck(producerMessage *sarama.ProducerMessage, more bool) {
	if !more {
		return
	}
	incomingMessage := producerMessage.Metadata.(*IncomingMessage)
	pp := tp.partitionProcessors[int32(incomingMessage.Partition)]
	pp.onProducerAck(producerMessage)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/e-asphyx/tpm2net"
	"log"
)

type TPMHandler struct {
	VirtualWidth  int
	VirtualHeight int

	Layout Layout
	Output OutputDevice

	outputBuffer []Color
}

func (hnd *TPMHandler) HandlePacket(pkt *tpm2net.Packet) {
	buf := pkt.Data

	numLeds := hnd.Layout.NumCells()
	if len(hnd.outputBuffer) < numLeds {
		hnd.outputBuffer = make([]Color, numLeds)
	}

	layoutWidth := hnd.Layout.Width()
	layoutHeight := hnd.Layout.Height()

	xstep := layoutWidth / float64(hnd.VirtualWidth)
	ystep := layoutHeight / float64(hnd.VirtualHeight)

	for i := range hnd.outputBuffer {
		poly := hnd.Layout.Cell(i)
		tl, br := poly.BoundingBox()

		x0 := int(tl.X / layoutWidth * float64(hnd.VirtualWidth))
		x1 := int(br.X / layoutWidth * float64(hnd.VirtualWidth))

		y0 := int(tl.Y / layoutHeight * float64(hnd.VirtualHeight))
		y1 := int(br.Y / layoutHeight * float64(hnd.VirtualHeight))

		acc := [3]int32{}
		var cnt int32

		for y := y0; y <= y1; y++ {
			for x := x0; x <= x1; x++ {
				center := Point{float64(x)*xstep + xstep/2.0, float64(y)*ystep + ystep/2.0}

				if poly.PointInside(center) &&
					x >= 0 && y >= 0 &&
					x < hnd.VirtualWidth && y < hnd.VirtualHeight {

					offs := (y*hnd.VirtualWidth + x) * 3
					acc[0] += int32(buf[offs])
					acc[1] += int32(buf[offs+1])
					acc[2] += int32(buf[offs+2])
					cnt++
				}
			}
		}

		if cnt != 0 {
			for c := range acc {
				acc[c] = (acc[c] + (cnt / 2)) / cnt
				if acc[c] > 255 {
					acc[c] = 255
				}
			}
		} else {
			log.Println("Misplaced cell")
		}

		hnd.outputBuffer[i] = RGB(uint8(acc[0]), uint8(acc[1]), uint8(acc[2]))
	}

	if _, err := hnd.Output.Write(hnd.outputBuffer); err != nil {
		log.Println(err)
	}
}
<commit_msg>Prevent crash if smaller packet received<commit_after>package main

import (
	"github.com/e-asphyx/tpm2net"
	"log"
)

type TPMHandler struct {
	VirtualWidth  int
	VirtualHeight int

	Layout Layout
	Output OutputDevice

	frameBuffer  []uint8
	outputBuffer []Color
}

func (hnd *TPMHandler) HandlePacket(pkt *tpm2net.Packet) {
	numLeds := hnd.Layout.NumCells()
	bufSz := hnd.VirtualWidth * hnd.VirtualHeight * 3

	if len(hnd.frameBuffer) < bufSz {
		hnd.frameBuffer = make([]uint8, bufSz)
	}
	copy(hnd.frameBuffer, pkt.Data)

	if len(hnd.outputBuffer) < numLeds {
		hnd.outputBuffer = make([]Color, numLeds)
	}

	layoutWidth := hnd.Layout.Width()
	layoutHeight := hnd.Layout.Height()

	xstep := layoutWidth / float64(hnd.VirtualWidth)
	ystep := layoutHeight / float64(hnd.VirtualHeight)

	for i := range hnd.outputBuffer {
		poly := hnd.Layout.Cell(i)
		tl, br := poly.BoundingBox()

		x0 := int(tl.X / layoutWidth * float64(hnd.VirtualWidth))
		x1 := int(br.X / layoutWidth * float64(hnd.VirtualWidth))

		y0 := int(tl.Y / layoutHeight * float64(hnd.VirtualHeight))
		y1 := int(br.Y / layoutHeight * float64(hnd.VirtualHeight))

		acc := [3]int32{}
		var cnt int32

		for y := y0; y <= y1; y++ {
			for x := x0; x <= x1; x++ {
				center := Point{float64(x)*xstep + xstep/2.0, float64(y)*ystep + ystep/2.0}

				if poly.PointInside(center) &&
					x >= 0 && y >= 0 &&
					x < hnd.VirtualWidth && y < hnd.VirtualHeight {

					offs := (y*hnd.VirtualWidth + x) * 3
					acc[0] += int32(hnd.frameBuffer[offs])
					acc[1] += int32(hnd.frameBuffer[offs+1])
					acc[2] += int32(hnd.frameBuffer[offs+2])
					cnt++
				}
			}
		}

		if cnt != 0 {
			for c := range acc {
				acc[c] = (acc[c] + (cnt / 2)) / cnt
				if acc[c] > 255 {
					acc[c] = 255
				}
			}
		} else {
			log.Println("Misplaced cell")
		}

		hnd.outputBuffer[i] = RGB(uint8(acc[0]), uint8(acc[1]), uint8(acc[2]))
	}

	if _, err := hnd.Output.Write(hnd.outputBuffer); err != nil {
		log.Println(err)
	}
}
<|endoftext|>


<commit_before>package tracking

import (
	"bytes"
	"encoding/json"
	"net/http"
	"strconv"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"

	"gopkg.in/mgo.v2/bson"
)

// Coord represents a single lat/lng point used to draw routes
type Coord struct {
	Lat float64 `json:"lat" bson:"lat"`
	Lng float64 `json:"lng" bson:"lng"`
}

// Route represents a set of coordinates to draw a path on our tracking map
type Route struct {
	ID          string    `json:"id"             bson:"_id,omitempty"`
	Name        string    `json:"name"           bson:"name"`
	Description string    `json:"description"    bson:"description"`
	StartTime   string    `json:"startTime"      bson:"startTime"`
	EndTime     string    `json:"endTime"        bson:"endTime"`
	Enabled     bool      `json:"enabled,string" bson:"enabled"`
	Color       string    `json:"color"          bson:"color"`
	Width       int       `json:"width,string"   bson:"width"`
	Coords      []Coord   `json:"coords"         bson:"coords"`
	Created     time.Time `json:"created"        bson:"created"`
	Updated     time.Time `json:"updated"        bson:"updated"`
}

// Stop indicates where a tracked object is scheduled to arrive
type Stop struct {
	ID          string `json:"id"             bson:"id"`
	Name        string `json:"name"           bson:"name"`
	Description string `json:"description"    bson:"description"`
	// position on map
	Lat     float64 `json:"lat,string"     bson:"lat"`
	Lng     float64 `json:"lng,string"     bson:"lng"`
	Address string  `json:"address"        bson:"address"`

	StartTime string `json:"startTime"      bson:"startTime"`
	EndTime   string `json:"endTime"        bson:"endTime"`
	Enabled   bool   `json:"enabled,string" bson:"enabled"`
	RouteID   string `json:"routeId"        bson:"routeId"`
}

// RoutesHandler finds all of the routes in the database
func (App *App) RoutesHandler(w http.ResponseWriter, r *http.Request) {
	// Find all routes in database
	var routes []Route
	err := App.Routes.Find(bson.M{}).All(&routes)
	// Handle query errors
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Send each route to client as JSON
	WriteJSON(w, routes)
}

// StopsHandler finds all of the route stops in the database
func (App *App) StopsHandler(w http.ResponseWriter, r *http.Request) {
	// Find all stops in database
	var stops []Stop
	err := App.Stops.Find(bson.M{}).All(&stops)
	// Handle query errors
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Send each stop to client as JSON
	WriteJSON(w, stops)
}

func Interpolate(coords []Coord, key string) []Coord {
	// make request
	prefix := "https://roads.googleapis.com/v1/snapToRoads?"
	var buffer bytes.Buffer
	buffer.WriteString(prefix)
	buffer.WriteString("path=")
	for i, coord := range coords {
		buffer.WriteString(strconv.FormatFloat(coord.Lat, 'f', 10, 64))
		buffer.WriteString(",")
		buffer.WriteString(strconv.FormatFloat(coord.Lng, 'f', 10, 64))
		if i > len(coords) {
			buffer.WriteString("|")
		}
	}
	buffer.WriteString("&interpolate=true&key=")
	buffer.WriteString(key)
}

// RoutesCreateHandler adds a new route to the database
func (App *App) RoutesCreateHandler(w http.ResponseWriter, r *http.Request) {
	// Create a new route object using request fields
	var routeData map[string]string
	var coordsData []map[string]float64
	// Decode route details
	err := json.NewDecoder(r.Body).Decode(&routeData)
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Unmarshal route coordinates
	err = json.Unmarshal([]byte(routeData["coords"]), &coordsData)
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Create a Coord from each set of input coordinates
	coords := []Coord{}
	for _, c := range coordsData {
		coord := Coord{c["lat"], c["lng"]}
		coords = append(coords, coord)
	}
	// Here do the interpolation
	coords = Interpolate(coords, App.Config.GoogleMapAPIKey)
	// Type conversions
	enabled, _ := strconv.ParseBool(routeData["enabled"])
	width, _ := strconv.Atoi(routeData["width"])
	currentTime := time.Now()
	// Create a new route
	route := Route{
		string(bson.NewObjectId()),
		routeData["name"],
		routeData["description"],
		routeData["startTime"],
		routeData["endTime"],
		enabled,
		routeData["color"],
		width,
		coords,
		currentTime,
		currentTime}
	// Store new route under routes collection
	err = App.Routes.Insert(&route)
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

//Deletes route from database
func (App *App) RoutesDeleteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	log.Debugf("deleting", vars["id"])
	err := App.Routes.Remove(bson.M{"_id": bson.ObjectIdHex(vars["id"])})
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// StopsCreateHandler adds a new route stop to the database
func (App *App) StopsCreateHandler(w http.ResponseWriter, r *http.Request) {
	// Create a new stop object using request fields
	stop := Stop{}
	err := json.NewDecoder(r.Body).Decode(&stop)
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Store new stop under stops collection
	err = App.Stops.Insert(&stop)
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func (App *App) StopsDeleteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	log.Debugf("deleting", vars["id"])
	err := App.Stops.Remove(bson.M{"name": vars["id"]})
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
<commit_msg>finish implementing snap to roads function<commit_after>package tracking

import (
	"bytes"
	"encoding/json"
	"net/http"
	"strconv"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/gorilla/mux"

	"fmt"
	"io/ioutil"

	"gopkg.in/mgo.v2/bson"
)

// Coord represents a single lat/lng point used to draw routes
type Coord struct {
	Lat float64 `json:"lat" bson:"lat"`
	Lng float64 `json:"lng" bson:"lng"`
}

// Route represents a set of coordinates to draw a path on our tracking map
type Route struct {
	ID          string    `json:"id"             bson:"_id,omitempty"`
	Name        string    `json:"name"           bson:"name"`
	Description string    `json:"description"    bson:"description"`
	StartTime   string    `json:"startTime"      bson:"startTime"`
	EndTime     string    `json:"endTime"        bson:"endTime"`
	Enabled     bool      `json:"enabled,string" bson:"enabled"`
	Color       string    `json:"color"          bson:"color"`
	Width       int       `json:"width,string"   bson:"width"`
	Coords      []Coord   `json:"coords"         bson:"coords"`
	Created     time.Time `json:"created"        bson:"created"`
	Updated     time.Time `json:"updated"        bson:"updated"`
}

// Stop indicates where a tracked object is scheduled to arrive
type Stop struct {
	ID          string `json:"id"             bson:"id"`
	Name        string `json:"name"           bson:"name"`
	Description string `json:"description"    bson:"description"`
	// position on map
	Lat     float64 `json:"lat,string"     bson:"lat"`
	Lng     float64 `json:"lng,string"     bson:"lng"`
	Address string  `json:"address"        bson:"address"`

	StartTime string `json:"startTime"      bson:"startTime"`
	EndTime   string `json:"endTime"        bson:"endTime"`
	Enabled   bool   `json:"enabled,string" bson:"enabled"`
	RouteID   string `json:"routeId"        bson:"routeId"`
}

type MapPoint struct {
	Latitude  float32 `json:"latitude"`
	Longitude float32 `json:"longitude"`
}
type MapResponsePoint struct {
	Location      MapPoint `json:"location"`
	OriginalIndex int      `json:"originalIndex,omitempty"`
	PlaceID       string   `json:"placeId"`
}
type MapResponse struct {
	SnappedPoints []MapResponsePoint
}

// RoutesHandler finds all of the routes in the database
func (App *App) RoutesHandler(w http.ResponseWriter, r *http.Request) {
	// Find all routes in database
	var routes []Route
	err := App.Routes.Find(bson.M{}).All(&routes)
	// Handle query errors
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Send each route to client as JSON
	WriteJSON(w, routes)
}

// StopsHandler finds all of the route stops in the database
func (App *App) StopsHandler(w http.ResponseWriter, r *http.Request) {
	// Find all stops in database
	var stops []Stop
	err := App.Stops.Find(bson.M{}).All(&stops)
	// Handle query errors
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Send each stop to client as JSON
	WriteJSON(w, stops)
}

func Interpolate(coords []Coord, key string) []Coord {
	// make request
	prefix := "https://roads.googleapis.com/v1/snapToRoads?"
	var buffer bytes.Buffer
	buffer.WriteString(prefix)
	buffer.WriteString("path=")
	for i, coord := range coords {
		buffer.WriteString(strconv.FormatFloat(coord.Lat, 'f', 10, 64))
		buffer.WriteString(",")
		buffer.WriteString(strconv.FormatFloat(coord.Lng, 'f', 10, 64))
		if i < len(coords)-1 {
			buffer.WriteString("|")
		}
	}
	buffer.WriteString("&interpolate=true&key=")
	buffer.WriteString(key)
	fmt.Print("sending request: " + buffer.String())
	resp, err := http.Get(buffer.String())
	if err != nil {
		fmt.Errorf("Error Not valid response from Google API")
		return nil
	}
	defer resp.Body.Close()
	fmt.Print(resp.Header)
	body, err := ioutil.ReadAll(resp.Body)

	mapResponse := MapResponse{}
	json.Unmarshal(body, &mapResponse)
	result := []Coord{}
	for _, location := range mapResponse.SnappedPoints {
		currentLocation := Coord{
			Lat: float64(location.Location.Latitude),
			Lng: float64(location.Location.Longitude),
		}
		result = append(result, currentLocation)
	}
	return result
}

// RoutesCreateHandler adds a new route to the database
func (App *App) RoutesCreateHandler(w http.ResponseWriter, r *http.Request) {
	// Create a new route object using request fields
	var routeData map[string]string
	var coordsData []map[string]float64
	// Decode route details
	err := json.NewDecoder(r.Body).Decode(&routeData)
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Unmarshal route coordinates
	err = json.Unmarshal([]byte(routeData["coords"]), &coordsData)
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Create a Coord from each set of input coordinates
	coords := []Coord{}
	for _, c := range coordsData {
		coord := Coord{c["lat"], c["lng"]}
		coords = append(coords, coord)
	}
	// Here do the interpolation
	coords = Interpolate(coords, App.Config.GoogleMapAPIKey)
	fmt.Printf("Size of coordinates = %d", len(coords))
	// Type conversions
	enabled, _ := strconv.ParseBool(routeData["enabled"])
	width, _ := strconv.Atoi(routeData["width"])
	currentTime := time.Now()
	// Create a new route
	route := Route{
		string(bson.NewObjectId()),
		routeData["name"],
		routeData["description"],
		routeData["startTime"],
		routeData["endTime"],
		enabled,
		routeData["color"],
		width,
		coords,
		currentTime,
		currentTime}
	// Store new route under routes collection
	err = App.Routes.Insert(&route)
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

//Deletes route from database
func (App *App) RoutesDeleteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	log.Debugf("deleting", vars["id"])
	err := App.Routes.Remove(bson.M{"_id": bson.ObjectIdHex(vars["id"])})
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

// StopsCreateHandler adds a new route stop to the database
func (App *App) StopsCreateHandler(w http.ResponseWriter, r *http.Request) {
	// Create a new stop object using request fields
	stop := Stop{}
	err := json.NewDecoder(r.Body).Decode(&stop)
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	// Store new stop under stops collection
	err = App.Stops.Insert(&stop)
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func (App *App) StopsDeleteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	log.Debugf("deleting", vars["id"])
	err := App.Stops.Remove(bson.M{"name": vars["id"]})
	// Error handling
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
<|endoftext|>


<commit_before>package node

import (
	"fmt"
	"net"
	"sort"
	"strings"

	"k8s.io/apimachinery/pkg/util/sets"
	utilfeature "k8s.io/apiserver/pkg/util/feature"
	"k8s.io/kubernetes/pkg/features"

	"github.com/openshift/library-go/pkg/crypto"
	configapi "github.com/openshift/origin/pkg/cmd/server/apis/config"
	cmdutil "github.com/openshift/origin/pkg/cmd/util"
	"github.com/openshift/origin/pkg/cmd/util/variable"
	"github.com/openshift/origin/pkg/network"
)

// ComputeKubeletFlags returns the flags to use when starting the kubelet.
func ComputeKubeletFlags(startingArgs map[string][]string, options configapi.NodeConfig) ([]string, error) {
	args := map[string][]string{}
	for key, slice := range startingArgs {
		for _, val := range slice {
			args[key] = append(args[key], val)
		}
	}

	imageTemplate := variable.NewDefaultImageTemplate()
	imageTemplate.Format = options.ImageConfig.Format
	imageTemplate.Latest = options.ImageConfig.Latest

	path := ""
	var fileCheckInterval int64
	if options.PodManifestConfig != nil {
		path = options.PodManifestConfig.Path
		fileCheckInterval = options.PodManifestConfig.FileCheckIntervalSeconds
	}
	kubeAddressStr, kubePortStr, err := net.SplitHostPort(options.ServingInfo.BindAddress)
	if err != nil {
		return nil, fmt.Errorf("cannot parse node address: %v", err)
	}

	setIfUnset(args, "address", kubeAddressStr)
	setIfUnset(args, "port", kubePortStr)
	setIfUnset(args, "kubeconfig", options.MasterKubeConfig)
	setIfUnset(args, "pod-manifest-path", path)
	setIfUnset(args, "root-dir", options.VolumeDirectory)
	setIfUnset(args, "node-ip", options.NodeIP)
	setIfUnset(args, "hostname-override", options.NodeName)
	setIfUnset(args, "allow-privileged", "true")
	setIfUnset(args, "register-node", "true")
	setIfUnset(args, "read-only-port", "0")      // no read only access
	setIfUnset(args, "cadvisor-port", "0")       // no unsecured cadvisor access
	setIfUnset(args, "healthz-port", "0")        // no unsecured healthz access
	setIfUnset(args, "healthz-bind-address", "") // no unsecured healthz access
	setIfUnset(args, "fail-swap-on", "false")
	setIfUnset(args, "cluster-dns", options.DNSIP)
	setIfUnset(args, "cluster-domain", options.DNSDomain)
	setIfUnset(args, "host-network-sources", "api", "file")
	setIfUnset(args, "host-pid-sources", "api", "file")
	setIfUnset(args, "host-ipc-sources", "api", "file")
	setIfUnset(args, "http-check-frequency", "0s") // no remote HTTP pod creation access
	setIfUnset(args, "file-check-frequency", fmt.Sprintf("%ds", fileCheckInterval))
	setIfUnset(args, "pod-infra-container-image", imageTemplate.ExpandOrDie("pod"))
	setIfUnset(args, "max-pods", "250")
	setIfUnset(args, "cgroup-driver", "systemd")
	setIfUnset(args, "container-runtime-endpoint", options.DockerConfig.DockerShimSocket)
	setIfUnset(args, "image-service-endpoint", options.DockerConfig.DockerShimSocket)
	setIfUnset(args, "experimental-dockershim-root-directory", options.DockerConfig.DockershimRootDirectory)
	setIfUnset(args, "containerized", fmt.Sprintf("%v", cmdutil.Env("OPENSHIFT_CONTAINERIZED", "") == "true"))
	setIfUnset(args, "authentication-token-webhook", "true")
	setIfUnset(args, "authentication-token-webhook-cache-ttl", options.AuthConfig.AuthenticationCacheTTL)
	setIfUnset(args, "anonymous-auth", "true")
	setIfUnset(args, "client-ca-file", options.ServingInfo.ClientCA)
	setIfUnset(args, "authorization-mode", "Webhook")
	setIfUnset(args, "authorization-webhook-cache-authorized-ttl", options.AuthConfig.AuthorizationCacheTTL)
	setIfUnset(args, "authorization-webhook-cache-unauthorized-ttl", options.AuthConfig.AuthorizationCacheTTL)

	// Override kubelet iptables-masquerade-bit value to match overridden kube-proxy
	// iptables-masquerade-bit value, UNLESS the user has overridden kube-proxy to match the
	// previously-not-overridden kubelet value, in which case we don't want to re-break them.
	if len(options.ProxyArguments["iptables-masquerade-bit"]) != 1 || options.ProxyArguments["iptables-masquerade-bit"][0] != "14" {
		setIfUnset(args, "iptables-masquerade-bit", "0")
	}

	if network.IsOpenShiftNetworkPlugin(options.NetworkConfig.NetworkPluginName) {
		// SDN plugin pod setup/teardown is implemented as a CNI plugin
		setIfUnset(args, "network-plugin", "cni")
	} else {
		setIfUnset(args, "network-plugin", options.NetworkConfig.NetworkPluginName)
	}

	// prevents kube from generating certs
	setIfUnset(args, "tls-cert-file", options.ServingInfo.ServerCert.CertFile)
	setIfUnset(args, "tls-private-key-file", options.ServingInfo.ServerCert.KeyFile)
	// roundtrip to get a default value
	setIfUnset(args, "tls-cipher-suites", crypto.CipherSuitesToNamesOrDie(crypto.CipherSuitesOrDie(options.ServingInfo.CipherSuites))...)
	setIfUnset(args, "tls-min-version", crypto.TLSVersionToNameOrDie(crypto.TLSVersionOrDie(options.ServingInfo.MinTLSVersion)))

	// Server cert rotation is ineffective if a cert is hardcoded.
	if len(args["feature-gates"]) > 0 {
		// TODO this affects global state, but it matches what happens later.  Need a less side-effecty way to do it
		if err := utilfeature.DefaultFeatureGate.Set(args["feature-gates"][0]); err != nil {
			return nil, err
		}
		if utilfeature.DefaultFeatureGate.Enabled(features.RotateKubeletServerCertificate) {
			// Server cert rotation is ineffective if a cert is hardcoded.
			setIfUnset(args, "tls-cert-file", "")
			setIfUnset(args, "tls-private-key-file", "")
			setIfUnset(args, "rotate-server-certificates", "true")
		}
	}

	// there is a special case.  If you set `--cgroups-per-qos=false` and `--enforce-node-allocatable` is
	// an empty string, `--enforce-node-allocatable=""` needs to be explicitly set
	// cgroups-per-qos defaults to true
	if cgroupArg, enforceAllocatable := args["cgroups-per-qos"], args["enforce-node-allocatable"]; len(cgroupArg) == 1 && cgroupArg[0] == "false" && len(enforceAllocatable) == 0 {
		args["enforce-node-allocatable"] = []string{""}
	}

	var keys []string
	for key := range args {
		keys = append(keys, key)
	}
	sort.Strings(keys)

	var arguments []string
	for _, key := range keys {
		for _, token := range args[key] {
			arguments = append(arguments, fmt.Sprintf("--%s=%v", key, token))
		}
	}
	return arguments, nil
}

func setIfUnset(cmdLineArgs map[string][]string, key string, value ...string) {
	if _, ok := cmdLineArgs[key]; !ok {
		cmdLineArgs[key] = value
	}
}

// Some flags are *required* to be set when running from openshift start node.  This ensures they are set.
// If they are not set, we fail.  This is compensating for some lost integration tests.
func CheckFlags(args []string) error {
	if needle := "--authentication-token-webhook=true"; !hasArg(needle, args) {
		return fmt.Errorf("missing %v: %v", needle, args)
	}
	if needle := "--authorization-mode=Webhook"; !hasArg(needle, args) {
		return fmt.Errorf("missing %v: %v", needle, args)
	}
	if needle := "--tls-min-version="; !hasArgPrefix(needle, args) {
		return fmt.Errorf("missing %v: %v", needle, args)
	}
	if needle := "--tls-cipher-suites="; !hasArgPrefix(needle, args) {
		return fmt.Errorf("missing %v: %v", needle, args)
	}

	return nil
}

func hasArg(needle string, haystack []string) bool {
	return sets.NewString(haystack...).Has(needle)
}

func hasArgPrefix(needle string, haystack []string) bool {
	for _, haystackToken := range haystack {
		if strings.HasPrefix(haystackToken, needle) {
			return true
		}
	}

	return false
}
<commit_msg>only set PodManifestConfig flags if explicitly specified<commit_after>package node

import (
	"fmt"
	"net"
	"sort"
	"strings"

	"k8s.io/apimachinery/pkg/util/sets"
	utilfeature "k8s.io/apiserver/pkg/util/feature"
	"k8s.io/kubernetes/pkg/features"

	"github.com/openshift/library-go/pkg/crypto"
	configapi "github.com/openshift/origin/pkg/cmd/server/apis/config"
	cmdutil "github.com/openshift/origin/pkg/cmd/util"
	"github.com/openshift/origin/pkg/cmd/util/variable"
	"github.com/openshift/origin/pkg/network"
)

// ComputeKubeletFlags returns the flags to use when starting the kubelet.
func ComputeKubeletFlags(startingArgs map[string][]string, options configapi.NodeConfig) ([]string, error) {
	args := map[string][]string{}
	for key, slice := range startingArgs {
		for _, val := range slice {
			args[key] = append(args[key], val)
		}
	}

	imageTemplate := variable.NewDefaultImageTemplate()
	imageTemplate.Format = options.ImageConfig.Format
	imageTemplate.Latest = options.ImageConfig.Latest

	if options.PodManifestConfig != nil {
		setIfUnset(args, "pod-manifest-path", options.PodManifestConfig.Path)
		setIfUnset(args, "file-check-frequency", fmt.Sprintf("%ds", options.PodManifestConfig.FileCheckIntervalSeconds))
	}
	kubeAddressStr, kubePortStr, err := net.SplitHostPort(options.ServingInfo.BindAddress)
	if err != nil {
		return nil, fmt.Errorf("cannot parse node address: %v", err)
	}

	setIfUnset(args, "address", kubeAddressStr)
	setIfUnset(args, "port", kubePortStr)
	setIfUnset(args, "kubeconfig", options.MasterKubeConfig)
	setIfUnset(args, "root-dir", options.VolumeDirectory)
	setIfUnset(args, "node-ip", options.NodeIP)
	setIfUnset(args, "hostname-override", options.NodeName)
	setIfUnset(args, "allow-privileged", "true")
	setIfUnset(args, "register-node", "true")
	setIfUnset(args, "read-only-port", "0")      // no read only access
	setIfUnset(args, "cadvisor-port", "0")       // no unsecured cadvisor access
	setIfUnset(args, "healthz-port", "0")        // no unsecured healthz access
	setIfUnset(args, "healthz-bind-address", "") // no unsecured healthz access
	setIfUnset(args, "fail-swap-on", "false")
	setIfUnset(args, "cluster-dns", options.DNSIP)
	setIfUnset(args, "cluster-domain", options.DNSDomain)
	setIfUnset(args, "host-network-sources", "api", "file")
	setIfUnset(args, "host-pid-sources", "api", "file")
	setIfUnset(args, "host-ipc-sources", "api", "file")
	setIfUnset(args, "http-check-frequency", "0s") // no remote HTTP pod creation access
	setIfUnset(args, "pod-infra-container-image", imageTemplate.ExpandOrDie("pod"))
	setIfUnset(args, "max-pods", "250")
	setIfUnset(args, "cgroup-driver", "systemd")
	setIfUnset(args, "container-runtime-endpoint", options.DockerConfig.DockerShimSocket)
	setIfUnset(args, "image-service-endpoint", options.DockerConfig.DockerShimSocket)
	setIfUnset(args, "experimental-dockershim-root-directory", options.DockerConfig.DockershimRootDirectory)
	setIfUnset(args, "containerized", fmt.Sprintf("%v", cmdutil.Env("OPENSHIFT_CONTAINERIZED", "") == "true"))
	setIfUnset(args, "authentication-token-webhook", "true")
	setIfUnset(args, "authentication-token-webhook-cache-ttl", options.AuthConfig.AuthenticationCacheTTL)
	setIfUnset(args, "anonymous-auth", "true")
	setIfUnset(args, "client-ca-file", options.ServingInfo.ClientCA)
	setIfUnset(args, "authorization-mode", "Webhook")
	setIfUnset(args, "authorization-webhook-cache-authorized-ttl", options.AuthConfig.AuthorizationCacheTTL)
	setIfUnset(args, "authorization-webhook-cache-unauthorized-ttl", options.AuthConfig.AuthorizationCacheTTL)

	// Override kubelet iptables-masquerade-bit value to match overridden kube-proxy
	// iptables-masquerade-bit value, UNLESS the user has overridden kube-proxy to match the
	// previously-not-overridden kubelet value, in which case we don't want to re-break them.
	if len(options.ProxyArguments["iptables-masquerade-bit"]) != 1 || options.ProxyArguments["iptables-masquerade-bit"][0] != "14" {
		setIfUnset(args, "iptables-masquerade-bit", "0")
	}

	if network.IsOpenShiftNetworkPlugin(options.NetworkConfig.NetworkPluginName) {
		// SDN plugin pod setup/teardown is implemented as a CNI plugin
		setIfUnset(args, "network-plugin", "cni")
	} else {
		setIfUnset(args, "network-plugin", options.NetworkConfig.NetworkPluginName)
	}

	// prevents kube from generating certs
	setIfUnset(args, "tls-cert-file", options.ServingInfo.ServerCert.CertFile)
	setIfUnset(args, "tls-private-key-file", options.ServingInfo.ServerCert.KeyFile)
	// roundtrip to get a default value
	setIfUnset(args, "tls-cipher-suites", crypto.CipherSuitesToNamesOrDie(crypto.CipherSuitesOrDie(options.ServingInfo.CipherSuites))...)
	setIfUnset(args, "tls-min-version", crypto.TLSVersionToNameOrDie(crypto.TLSVersionOrDie(options.ServingInfo.MinTLSVersion)))

	// Server cert rotation is ineffective if a cert is hardcoded.
	if len(args["feature-gates"]) > 0 {
		// TODO this affects global state, but it matches what happens later.  Need a less side-effecty way to do it
		if err := utilfeature.DefaultFeatureGate.Set(args["feature-gates"][0]); err != nil {
			return nil, err
		}
		if utilfeature.DefaultFeatureGate.Enabled(features.RotateKubeletServerCertificate) {
			// Server cert rotation is ineffective if a cert is hardcoded.
			setIfUnset(args, "tls-cert-file", "")
			setIfUnset(args, "tls-private-key-file", "")
			setIfUnset(args, "rotate-server-certificates", "true")
		}
	}

	// there is a special case.  If you set `--cgroups-per-qos=false` and `--enforce-node-allocatable` is
	// an empty string, `--enforce-node-allocatable=""` needs to be explicitly set
	// cgroups-per-qos defaults to true
	if cgroupArg, enforceAllocatable := args["cgroups-per-qos"], args["enforce-node-allocatable"]; len(cgroupArg) == 1 && cgroupArg[0] == "false" && len(enforceAllocatable) == 0 {
		args["enforce-node-allocatable"] = []string{""}
	}

	var keys []string
	for key := range args {
		keys = append(keys, key)
	}
	sort.Strings(keys)

	var arguments []string
	for _, key := range keys {
		for _, token := range args[key] {
			arguments = append(arguments, fmt.Sprintf("--%s=%v", key, token))
		}
	}
	return arguments, nil
}

func setIfUnset(cmdLineArgs map[string][]string, key string, value ...string) {
	if _, ok := cmdLineArgs[key]; !ok {
		cmdLineArgs[key] = value
	}
}

// Some flags are *required* to be set when running from openshift start node.  This ensures they are set.
// If they are not set, we fail.  This is compensating for some lost integration tests.
func CheckFlags(args []string) error {
	if needle := "--authentication-token-webhook=true"; !hasArg(needle, args) {
		return fmt.Errorf("missing %v: %v", needle, args)
	}
	if needle := "--authorization-mode=Webhook"; !hasArg(needle, args) {
		return fmt.Errorf("missing %v: %v", needle, args)
	}
	if needle := "--tls-min-version="; !hasArgPrefix(needle, args) {
		return fmt.Errorf("missing %v: %v", needle, args)
	}
	if needle := "--tls-cipher-suites="; !hasArgPrefix(needle, args) {
		return fmt.Errorf("missing %v: %v", needle, args)
	}

	return nil
}

func hasArg(needle string, haystack []string) bool {
	return sets.NewString(haystack...).Has(needle)
}

func hasArgPrefix(needle string, haystack []string) bool {
	for _, haystackToken := range haystack {
		if strings.HasPrefix(haystackToken, needle) {
			return true
		}
	}

	return false
}
<|endoftext|>


<commit_before>package deploymentconfig

import (
	"time"

	"github.com/golang/glog"
	kapi "k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/client/cache"
	kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
	kcoreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/unversioned"
	"k8s.io/kubernetes/pkg/client/record"
	kcontroller "k8s.io/kubernetes/pkg/controller"
	"k8s.io/kubernetes/pkg/controller/framework"
	"k8s.io/kubernetes/pkg/runtime"
	utilruntime "k8s.io/kubernetes/pkg/util/runtime"
	"k8s.io/kubernetes/pkg/util/wait"
	"k8s.io/kubernetes/pkg/util/workqueue"

	osclient "github.com/openshift/origin/pkg/client"
	deployapi "github.com/openshift/origin/pkg/deploy/api"
)

const (
	// We must avoid creating new replication controllers until the deployment config and replication
	// controller stores have synced. If it hasn't synced, to avoid a hot loop, we'll wait this long
	// between checks.
	storeSyncedPollPeriod = 100 * time.Millisecond
	// MaxRetries is the number of times a deployment config will be retried before it is dropped out
	// of the queue.
	MaxRetries = 5
)

// NewDeploymentConfigController creates a new DeploymentConfigController.
func NewDeploymentConfigController(dcInformer, rcInformer, podInformer framework.SharedIndexInformer, oc osclient.Interface, kc kclientset.Interface, codec runtime.Codec) *DeploymentConfigController {
	eventBroadcaster := record.NewBroadcaster()
	eventBroadcaster.StartRecordingToSink(&kcoreclient.EventSinkImpl{Interface: kc.Core().Events("")})
	recorder := eventBroadcaster.NewRecorder(kapi.EventSource{Component: "deploymentconfig-controller"})

	c := &DeploymentConfigController{
		dn: oc,
		rn: kc.Core(),

		queue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()),

		recorder: recorder,
		codec:    codec,
	}

	c.dcStore.Indexer = dcInformer.GetIndexer()
	dcInformer.AddEventHandler(framework.ResourceEventHandlerFuncs{
		AddFunc:    c.addDeploymentConfig,
		UpdateFunc: c.updateDeploymentConfig,
		DeleteFunc: c.deleteDeploymentConfig,
	})
	c.rcStore.Indexer = rcInformer.GetIndexer()
	rcInformer.AddEventHandler(framework.ResourceEventHandlerFuncs{
		AddFunc:    c.addReplicationController,
		UpdateFunc: c.updateReplicationController,
		DeleteFunc: c.deleteReplicationController,
	})
	c.podStore.Indexer = podInformer.GetIndexer()
	podInformer.AddEventHandler(framework.ResourceEventHandlerFuncs{
		AddFunc:    c.addPod,
		UpdateFunc: c.updatePod,
		DeleteFunc: c.deletePod,
	})

	c.dcStoreSynced = dcInformer.HasSynced
	c.rcStoreSynced = rcInformer.HasSynced
	c.podStoreSynced = podInformer.HasSynced

	return c
}

// Run begins watching and syncing.
func (c *DeploymentConfigController) Run(workers int, stopCh <-chan struct{}) {
	defer utilruntime.HandleCrash()

	// Wait for the rc and dc stores to sync before starting any work in this controller.
	ready := make(chan struct{})
	go c.waitForSyncedStores(ready, stopCh)
	select {
	case <-ready:
	case <-stopCh:
		return
	}

	for i := 0; i < workers; i++ {
		go wait.Until(c.worker, time.Second, stopCh)
	}

	<-stopCh
	glog.Infof("Shutting down deploymentconfig controller")
	c.queue.ShutDown()
}

func (c *DeploymentConfigController) waitForSyncedStores(ready chan<- struct{}, stopCh <-chan struct{}) {
	defer utilruntime.HandleCrash()

	for !c.dcStoreSynced() || !c.rcStoreSynced() || !c.podStoreSynced() {
		glog.V(4).Infof("Waiting for the dc, rc, and pod caches to sync before starting the deployment config controller workers")
		select {
		case <-time.After(storeSyncedPollPeriod):
		case <-stopCh:
			return
		}
	}
	close(ready)
}

func (c *DeploymentConfigController) addDeploymentConfig(obj interface{}) {
	dc := obj.(*deployapi.DeploymentConfig)
	glog.V(4).Infof("Adding deployment config %q", dc.Name)
	c.enqueueDeploymentConfig(dc)
}

func (c *DeploymentConfigController) updateDeploymentConfig(old, cur interface{}) {
	// A periodic relist will send update events for all known configs.
	newDc := cur.(*deployapi.DeploymentConfig)
	oldDc := old.(*deployapi.DeploymentConfig)
	if newDc.ResourceVersion == oldDc.ResourceVersion {
		return
	}

	glog.V(4).Infof("Updating deployment config %q", newDc.Name)
	c.enqueueDeploymentConfig(newDc)
}

func (c *DeploymentConfigController) deleteDeploymentConfig(obj interface{}) {
	dc, ok := obj.(*deployapi.DeploymentConfig)
	if !ok {
		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
		if !ok {
			glog.Errorf("Couldn't get object from tombstone %+v", obj)
			return
		}
		dc, ok = tombstone.Obj.(*deployapi.DeploymentConfig)
		if !ok {
			glog.Errorf("Tombstone contained object that is not a deployment config: %+v", obj)
			return
		}
	}
	glog.V(4).Infof("Deleting deployment config %q", dc.Name)
	c.enqueueDeploymentConfig(dc)
}

// addReplicationController figures out which deploymentconfig is managing this replication
// controller and requeues the deployment config.
// TODO: Determine if we need to resync here. Would be useful for adoption but we cannot
// adopt right now.
func (c *DeploymentConfigController) addReplicationController(obj interface{}) {
	rc := obj.(*kapi.ReplicationController)
	glog.V(4).Infof("Replication controller %q added.", rc.Name)
	// We are waiting for the deployment config store to sync but still there are pathological
	// cases of highly latent watches.
	if dc, err := c.dcStore.GetConfigForController(rc); err == nil && dc != nil {
		c.enqueueDeploymentConfig(dc)
	}
}

// updateReplicationController figures out which deploymentconfig is managing this replication
// controller and requeues the deployment config.
func (c *DeploymentConfigController) updateReplicationController(old, cur interface{}) {
	// A periodic relist will send update events for all known controllers.
	curRC := cur.(*kapi.ReplicationController)
	oldRC := old.(*kapi.ReplicationController)
	if curRC.ResourceVersion == oldRC.ResourceVersion {
		return
	}

	glog.V(4).Infof("Replication controller %q updated.", curRC.Name)
	if dc, err := c.dcStore.GetConfigForController(curRC); err == nil && dc != nil {
		c.enqueueDeploymentConfig(dc)
	}
}

// deleteReplicationController enqueues the deployment that manages a replicationcontroller when
// the replicationcontroller is deleted. obj could be an *kapi.ReplicationController, or
// a DeletionFinalStateUnknown marker item.
func (c *DeploymentConfigController) deleteReplicationController(obj interface{}) {
	rc, ok := obj.(*kapi.ReplicationController)

	// When a delete is dropped, the relist will notice a pod in the store not
	// in the list, leading to the insertion of a tombstone object which contains
	// the deleted key/value.
	if !ok {
		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
		if !ok {
			glog.Errorf("Couldn't get object from tombstone %#v", obj)
			return
		}
		rc, ok = tombstone.Obj.(*kapi.ReplicationController)
		if !ok {
			glog.Errorf("Tombstone contained object that is not a replication controller %#v", obj)
			return
		}
	}
	glog.V(4).Infof("Replication controller %q deleted.", rc.Name)
	if dc, err := c.dcStore.GetConfigForController(rc); err == nil && dc != nil {
		c.enqueueDeploymentConfig(dc)
	}
}

func (c *DeploymentConfigController) addPod(obj interface{}) {
	if dc, err := c.dcStore.GetConfigForPod(obj.(*kapi.Pod)); err == nil && dc != nil {
		c.enqueueDeploymentConfig(dc)
	}
}

func (c *DeploymentConfigController) updatePod(old, cur interface{}) {
	curPod := cur.(*kapi.Pod)
	oldPod := old.(*kapi.Pod)
	if curPod.ResourceVersion == oldPod.ResourceVersion {
		return
	}

	if dc, err := c.dcStore.GetConfigForPod(curPod); err == nil && dc != nil {
		c.enqueueDeploymentConfig(dc)
	}
}

func (c *DeploymentConfigController) deletePod(obj interface{}) {
	pod, ok := obj.(*kapi.Pod)
	if !ok {
		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
		if !ok {
			glog.Errorf("Couldn't get object from tombstone %+v", obj)
			return
		}
		pod, ok = tombstone.Obj.(*kapi.Pod)
		if !ok {
			glog.Errorf("Tombstone contained object that is not a pod: %+v", obj)
			return
		}
	}
	if dc, err := c.dcStore.GetConfigForPod(pod); err == nil && dc != nil {
		c.enqueueDeploymentConfig(dc)
	}
}

func (c *DeploymentConfigController) enqueueDeploymentConfig(dc *deployapi.DeploymentConfig) {
	key, err := kcontroller.KeyFunc(dc)
	if err != nil {
		glog.Errorf("Couldn't get key for object %#v: %v", dc, err)
		return
	}
	c.queue.Add(key)
}

func (c *DeploymentConfigController) worker() {
	for {
		if quit := c.work(); quit {
			return
		}
	}
}

func (c *DeploymentConfigController) work() bool {
	key, quit := c.queue.Get()
	if quit {
		return true
	}
	defer c.queue.Done(key)

	dc, err := c.getByKey(key.(string))
	if err != nil {
		glog.Error(err.Error())
	}

	if dc == nil {
		return false
	}

	err = c.Handle(dc)
	c.handleErr(err, key)

	return false
}

func (c *DeploymentConfigController) getByKey(key string) (*deployapi.DeploymentConfig, error) {
	obj, exists, err := c.dcStore.Indexer.GetByKey(key)
	if err != nil {
		glog.V(2).Infof("Unable to retrieve deployment config %q from store: %v", key, err)
		c.queue.AddRateLimited(key)
		return nil, err
	}
	if !exists {
		glog.V(4).Infof("Deployment config %q has been deleted", key)
		return nil, nil
	}

	return obj.(*deployapi.DeploymentConfig), nil
}
<commit_msg>deploy: drop unnecessary resource handlers to reduce dc requeues<commit_after>package deploymentconfig

import (
	"time"

	"github.com/golang/glog"
	kapi "k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/client/cache"
	kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
	kcoreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/unversioned"
	"k8s.io/kubernetes/pkg/client/record"
	kcontroller "k8s.io/kubernetes/pkg/controller"
	"k8s.io/kubernetes/pkg/controller/framework"
	"k8s.io/kubernetes/pkg/runtime"
	utilruntime "k8s.io/kubernetes/pkg/util/runtime"
	"k8s.io/kubernetes/pkg/util/wait"
	"k8s.io/kubernetes/pkg/util/workqueue"

	osclient "github.com/openshift/origin/pkg/client"
	deployapi "github.com/openshift/origin/pkg/deploy/api"
)

const (
	// We must avoid creating new replication controllers until the deployment config and replication
	// controller stores have synced. If it hasn't synced, to avoid a hot loop, we'll wait this long
	// between checks.
	storeSyncedPollPeriod = 100 * time.Millisecond
	// MaxRetries is the number of times a deployment config will be retried before it is dropped out
	// of the queue.
	MaxRetries = 5
)

// NewDeploymentConfigController creates a new DeploymentConfigController.
func NewDeploymentConfigController(dcInformer, rcInformer, podInformer framework.SharedIndexInformer, oc osclient.Interface, kc kclientset.Interface, codec runtime.Codec) *DeploymentConfigController {
	eventBroadcaster := record.NewBroadcaster()
	eventBroadcaster.StartRecordingToSink(&kcoreclient.EventSinkImpl{Interface: kc.Core().Events("")})
	recorder := eventBroadcaster.NewRecorder(kapi.EventSource{Component: "deploymentconfig-controller"})

	c := &DeploymentConfigController{
		dn: oc,
		rn: kc.Core(),

		queue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()),

		recorder: recorder,
		codec:    codec,
	}

	c.dcStore.Indexer = dcInformer.GetIndexer()
	dcInformer.AddEventHandler(framework.ResourceEventHandlerFuncs{
		AddFunc:    c.addDeploymentConfig,
		UpdateFunc: c.updateDeploymentConfig,
		DeleteFunc: c.deleteDeploymentConfig,
	})
	c.rcStore.Indexer = rcInformer.GetIndexer()
	rcInformer.AddEventHandler(framework.ResourceEventHandlerFuncs{
		UpdateFunc: c.updateReplicationController,
		DeleteFunc: c.deleteReplicationController,
	})
	c.podStore.Indexer = podInformer.GetIndexer()
	podInformer.AddEventHandler(framework.ResourceEventHandlerFuncs{
		UpdateFunc: c.updatePod,
		DeleteFunc: c.deletePod,
	})

	c.dcStoreSynced = dcInformer.HasSynced
	c.rcStoreSynced = rcInformer.HasSynced
	c.podStoreSynced = podInformer.HasSynced

	return c
}

// Run begins watching and syncing.
func (c *DeploymentConfigController) Run(workers int, stopCh <-chan struct{}) {
	defer utilruntime.HandleCrash()

	// Wait for the rc and dc stores to sync before starting any work in this controller.
	ready := make(chan struct{})
	go c.waitForSyncedStores(ready, stopCh)
	select {
	case <-ready:
	case <-stopCh:
		return
	}

	for i := 0; i < workers; i++ {
		go wait.Until(c.worker, time.Second, stopCh)
	}

	<-stopCh
	glog.Infof("Shutting down deploymentconfig controller")
	c.queue.ShutDown()
}

func (c *DeploymentConfigController) waitForSyncedStores(ready chan<- struct{}, stopCh <-chan struct{}) {
	defer utilruntime.HandleCrash()

	for !c.dcStoreSynced() || !c.rcStoreSynced() || !c.podStoreSynced() {
		glog.V(4).Infof("Waiting for the dc, rc, and pod caches to sync before starting the deployment config controller workers")
		select {
		case <-time.After(storeSyncedPollPeriod):
		case <-stopCh:
			return
		}
	}
	close(ready)
}

func (c *DeploymentConfigController) addDeploymentConfig(obj interface{}) {
	dc := obj.(*deployapi.DeploymentConfig)
	glog.V(4).Infof("Adding deployment config %q", dc.Name)
	c.enqueueDeploymentConfig(dc)
}

func (c *DeploymentConfigController) updateDeploymentConfig(old, cur interface{}) {
	// A periodic relist will send update events for all known configs.
	newDc := cur.(*deployapi.DeploymentConfig)
	oldDc := old.(*deployapi.DeploymentConfig)
	if newDc.ResourceVersion == oldDc.ResourceVersion {
		return
	}

	glog.V(4).Infof("Updating deployment config %q", newDc.Name)
	c.enqueueDeploymentConfig(newDc)
}

func (c *DeploymentConfigController) deleteDeploymentConfig(obj interface{}) {
	dc, ok := obj.(*deployapi.DeploymentConfig)
	if !ok {
		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
		if !ok {
			glog.Errorf("Couldn't get object from tombstone %+v", obj)
			return
		}
		dc, ok = tombstone.Obj.(*deployapi.DeploymentConfig)
		if !ok {
			glog.Errorf("Tombstone contained object that is not a deployment config: %+v", obj)
			return
		}
	}
	glog.V(4).Infof("Deleting deployment config %q", dc.Name)
	c.enqueueDeploymentConfig(dc)
}

// updateReplicationController figures out which deploymentconfig is managing this replication
// controller and requeues the deployment config.
func (c *DeploymentConfigController) updateReplicationController(old, cur interface{}) {
	// A periodic relist will send update events for all known controllers.
	curRC := cur.(*kapi.ReplicationController)
	oldRC := old.(*kapi.ReplicationController)
	if curRC.ResourceVersion == oldRC.ResourceVersion {
		return
	}

	glog.V(4).Infof("Replication controller %q updated.", curRC.Name)
	if dc, err := c.dcStore.GetConfigForController(curRC); err == nil && dc != nil {
		c.enqueueDeploymentConfig(dc)
	}
}

// deleteReplicationController enqueues the deployment that manages a replicationcontroller when
// the replicationcontroller is deleted. obj could be an *kapi.ReplicationController, or
// a DeletionFinalStateUnknown marker item.
func (c *DeploymentConfigController) deleteReplicationController(obj interface{}) {
	rc, ok := obj.(*kapi.ReplicationController)

	// When a delete is dropped, the relist will notice a pod in the store not
	// in the list, leading to the insertion of a tombstone object which contains
	// the deleted key/value.
	if !ok {
		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
		if !ok {
			glog.Errorf("Couldn't get object from tombstone %#v", obj)
			return
		}
		rc, ok = tombstone.Obj.(*kapi.ReplicationController)
		if !ok {
			glog.Errorf("Tombstone contained object that is not a replication controller %#v", obj)
			return
		}
	}
	glog.V(4).Infof("Replication controller %q deleted.", rc.Name)
	if dc, err := c.dcStore.GetConfigForController(rc); err == nil && dc != nil {
		c.enqueueDeploymentConfig(dc)
	}
}

func (c *DeploymentConfigController) updatePod(old, cur interface{}) {
	curPod := cur.(*kapi.Pod)
	oldPod := old.(*kapi.Pod)
	if curPod.ResourceVersion == oldPod.ResourceVersion {
		return
	}

	if dc, err := c.dcStore.GetConfigForPod(curPod); err == nil && dc != nil {
		c.enqueueDeploymentConfig(dc)
	}
}

func (c *DeploymentConfigController) deletePod(obj interface{}) {
	pod, ok := obj.(*kapi.Pod)
	if !ok {
		tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
		if !ok {
			glog.Errorf("Couldn't get object from tombstone %+v", obj)
			return
		}
		pod, ok = tombstone.Obj.(*kapi.Pod)
		if !ok {
			glog.Errorf("Tombstone contained object that is not a pod: %+v", obj)
			return
		}
	}
	if dc, err := c.dcStore.GetConfigForPod(pod); err == nil && dc != nil {
		c.enqueueDeploymentConfig(dc)
	}
}

func (c *DeploymentConfigController) enqueueDeploymentConfig(dc *deployapi.DeploymentConfig) {
	key, err := kcontroller.KeyFunc(dc)
	if err != nil {
		glog.Errorf("Couldn't get key for object %#v: %v", dc, err)
		return
	}
	c.queue.Add(key)
}

func (c *DeploymentConfigController) worker() {
	for {
		if quit := c.work(); quit {
			return
		}
	}
}

func (c *DeploymentConfigController) work() bool {
	key, quit := c.queue.Get()
	if quit {
		return true
	}
	defer c.queue.Done(key)

	dc, err := c.getByKey(key.(string))
	if err != nil {
		glog.Error(err.Error())
	}

	if dc == nil {
		return false
	}

	err = c.Handle(dc)
	c.handleErr(err, key)

	return false
}

func (c *DeploymentConfigController) getByKey(key string) (*deployapi.DeploymentConfig, error) {
	obj, exists, err := c.dcStore.Indexer.GetByKey(key)
	if err != nil {
		glog.V(2).Infof("Unable to retrieve deployment config %q from store: %v", key, err)
		c.queue.AddRateLimited(key)
		return nil, err
	}
	if !exists {
		glog.V(4).Infof("Deployment config %q has been deleted", key)
		return nil, nil
	}

	return obj.(*deployapi.DeploymentConfig), nil
}
<|endoftext|>