<commit_before>package image

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

	"github.com/containers/image/types"
)

type descriptor struct {
	MediaType string `json:"mediaType"`
	Size      int64  `json:"size"`
	Digest    string `json:"digest"`
}

type manifestSchema2 struct {
	src               types.ImageSource
	SchemaVersion     int          `json:"schemaVersion"`
	MediaType         string       `json:"mediaType"`
	ConfigDescriptor  descriptor   `json:"config"`
	LayersDescriptors []descriptor `json:"layers"`
}

func manifestSchema2FromManifest(src types.ImageSource, manifest []byte) (genericManifest, error) {
	v2s2 := manifestSchema2{src: src}
	if err := json.Unmarshal(manifest, &v2s2); err != nil {
		return nil, err
	}
	return &v2s2, nil
}

func (m *manifestSchema2) serialize() ([]byte, error) {
	return json.Marshal(*m)
}

func (m *manifestSchema2) manifestMIMEType() string {
	return m.MediaType
}

// ConfigInfo returns a complete BlobInfo for the separate config object, or a BlobInfo{Digest:""} if there isn't a separate object.
func (m *manifestSchema2) ConfigInfo() types.BlobInfo {
	return types.BlobInfo{Digest: m.ConfigDescriptor.Digest, Size: m.ConfigDescriptor.Size}
}

// LayerInfos returns a list of BlobInfos of layers referenced by this image, in order (the root layer first, and then successive layered layers).
// The Digest field is guaranteed to be provided; Size may be -1.
// WARNING: The list may contain duplicates, and they are semantically relevant.
func (m *manifestSchema2) LayerInfos() []types.BlobInfo {
	blobs := []types.BlobInfo{}
	for _, layer := range m.LayersDescriptors {
		blobs = append(blobs, types.BlobInfo{Digest: layer.Digest, Size: layer.Size})
	}
	return blobs
}

func (m *manifestSchema2) config() ([]byte, error) {
	rawConfig, _, err := m.src.GetBlob(m.ConfigDescriptor.Digest)
	if err != nil {
		return nil, err
	}
	config, err := ioutil.ReadAll(rawConfig)
	rawConfig.Close()
	return config, err
}

func (m *manifestSchema2) imageInspectInfo() (*types.ImageInspectInfo, error) {
	config, err := m.config()
	if err != nil {
		return nil, err
	}
	v1 := &v1Image{}
	if err := json.Unmarshal(config, v1); err != nil {
		return nil, err
	}
	return &types.ImageInspectInfo{
		DockerVersion: v1.DockerVersion,
		Created:       v1.Created,
		Labels:        v1.Config.Labels,
		Architecture:  v1.Architecture,
		Os:            v1.OS,
	}, nil
}

// UpdatedImage returns a types.Image modified according to options.
// This does not change the state of the original Image object.
func (m *manifestSchema2) UpdatedImage(options types.ManifestUpdateOptions) (types.Image, error) {
	copy := *m
	if options.LayerInfos != nil {
		if len(copy.LayersDescriptors) != len(options.LayerInfos) {
			return nil, fmt.Errorf("Error preparing updated manifest: layer count changed from %d to %d", len(copy.LayersDescriptors), len(options.LayerInfos))
		}
		for i, info := range options.LayerInfos {
			copy.LayersDescriptors[i].Digest = info.Digest
			copy.LayersDescriptors[i].Size = info.Size
		}
	}
	return memoryImageFromManifest(&copy), nil
}
<commit_msg>Fix manifestSchema2.UpdatedImage<commit_after>package image

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

	"github.com/containers/image/types"
)

type descriptor struct {
	MediaType string `json:"mediaType"`
	Size      int64  `json:"size"`
	Digest    string `json:"digest"`
}

type manifestSchema2 struct {
	src               types.ImageSource
	SchemaVersion     int          `json:"schemaVersion"`
	MediaType         string       `json:"mediaType"`
	ConfigDescriptor  descriptor   `json:"config"`
	LayersDescriptors []descriptor `json:"layers"`
}

func manifestSchema2FromManifest(src types.ImageSource, manifest []byte) (genericManifest, error) {
	v2s2 := manifestSchema2{src: src}
	if err := json.Unmarshal(manifest, &v2s2); err != nil {
		return nil, err
	}
	return &v2s2, nil
}

func (m *manifestSchema2) serialize() ([]byte, error) {
	return json.Marshal(*m)
}

func (m *manifestSchema2) manifestMIMEType() string {
	return m.MediaType
}

// ConfigInfo returns a complete BlobInfo for the separate config object, or a BlobInfo{Digest:""} if there isn't a separate object.
func (m *manifestSchema2) ConfigInfo() types.BlobInfo {
	return types.BlobInfo{Digest: m.ConfigDescriptor.Digest, Size: m.ConfigDescriptor.Size}
}

// LayerInfos returns a list of BlobInfos of layers referenced by this image, in order (the root layer first, and then successive layered layers).
// The Digest field is guaranteed to be provided; Size may be -1.
// WARNING: The list may contain duplicates, and they are semantically relevant.
func (m *manifestSchema2) LayerInfos() []types.BlobInfo {
	blobs := []types.BlobInfo{}
	for _, layer := range m.LayersDescriptors {
		blobs = append(blobs, types.BlobInfo{Digest: layer.Digest, Size: layer.Size})
	}
	return blobs
}

func (m *manifestSchema2) config() ([]byte, error) {
	rawConfig, _, err := m.src.GetBlob(m.ConfigDescriptor.Digest)
	if err != nil {
		return nil, err
	}
	config, err := ioutil.ReadAll(rawConfig)
	rawConfig.Close()
	return config, err
}

func (m *manifestSchema2) imageInspectInfo() (*types.ImageInspectInfo, error) {
	config, err := m.config()
	if err != nil {
		return nil, err
	}
	v1 := &v1Image{}
	if err := json.Unmarshal(config, v1); err != nil {
		return nil, err
	}
	return &types.ImageInspectInfo{
		DockerVersion: v1.DockerVersion,
		Created:       v1.Created,
		Labels:        v1.Config.Labels,
		Architecture:  v1.Architecture,
		Os:            v1.OS,
	}, nil
}

// UpdatedImage returns a types.Image modified according to options.
// This does not change the state of the original Image object.
func (m *manifestSchema2) UpdatedImage(options types.ManifestUpdateOptions) (types.Image, error) {
	copy := *m // NOTE: This is not a deep copy, it still shares slices etc.
	if options.LayerInfos != nil {
		if len(copy.LayersDescriptors) != len(options.LayerInfos) {
			return nil, fmt.Errorf("Error preparing updated manifest: layer count changed from %d to %d", len(copy.LayersDescriptors), len(options.LayerInfos))
		}
		copy.LayersDescriptors = make([]descriptor, len(options.LayerInfos))
		for i, info := range options.LayerInfos {
			copy.LayersDescriptors[i].Digest = info.Digest
			copy.LayersDescriptors[i].Size = info.Size
		}
	}
	return memoryImageFromManifest(&copy), nil
}
<|endoftext|>


<commit_before>package server

import (
	"time"

	"github.com/golang/glog"
	"github.com/google/trillian/util"
)

// LogOperation defines a task that operates on logs. Examples are scheduling, signing,
// consistency checking or cleanup.
type LogOperation interface {
	Name() string
	ExecutePass([]int64, LogOperationManagerContext) bool
}

// LogOperationManagerContext bundles up the values so testing can be made easier
type LogOperationManagerContext struct {
	// done is a channel that provides an exit signal
	done chan struct{}
	// storageProvider is the log storage provider used to get active logs
	storageProvider LogStorageProviderFunc
	// batchSize is the batch size to be passed to tasks run by this manager
	batchSize int
	// sleepBetweenRuns is the time to pause after all active logs have processed a batch
	sleepBetweenRuns time.Duration
	// signInterval is the interval when we will create new STHs if no new leaves added
	signInterval time.Duration
	// oneShot is for use by tests only, it exits after one pass
	oneShot bool
	// timeSource allows us to mock this in tests
	timeSource util.TimeSource
}

// LogOperationManager controls scheduling activities for logs. At the moment it's very simple
// with a single task running over active logs one at a time. This will be expanded later.
// This is meant for embedding into the actual operation implementations and should not
// be created separately.
type LogOperationManager struct {
	context LogOperationManagerContext
	// logOperation is the task that gets run across active logs in the scheduling loop
	logOperation LogOperation
}

// NewLogOperationManager creates a new LogOperationManager instance.
func NewLogOperationManager(done chan struct{}, sp LogStorageProviderFunc, batchSize int, sleepBetweenRuns time.Duration, signInterval time.Duration, timeSource util.TimeSource, logOperation LogOperation) *LogOperationManager {
	return &LogOperationManager{context: LogOperationManagerContext{done: done, storageProvider: sp, batchSize: batchSize, sleepBetweenRuns: sleepBetweenRuns, signInterval: signInterval, timeSource: timeSource}, logOperation: logOperation}
}

// NewLogOperationManagerForTest creates a one-shot LogOperationManager instance, for use by tests only.
func NewLogOperationManagerForTest(done chan struct{}, sp LogStorageProviderFunc, batchSize int, sleepBetweenRuns time.Duration, signInterval time.Duration, timeSource util.TimeSource, logOperation LogOperation) *LogOperationManager {
	return &LogOperationManager{context: LogOperationManagerContext{done: done, storageProvider: sp, batchSize: batchSize, sleepBetweenRuns: sleepBetweenRuns, signInterval: signInterval, timeSource: timeSource, oneShot: true}, logOperation: logOperation}
}

func (l LogOperationManager) getLogsAndExecutePass() bool {
	// TODO(Martin2112) using log ID zero because we don't have an id for metadata ops
	// this API could improved
	provider, err := l.context.storageProvider(0)

	// If we get an error, we can't do anything but wait until the next run through
	if err != nil {
		glog.Warningf("Failed to get storage provider for run: %v", err)
		return false
	}

	tx, err := provider.Begin()

	if err != nil {
		glog.Warningf("Failed to get tx for run: %v", err)
		return false
	}

	// Inner loop is across all active logs, currently one at a time
	logIDs, err := tx.GetActiveLogIDs()

	if err != nil {
		glog.Warningf("Failed to get log list for run: %v", err)
		tx.Rollback()
		return false
	}

	if err := tx.Commit(); err != nil {
		glog.Warningf("Failed to commit getting logs: %v", err)
		return false
	}

	// Process each active log once, exit if we've seen a quit signal
	quit := l.logOperation.ExecutePass(logIDs, l.context)
	if quit {
		glog.Infof("Log operation manager shutting down")
	}

	return quit
}

// OperationLoop starts the manager working. It continues until told to exit.
// TODO(Martin2112): No mechanism for error reporting etc., this is OK for v1 but needs work
func (l LogOperationManager) OperationLoop() {
	glog.Infof("Log operation manager starting")

	// Outer loop, runs until terminated
	for {
		// Wait for the configured time before going for another pass
		time.Sleep(l.context.sleepBetweenRuns)

		quit := l.getLogsAndExecutePass()

		glog.Infof("Log operation manager pass complete")

		// We might want to bail out early when testing
		if quit || l.context.oneShot {
			return
		}
	}
}
<commit_msg>server: add comment<commit_after>package server

import (
	"time"

	"github.com/golang/glog"
	"github.com/google/trillian/util"
)

// LogOperation defines a task that operates on logs. Examples are scheduling, signing,
// consistency checking or cleanup.
type LogOperation interface {
	// Name returns the name of the task.
	Name() string
	// ExecutePass performs a single pass of processing on a set of logs; its
	// return value indicates whether the LogOperation task should terminate.
	ExecutePass(logIDs []int64, context LogOperationManagerContext) bool
}

// LogOperationManagerContext bundles up the values so testing can be made easier
type LogOperationManagerContext struct {
	// done is a channel that provides an exit signal
	done chan struct{}
	// storageProvider is the log storage provider used to get active logs
	storageProvider LogStorageProviderFunc
	// batchSize is the batch size to be passed to tasks run by this manager
	batchSize int
	// sleepBetweenRuns is the time to pause after all active logs have processed a batch
	sleepBetweenRuns time.Duration
	// signInterval is the interval when we will create new STHs if no new leaves added
	signInterval time.Duration
	// oneShot is for use by tests only, it exits after one pass
	oneShot bool
	// timeSource allows us to mock this in tests
	timeSource util.TimeSource
}

// LogOperationManager controls scheduling activities for logs. At the moment it's very simple
// with a single task running over active logs one at a time. This will be expanded later.
// This is meant for embedding into the actual operation implementations and should not
// be created separately.
type LogOperationManager struct {
	context LogOperationManagerContext
	// logOperation is the task that gets run across active logs in the scheduling loop
	logOperation LogOperation
}

// NewLogOperationManager creates a new LogOperationManager instance.
func NewLogOperationManager(done chan struct{}, sp LogStorageProviderFunc, batchSize int, sleepBetweenRuns time.Duration, signInterval time.Duration, timeSource util.TimeSource, logOperation LogOperation) *LogOperationManager {
	return &LogOperationManager{context: LogOperationManagerContext{done: done, storageProvider: sp, batchSize: batchSize, sleepBetweenRuns: sleepBetweenRuns, signInterval: signInterval, timeSource: timeSource}, logOperation: logOperation}
}

// NewLogOperationManagerForTest creates a one-shot LogOperationManager instance, for use by tests only.
func NewLogOperationManagerForTest(done chan struct{}, sp LogStorageProviderFunc, batchSize int, sleepBetweenRuns time.Duration, signInterval time.Duration, timeSource util.TimeSource, logOperation LogOperation) *LogOperationManager {
	return &LogOperationManager{context: LogOperationManagerContext{done: done, storageProvider: sp, batchSize: batchSize, sleepBetweenRuns: sleepBetweenRuns, signInterval: signInterval, timeSource: timeSource, oneShot: true}, logOperation: logOperation}
}

func (l LogOperationManager) getLogsAndExecutePass() bool {
	// TODO(Martin2112) using log ID zero because we don't have an id for metadata ops
	// this API could improved
	provider, err := l.context.storageProvider(0)

	// If we get an error, we can't do anything but wait until the next run through
	if err != nil {
		glog.Warningf("Failed to get storage provider for run: %v", err)
		return false
	}

	tx, err := provider.Begin()

	if err != nil {
		glog.Warningf("Failed to get tx for run: %v", err)
		return false
	}

	// Inner loop is across all active logs, currently one at a time
	logIDs, err := tx.GetActiveLogIDs()

	if err != nil {
		glog.Warningf("Failed to get log list for run: %v", err)
		tx.Rollback()
		return false
	}

	if err := tx.Commit(); err != nil {
		glog.Warningf("Failed to commit getting logs: %v", err)
		return false
	}

	// Process each active log once, exit if we've seen a quit signal
	quit := l.logOperation.ExecutePass(logIDs, l.context)
	if quit {
		glog.Infof("Log operation manager shutting down")
	}

	return quit
}

// OperationLoop starts the manager working. It continues until told to exit.
// TODO(Martin2112): No mechanism for error reporting etc., this is OK for v1 but needs work
func (l LogOperationManager) OperationLoop() {
	glog.Infof("Log operation manager starting")

	// Outer loop, runs until terminated
	for {
		// Wait for the configured time before going for another pass
		time.Sleep(l.context.sleepBetweenRuns)

		quit := l.getLogsAndExecutePass()

		glog.Infof("Log operation manager pass complete")

		// We might want to bail out early when testing
		if quit || l.context.oneShot {
			return
		}
	}
}
<|endoftext|>


<commit_before>package api

import "testing"
import "net/http/httptest"
import "fmt"
import "net/http"
import "io/ioutil"
import . "music"
import "encoding/json"

var (
  server *httptest.Server
)

func init() {
  server = httptest.NewServer(Handlers())
}

func TestJson(t *testing.T) {
  url := fmt.Sprintf("%s/search/x", server.URL)
  resp, err := http.Get(url)

  if err != nil {
    panic(err.Error())
  }

  body, err := ioutil.ReadAll(resp.Body)

  if err != nil {
    panic(err.Error())
  }

  var data Results
  jerr := json.Unmarshal(body, &data)

  if jerr != nil {
    t.Error(jerr)
  }

}
<commit_msg>make test fail<commit_after>package api

import "testing"
import "net/http/httptest"
import "fmt"
import "net/http"
import "io/ioutil"
import . "music"
import "encoding/json"

var (
  server *httptest.Server
)

func init() {
  server = httptest.NewServer(Handlers())
}

func TestJson(t *testing.T) {
  url := fmt.Sprintf("%s/search/x", server.URL)
  resp, err := http.Get(url)

  if err != nil {
    panic(err.Error())
  }

  body, err := ioutil.ReadAll(resp.Body)

  if err != nil {
    panic(err.Error())
  }

  var data Results
  jerr := json.Unmarshal(body, &data)

  if jerr != nil {
    t.Error(jerr)
  }

  t.Error("This should fail!")
}
<|endoftext|>


<commit_before>// tweetlib - A fully oauth-authenticated Go Twitter library
//
// Copyright 2011 The Tweetlib Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tweetlib

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"net/url"
	"reflect"
)

var _ = reflect.TypeOf

const (
	// URL to post tweets
	postURL = "http://api.twitter.com/1.1/statuses/update.json"
	// General URL for API calls
	apiURL = "https://api.twitter.com/1.1"
)

// twitterError represents an error generated by
// the Twitter API
type twitterError struct {
	Message string `json:message` // Error message
	Code    int    `json:code`    // Error code
}

// twitterErrorReply: contains a list of errors returned
// for a request to the Twitter API
type twitterErrorReply struct {
	Errors []twitterError `json:errors`
}

// Twitter error responses can actually contain
// multiple errors. This function preps them
// for a nice display
func (ter *twitterErrorReply) String() string {
	buf := bytes.NewBufferString("")
	for i := range ter.Errors {
		fmt.Fprintf(buf, "%s (%d)\n", ter.Errors[i].Message, ter.Errors[i].Code)
	}
	return buf.String()
}

// Checks whether the response is an error
func checkResponse(res *http.Response) (err error) {
	if res.StatusCode >= 200 && res.StatusCode <= 299 {
		return nil
	}
	slurp, err := ioutil.ReadAll(res.Body)
	fmt.Printf("%s\n", slurp)
	if err != nil {
		return err
	}
	var jerr twitterErrorReply
	if err = json.Unmarshal(slurp, &jerr); err != nil {
		return
	}
	return errors.New(jerr.String())
}

// Creates a new twitter client
func New(transport *Transport) (*Client, error) {
	if transport.Client() == nil {
		return nil, errors.New("client is nil")
	}
	c := &Client{client: transport.Client()}
	c.Timelines = &TimelinesService{c: c}
	c.Tweets = &TweetsService{c: c}
	c.Help = &HelpService{c: c}
	c.DM = &DMService{c: c}
	c.Users = &UsersService{c: c}
	c.Account = &AccountService{c: c}
	c.Lists = &ListsService{c: c}
	return c, nil
}

// Client: Twitter API client provides access to the various
// API services
type Client struct {
	client *http.Client

	// Timelines includes funcionality to work with collections of Tweets
	Timelines *TimelinesService

	// Tweets: facilities to deal with the atomic building blocks of Twitter,
	// 140-character status updates with additional associated metadata.
	Tweets *TweetsService

	// Methods to assist in working & debugging with the Twitter API.
	Help *HelpService

	// Facilities for finding relevant Tweets based on queries performed
	// by the users.
	Search *SearchService

	// Direct Messages are short, non-public messages sent between two users
	DM *DMService

	// Users are at the center of everything Twitter: they follow, they favorite,
	// and tweet & retweet.
	Users *UsersService

	// Account deals with account and profile functionality
	Account *AccountService

	// Lists provides functions to manage user lists
	Lists *ListsService
}

// perform a GET request to the appropriate endpoint and using the provided
// parameters. Will try to unmarshall the response to resp.
func (c *Client) get(endpoint string, params *url.Values, resp interface{}) (err error) {
	if params == nil {
		params = &url.Values{}
	}
	endpoint = fmt.Sprintf("%s/%s.json?%s", apiURL, endpoint, params.Encode())
	fmt.Println(endpoint)
	req, _ := http.NewRequest("GET", endpoint, nil)
	res, err := c.client.Do(req)
	if err != nil {
		return err
	}
	if err = checkResponse(res); err != nil {
		return err
	}
	//a,_ := ioutil.ReadAll(res.Body)
	//fmt.Printf("%s\n", a)
	if err = json.NewDecoder(res.Body).Decode(resp); err != nil && reflect.TypeOf(err) != reflect.TypeOf(&json.UnmarshalTypeError{}) {
		return err
	}
	return nil
}

// perform a POST request to the appropriate endpoint and using the provided
// parameters. Will try to unmarshall the response to resp.
func (c *Client) post(endpoint string, params *url.Values, resp interface{}) (err error) {
	body := bytes.NewBuffer([]byte(params.Encode()))
	endpoint = fmt.Sprintf("%s/%s.json?%s", apiURL, endpoint, params.Encode())
	req, _ := http.NewRequest("POST", endpoint, body)
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	res, err := c.client.Do(req)
	if err != nil {
		return err
	}
	if err = checkResponse(res); err != nil {
		return err
	}
	if err = json.NewDecoder(res.Body).Decode(resp); err != nil && reflect.TypeOf(err) != reflect.TypeOf(&json.UnmarshalTypeError{}) {
		return err
	}
	return nil
}

type TimelinesService struct {
	c *Client
}

// Returns the 20 (by default) most recent tweets containing a users's
// @screen_name for the authenticating user.
// THis method can only return up to 800 tweets (via the "count" optional
// parameter.
// See https://dev.twitter.com/docs/api/1.1/get/statuses/mentions_timeline
func (ts *TimelinesService) Mentions(opts *Optionals) (tweets *TweetList, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	tweets = &TweetList{}
	err = ts.c.get("statuses/mentions_timeline", &opts.Values, tweets)
	return
}

// Returns a collection of the most recent Tweets posted by the user indicated
// by the screen_name.
// See https://dev.twitter.com/docs/api/1.1/get/statuses/user_timeline
func (ts *TimelinesService) UserTimeline(screenname string, opts *Optionals) (tweets *TweetList, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	opts.Add("screen_name", screenname)
	tweets = new(TweetList)
	err = ts.c.get("statuses/user_timeline", &opts.Values, tweets)
	return
}

// Returns a collection of the most recent Tweets and retweets posted by
// the authenticating user and the users they follow.
// See https://dev.twitter.com/docs/api/1.1/get/statuses/home_timeline
func (ts *TimelinesService) HomeTimeline(opts *Optionals) (tweets *TweetList, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	tweets = new(TweetList)
	err = ts.c.get("statuses/home_timeline", &opts.Values, tweets)
	return
}

// Returns a collection of the  most recent tweets authored by the
// authenticating user that have been retweeted by others.
// See https://dev.twitter.com/docs/api/1.1/get/statuses/retweets_of_me
func (ts *TimelinesService) RetweetsOfMe(opts *Optionals) (tweets *TweetList, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	tweets = new(TweetList)
	err = ts.c.get("statuses/retweets_of_me", &opts.Values, tweets)
	return
}

type TweetsService struct {
	c *Client
}

// Update: posts a status update to Twitter
// See https://dev.twitter.com/docs/api/1.1/post/statuses/update
func (ts *TweetsService) Update(status string, opts *Optionals) (tweet *Tweet, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	opts.Add("status", status)
	tweet = &Tweet{}
	err = ts.c.post("statuses/update", &opts.Values, tweet)
	return tweet, err
}

// Returns up to 100 of the first retweets of a given tweet Id
func (ts *TweetsService) Retweets(id int64, opts *Optionals) (tweets *TweetList, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	tweets = &TweetList{}
	err = ts.c.get(fmt.Sprintf("statuses/retweets/%d", id), &opts.Values, tweets)
	return
}

// Returns a single Tweet, specified by the id parameter.
// The Tweet's author will also be embedded within the tweet.
func (ts *TweetsService) Show(id int64, opts *Optionals) (tweet *Tweet, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	opts.Add("id", id)
	tweet = &Tweet{}
	err = ts.c.get("statuses/show", &opts.Values, tweet)
	return
}

// Destroys the status specified by the required ID parameter.
// The authenticating user must be the author of the specified
// status. returns the destroyed tweet if successful
func (ts *TweetsService) Destroy(id int64, opts *Optionals) (tweet *Tweet, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	opts.Add("id", id)
	tweet = &Tweet{}
	err = ts.c.post(fmt.Sprintf("statuses/destroy/%d", id), &opts.Values, tweet)
	return tweet, err
}

// Retweets a tweet. Returns the original tweet with retweet details embedded.
func (ts *TweetsService) Retweet(id int64, opts *Optionals) (tweet *Tweet, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	opts.Add("id", id)
	tweet = &Tweet{}
	err = ts.c.post(fmt.Sprintf("statuses/retweet/%d", id), &opts.Values, tweet)
	return tweet, err
}

// Updates the authenticating user's current status and attaches media for
// upload. In other words, it creates a Tweet with a picture attached.
func (ts *TweetsService) UploadWithMedia(status string, media *TweetMedia, opts *Optionals) (tweet *Tweet, err error) {
	if opts == nil {
		opts = NewOptionals()
	}

	body := bytes.NewBufferString("")
	mp := multipart.NewWriter(body)
	mp.WriteField("status", status)
	for n, v := range opts.Values {
		mp.WriteField(n, v[0])
	}
	writer, err := mp.CreateFormFile("media[]", media.Filename)
	if err != nil {
		return nil, err
	}
	writer.Write(media.Data)
	header := fmt.Sprintf("multipart/form-data;boundary=%v", mp.Boundary())
	mp.Close()

	endpoint := fmt.Sprintf("%s/statuses/update_with_media.json?%s", apiURL, opts.Values.Encode())
	req, _ := http.NewRequest("POST", endpoint, body)
	req.Header.Set("Content-Type", header)
	res, err := ts.c.client.Do(req)
	if err != nil {
		return
	}
	if err = checkResponse(res); err != nil {
		return
	}
	if err = json.NewDecoder(res.Body).Decode(tweet); err != nil {
		return
	}
	return

}

type HelpService struct {
	c *Client
}

// Returns the current configuration used by Twitter including twitter.com
// slugs which are not usernames, maximum photo resolutions, and t.co URL
// lengths.
// See https://dev.twitter.com/docs/api/1.1/get/help/configuration
func (ts *HelpService) Configuration() (configuration *Configuration, err error) {
	configuration = &Configuration{}
	err = ts.c.get("help/configuration", nil, configuration)
	return
}

// Returns Twitter's Privacy Policy
// https://dev.twitter.com/docs/api/1.1/get/help/privacy
func (ts *HelpService) PrivacyPolicy() (privacyPolicy string, err error) {
	type pp struct {
		Text string `json:"privacy"`
	}
	ret := &pp{}
	err = ts.c.get("help/privacy", nil, ret)
	privacyPolicy = ret.Text
	return
}

// Returns Twitter's terms of service
// https://dev.twitter.com/docs/api/1.1/get/help/tos
func (ts *HelpService) TermsOfService() (string, error) {
	type tos struct {
		Text string `json:"tos"`
	}
	ret := &tos{}
	err := ts.c.get("help/tos", nil, ret)
	return ret.Text, err
}

// Returns Twitter's terms of service
// https://dev.twitter.com/docs/api/1.1/get/help/tos
func (ts *HelpService) Limits() (limits *Limits, err error) {
	limits = &Limits{}
	err = ts.c.get("application/rate_limit_status", nil, limits)
	return
}

type SearchService struct {
	c *Client
}

type DMService struct {
	c *Client
}

type UsersService struct {
	c *Client
}

type AccountService struct {
	c *Client
}

type ListsService struct {
	c *Client
}
<commit_msg>Completed Direct Messages<commit_after>// tweetlib - A fully oauth-authenticated Go Twitter library
//
// Copyright 2011 The Tweetlib Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tweetlib

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"net/url"
	"reflect"
)

var _ = reflect.TypeOf

const (
	// URL to post tweets
	postURL = "http://api.twitter.com/1.1/statuses/update.json"
	// General URL for API calls
	apiURL = "https://api.twitter.com/1.1"
)

// twitterError represents an error generated by
// the Twitter API
type twitterError struct {
	Message string `json:message` // Error message
	Code    int    `json:code`    // Error code
}

// twitterErrorReply: contains a list of errors returned
// for a request to the Twitter API
type twitterErrorReply struct {
	Errors []twitterError `json:errors`
}

// Twitter error responses can actually contain
// multiple errors. This function preps them
// for a nice display
func (ter *twitterErrorReply) String() string {
	buf := bytes.NewBufferString("")
	for i := range ter.Errors {
		fmt.Fprintf(buf, "%s (%d)\n", ter.Errors[i].Message, ter.Errors[i].Code)
	}
	return buf.String()
}

// Checks whether the response is an error
func checkResponse(res *http.Response) (err error) {
	if res.StatusCode >= 200 && res.StatusCode <= 299 {
		return nil
	}
	slurp, err := ioutil.ReadAll(res.Body)
	fmt.Printf("%s\n", slurp)
	if err != nil {
		return err
	}
	var jerr twitterErrorReply
	if err = json.Unmarshal(slurp, &jerr); err != nil {
		return
	}
	return errors.New(jerr.String())
}

// Creates a new twitter client
func New(transport *Transport) (*Client, error) {
	if transport.Client() == nil {
		return nil, errors.New("client is nil")
	}
	c := &Client{client: transport.Client()}
	c.Timelines = &TimelinesService{c: c}
	c.Tweets = &TweetsService{c: c}
	c.Help = &HelpService{c: c}
	c.DM = &DMService{c: c}
	c.Users = &UsersService{c: c}
	c.Account = &AccountService{c: c}
	c.Lists = &ListsService{c: c}
	return c, nil
}

// Client: Twitter API client provides access to the various
// API services
type Client struct {
	client *http.Client

	// Timelines includes funcionality to work with collections of Tweets
	Timelines *TimelinesService

	// Tweets: facilities to deal with the atomic building blocks of Twitter,
	// 140-character status updates with additional associated metadata.
	Tweets *TweetsService

	// Methods to assist in working & debugging with the Twitter API.
	Help *HelpService

	// Facilities for finding relevant Tweets based on queries performed
	// by the users.
	Search *SearchService

	// Direct Messages are short, non-public messages sent between two users
	DM *DMService

	// Users are at the center of everything Twitter: they follow, they favorite,
	// and tweet & retweet.
	Users *UsersService

	// Account deals with account and profile functionality
	Account *AccountService

	// Lists provides functions to manage user lists
	Lists *ListsService
}

// perform a GET request to the appropriate endpoint and using the provided
// parameters. Will try to unmarshall the response to resp.
func (c *Client) get(endpoint string, params *url.Values, resp interface{}) (err error) {
	if params == nil {
		params = &url.Values{}
	}
	endpoint = fmt.Sprintf("%s/%s.json?%s", apiURL, endpoint, params.Encode())
	fmt.Println(endpoint)
	req, _ := http.NewRequest("GET", endpoint, nil)
	res, err := c.client.Do(req)
	if err != nil {
		return err
	}
	if err = checkResponse(res); err != nil {
		return err
	}
	//a,_ := ioutil.ReadAll(res.Body)
	//fmt.Printf("%s\n", a)
	if err = json.NewDecoder(res.Body).Decode(resp); err != nil && reflect.TypeOf(err) != reflect.TypeOf(&json.UnmarshalTypeError{}) {
		return err
	}
	return nil
}

// perform a POST request to the appropriate endpoint and using the provided
// parameters. Will try to unmarshall the response to resp.
func (c *Client) post(endpoint string, params *url.Values, resp interface{}) (err error) {
	body := bytes.NewBuffer([]byte(params.Encode()))
	endpoint = fmt.Sprintf("%s/%s.json?%s", apiURL, endpoint, params.Encode())
	req, _ := http.NewRequest("POST", endpoint, body)
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	res, err := c.client.Do(req)
	if err != nil {
		return err
	}
	if err = checkResponse(res); err != nil {
		return err
	}
	if err = json.NewDecoder(res.Body).Decode(resp); err != nil && reflect.TypeOf(err) != reflect.TypeOf(&json.UnmarshalTypeError{}) {
		return err
	}
	return nil
}

type TimelinesService struct {
	c *Client
}

// Returns the 20 (by default) most recent tweets containing a users's
// @screen_name for the authenticating user.
// THis method can only return up to 800 tweets (via the "count" optional
// parameter.
// See https://dev.twitter.com/docs/api/1.1/get/statuses/mentions_timeline
func (ts *TimelinesService) Mentions(opts *Optionals) (tweets *TweetList, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	tweets = &TweetList{}
	err = ts.c.get("statuses/mentions_timeline", &opts.Values, tweets)
	return
}

// Returns a collection of the most recent Tweets posted by the user indicated
// by the screen_name.
// See https://dev.twitter.com/docs/api/1.1/get/statuses/user_timeline
func (ts *TimelinesService) UserTimeline(screenname string, opts *Optionals) (tweets *TweetList, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	opts.Add("screen_name", screenname)
	tweets = new(TweetList)
	err = ts.c.get("statuses/user_timeline", &opts.Values, tweets)
	return
}

// Returns a collection of the most recent Tweets and retweets posted by
// the authenticating user and the users they follow.
// See https://dev.twitter.com/docs/api/1.1/get/statuses/home_timeline
func (ts *TimelinesService) HomeTimeline(opts *Optionals) (tweets *TweetList, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	tweets = new(TweetList)
	err = ts.c.get("statuses/home_timeline", &opts.Values, tweets)
	return
}

// Returns a collection of the  most recent tweets authored by the
// authenticating user that have been retweeted by others.
// See https://dev.twitter.com/docs/api/1.1/get/statuses/retweets_of_me
func (ts *TimelinesService) RetweetsOfMe(opts *Optionals) (tweets *TweetList, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	tweets = new(TweetList)
	err = ts.c.get("statuses/retweets_of_me", &opts.Values, tweets)
	return
}

type TweetsService struct {
	c *Client
}

// Update: posts a status update to Twitter
// See https://dev.twitter.com/docs/api/1.1/post/statuses/update
func (ts *TweetsService) Update(status string, opts *Optionals) (tweet *Tweet, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	opts.Add("status", status)
	tweet = &Tweet{}
	err = ts.c.post("statuses/update", &opts.Values, tweet)
	return tweet, err
}

// Returns up to 100 of the first retweets of a given tweet Id
func (ts *TweetsService) Retweets(id int64, opts *Optionals) (tweets *TweetList, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	tweets = &TweetList{}
	err = ts.c.get(fmt.Sprintf("statuses/retweets/%d", id), &opts.Values, tweets)
	return
}

// Returns a single Tweet, specified by the id parameter.
// The Tweet's author will also be embedded within the tweet.
func (ts *TweetsService) Show(id int64, opts *Optionals) (tweet *Tweet, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	opts.Add("id", id)
	tweet = &Tweet{}
	err = ts.c.get("statuses/show", &opts.Values, tweet)
	return
}

// Destroys the status specified by the required ID parameter.
// The authenticating user must be the author of the specified
// status. returns the destroyed tweet if successful
func (ts *TweetsService) Destroy(id int64, opts *Optionals) (tweet *Tweet, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	opts.Add("id", id)
	tweet = &Tweet{}
	err = ts.c.post(fmt.Sprintf("statuses/destroy/%d", id), &opts.Values, tweet)
	return tweet, err
}

// Retweets a tweet. Returns the original tweet with retweet details embedded.
func (ts *TweetsService) Retweet(id int64, opts *Optionals) (tweet *Tweet, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	opts.Add("id", id)
	tweet = &Tweet{}
	err = ts.c.post(fmt.Sprintf("statuses/retweet/%d", id), &opts.Values, tweet)
	return tweet, err
}

// Updates the authenticating user's current status and attaches media for
// upload. In other words, it creates a Tweet with a picture attached.
func (ts *TweetsService) UploadWithMedia(status string, media *TweetMedia, opts *Optionals) (tweet *Tweet, err error) {
	if opts == nil {
		opts = NewOptionals()
	}

	body := bytes.NewBufferString("")
	mp := multipart.NewWriter(body)
	mp.WriteField("status", status)
	for n, v := range opts.Values {
		mp.WriteField(n, v[0])
	}
	writer, err := mp.CreateFormFile("media[]", media.Filename)
	if err != nil {
		return nil, err
	}
	writer.Write(media.Data)
	header := fmt.Sprintf("multipart/form-data;boundary=%v", mp.Boundary())
	mp.Close()

	endpoint := fmt.Sprintf("%s/statuses/update_with_media.json?%s", apiURL, opts.Values.Encode())
	req, _ := http.NewRequest("POST", endpoint, body)
	req.Header.Set("Content-Type", header)
	res, err := ts.c.client.Do(req)
	if err != nil {
		return
	}
	if err = checkResponse(res); err != nil {
		return
	}
	if err = json.NewDecoder(res.Body).Decode(tweet); err != nil {
		return
	}
	return

}

type HelpService struct {
	c *Client
}

// Returns the current configuration used by Twitter including twitter.com
// slugs which are not usernames, maximum photo resolutions, and t.co URL
// lengths.
// See https://dev.twitter.com/docs/api/1.1/get/help/configuration
func (ts *HelpService) Configuration() (configuration *Configuration, err error) {
	configuration = &Configuration{}
	err = ts.c.get("help/configuration", nil, configuration)
	return
}

// Returns Twitter's Privacy Policy
// https://dev.twitter.com/docs/api/1.1/get/help/privacy
func (ts *HelpService) PrivacyPolicy() (privacyPolicy string, err error) {
	type pp struct {
		Text string `json:"privacy"`
	}
	ret := &pp{}
	err = ts.c.get("help/privacy", nil, ret)
	privacyPolicy = ret.Text
	return
}

// Returns Twitter's terms of service
// https://dev.twitter.com/docs/api/1.1/get/help/tos
func (ts *HelpService) TermsOfService() (string, error) {
	type tos struct {
		Text string `json:"tos"`
	}
	ret := &tos{}
	err := ts.c.get("help/tos", nil, ret)
	return ret.Text, err
}

// Returns Twitter's terms of service
// https://dev.twitter.com/docs/api/1.1/get/help/tos
func (ts *HelpService) Limits() (limits *Limits, err error) {
	limits = &Limits{}
	err = ts.c.get("application/rate_limit_status", nil, limits)
	return
}

type SearchService struct {
	c *Client
}

type DMService struct {
	c *Client
}

// Returns the 20 most recent direct messages sent to the authenticating user.
// Includes detailed information about the sender and recipient user. You can
// request up to 200 direct messages per call, up to a maximum of 800 incoming DMs
// See https://dev.twitter.com/docs/api/1.1/get/direct_messages
func (ts *DMService) List(opts *Optionals) (messages *MessageList, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	messages = &MessageList{}
	err = ts.c.get("direct_messages", &opts.Values, messages)
	return
}

// Returns the 20 most recent direct messages sent by the authenticating user.
// Includes detailed information about the sender and recipient user. You can
// request up to 200 direct messages per call, up to a maximum of 800 outgoing DMs.
// See https://dev.twitter.com/docs/api/1.1/get/direct_messages/sent
func (ts *DMService) ListSent(opts *Optionals) (messages *MessageList, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	messages = &MessageList{}
	err = ts.c.get("direct_messages/sent", &opts.Values, messages)
	return
}

// Returns a single direct message, specified by an id parameter.
// See https://dev.twitter.com/docs/api/1.1/get/direct_messages/show
func (ts *DMService) Get(id int64, opts *Optionals) (message *Message, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	opts.Add("id", id)
	message = &Message{}
	err = ts.c.get("direct_messages/show", &opts.Values, message)
	return
}

// Destroys the direct message specified in the required ID parameter.
// The authenticating user must be the recipient of the specified direct
// message.
// See https://dev.twitter.com/docs/api/1.1/post/direct_messages/destroy
func (ts *DMService) Destroy(id int64, opts *Optionals) (message *Message, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	opts.Add("id", id)
	message = &Message{}
	err = ts.c.post("direct_messages/show", &opts.Values, message)
	return
}

// Sends a new direct message to the specified user from the authenticating user.
// See https://dev.twitter.com/docs/api/1.1/post/direct_messages/new
func (ts *DMService) Send(screenname, text string, opts *Optionals) (message *Message, err error) {
	if opts == nil {
		opts = NewOptionals()
	}
	opts.Add("screen_name", screenname)
	opts.Add("text", text)
	message = &Message{}
	err = ts.c.post("direct_messages/new", &opts.Values, message)
	return
}

type UsersService struct {
	c *Client
}

type AccountService struct {
	c *Client
}

type ListsService struct {
	c *Client
}
<|endoftext|>


<commit_before>/*
Copyright 2014 Google Inc. All rights reserved.

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

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

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

package e2e

import (
	"fmt"
	"strconv"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Events", func() {
	var c *client.Client

	BeforeEach(func() {
		var err error
		c, err = loadClient()
		Expect(err).NotTo(HaveOccurred())
	})

	It("should be sent by kubelets and the scheduler about pods scheduling and running", func() {
		provider := testContext.provider
		if len(provider) > 0 && provider != "gce" && provider != "gke" && provider != "aws" {
			By(fmt.Sprintf("skipping TestKubeletSendsEvent on cloud provider %s", provider))
			return
		}

		podClient := c.Pods(api.NamespaceDefault)

		By("creating the pod")
		name := "send-events-" + string(util.NewUUID())
		value := strconv.Itoa(time.Now().Nanosecond())
		pod := &api.Pod{
			ObjectMeta: api.ObjectMeta{
				Name: name,
				Labels: map[string]string{
					"name": "foo",
					"time": value,
				},
			},
			Spec: api.PodSpec{
				Containers: []api.Container{
					{
						Name:  "p",
						Image: "kubernetes/serve_hostname",
						Ports: []api.Port{{ContainerPort: 80, HostPort: 8080}},
					},
				},
			},
		}

		By("submitting the pod to kubernetes")
		_, err := podClient.Create(pod)
		if err != nil {
			Fail(fmt.Sprintf("Failed to create pod: %v", err))
		}
		defer func() {
			By("deleting the pod")
			defer GinkgoRecover()
			podClient.Delete(pod.Name)
		}()

		By("waiting for the pod to start running")
		err = waitForPodRunning(c, pod.Name, 300*time.Second)
		Expect(err).NotTo(HaveOccurred())

		By("verifying the pod is in kubernetes")
		pods, err := podClient.List(labels.SelectorFromSet(labels.Set(map[string]string{"time": value})))
		Expect(len(pods.Items)).To(Equal(1))

		By("retrieving the pod")
		podWithUid, err := podClient.Get(pod.Name)
		if err != nil {
			Fail(fmt.Sprintf("Failed to get pod: %v", err))
		}
		fmt.Printf("%+v\n", podWithUid)

		// Check for scheduler event about the pod.
		By("checking for scheduler event about the pod")
		events, err := c.Events(api.NamespaceDefault).List(
			labels.Everything(),
			labels.Set{
				"involvedObject.kind":      "Pod",
				"involvedObject.uid":       string(podWithUid.UID),
				"involvedObject.namespace": api.NamespaceDefault,
				"source":                   "scheduler",
			}.AsSelector(),
		)
		if err != nil {
			Fail(fmt.Sprintf("Error while listing events:", err))
		}
		Expect(len(events.Items)).ToNot(BeZero(), "scheduler events from running pod")
		fmt.Println("Saw scheduler event for our pod.")

		// Check for kubelet event about the pod.
		By("checking for kubelet event about the pod")
		events, err = c.Events(api.NamespaceDefault).List(
			labels.Everything(),
			labels.Set{
				"involvedObject.uid":       string(podWithUid.UID),
				"involvedObject.kind":      "BoundPod",
				"involvedObject.namespace": api.NamespaceDefault,
				"source":                   "kubelet",
			}.AsSelector(),
		)
		if err != nil {
			Fail(fmt.Sprintf("Error while listing events:", err))
		}
		Expect(len(events.Items)).ToNot(BeZero(), "kubelet events from running pod")
		fmt.Println("Saw kubelet event for our pod.")
	})
})
<commit_msg>Clean up events.go test by removing HostPort<commit_after>/*
Copyright 2014 Google Inc. All rights reserved.

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

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

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

package e2e

import (
	"fmt"
	"strconv"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Events", func() {
	var c *client.Client

	BeforeEach(func() {
		var err error
		c, err = loadClient()
		Expect(err).NotTo(HaveOccurred())
	})

	It("should be sent by kubelets and the scheduler about pods scheduling and running", func() {
		provider := testContext.provider
		if len(provider) > 0 && provider != "gce" && provider != "gke" && provider != "aws" {
			By(fmt.Sprintf("skipping TestKubeletSendsEvent on cloud provider %s", provider))
			return
		}

		podClient := c.Pods(api.NamespaceDefault)

		By("creating the pod")
		name := "send-events-" + string(util.NewUUID())
		value := strconv.Itoa(time.Now().Nanosecond())
		pod := &api.Pod{
			ObjectMeta: api.ObjectMeta{
				Name: name,
				Labels: map[string]string{
					"name": "foo",
					"time": value,
				},
			},
			Spec: api.PodSpec{
				Containers: []api.Container{
					{
						Name:  "p",
						Image: "kubernetes/serve_hostname",
						Ports: []api.Port{{ContainerPort: 80}},
					},
				},
			},
		}

		By("submitting the pod to kubernetes")
		_, err := podClient.Create(pod)
		if err != nil {
			Fail(fmt.Sprintf("Failed to create pod: %v", err))
		}
		defer func() {
			By("deleting the pod")
			defer GinkgoRecover()
			podClient.Delete(pod.Name)
		}()

		By("waiting for the pod to start running")
		err = waitForPodRunning(c, pod.Name, 300*time.Second)
		Expect(err).NotTo(HaveOccurred())

		By("verifying the pod is in kubernetes")
		pods, err := podClient.List(labels.SelectorFromSet(labels.Set(map[string]string{"time": value})))
		Expect(len(pods.Items)).To(Equal(1))

		By("retrieving the pod")
		podWithUid, err := podClient.Get(pod.Name)
		if err != nil {
			Fail(fmt.Sprintf("Failed to get pod: %v", err))
		}
		fmt.Printf("%+v\n", podWithUid)

		// Check for scheduler event about the pod.
		By("checking for scheduler event about the pod")
		events, err := c.Events(api.NamespaceDefault).List(
			labels.Everything(),
			labels.Set{
				"involvedObject.kind":      "Pod",
				"involvedObject.uid":       string(podWithUid.UID),
				"involvedObject.namespace": api.NamespaceDefault,
				"source":                   "scheduler",
			}.AsSelector(),
		)
		if err != nil {
			Fail(fmt.Sprintf("Error while listing events:", err))
		}
		Expect(len(events.Items)).ToNot(BeZero(), "scheduler events from running pod")
		fmt.Println("Saw scheduler event for our pod.")

		// Check for kubelet event about the pod.
		By("checking for kubelet event about the pod")
		events, err = c.Events(api.NamespaceDefault).List(
			labels.Everything(),
			labels.Set{
				"involvedObject.uid":       string(podWithUid.UID),
				"involvedObject.kind":      "BoundPod",
				"involvedObject.namespace": api.NamespaceDefault,
				"source":                   "kubelet",
			}.AsSelector(),
		)
		if err != nil {
			Fail(fmt.Sprintf("Error while listing events:", err))
		}
		Expect(len(events.Items)).ToNot(BeZero(), "kubelet events from running pod")
		fmt.Println("Saw kubelet event for our pod.")
	})
})
<|endoftext|>


<commit_before>// Copyright 2018 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package kbfsedits

import (
	"container/heap"
	"encoding/json"
	"sort"
	"sync"
)

const (
	// The max number of edits needed for each writer.
	maxEditsPerWriter    = 10
	maxWritersPerHistory = 10
)

type writerNotifications struct {
	writerName    string
	notifications notificationsByRevision
}

// writersByRevision sorts sets of per-writer notifications in reverse
// order by the revision of the latest notification for each writer.
type writersByRevision []*writerNotifications

func (wbr writersByRevision) Len() int {
	return len(wbr)
}

func (wbr writersByRevision) Less(i, j int) bool {
	// Some revisions come before no revisions.
	iHasZero := len(wbr[i].notifications) == 0
	jHasZero := len(wbr[j].notifications) == 0
	if jHasZero {
		return iHasZero
	} else if iHasZero {
		return false
	}

	// Reverse sort, so latest revisions come first.
	return wbr[i].notifications[0].Revision > wbr[j].notifications[0].Revision
}

func (wbr writersByRevision) Swap(i, j int) {
	wbr[i], wbr[j] = wbr[j], wbr[i]
}

func (wbr *writersByRevision) Push(x interface{}) {
	wn := x.(*writerNotifications)
	*wbr = append(*wbr, wn)
}

func (wbr *writersByRevision) Pop() interface{} {
	// The item to remove is the last item; heap has already swapped
	// it to the end.
	old := *wbr
	n := len(old)
	item := old[n-1]
	*wbr = old[0 : n-1]
	return item
}

// TlfHistory maintains a history of the last N file edits from each
// writer in the TLF.
//
// There will be two users of a TlfHistory instance:
//
//   * One user (likely something outside of the kbfsedits package,
//     e.g. libkbfs.folderBranchOps) will read notifications from the
//     corresponding TLF and add them to this history.  After adding a
//     batch or several batches of messages, it should call
//     `Recompute()`, and if some writers need more, earlier revisions,
//     it should fetch more notifications for the indicated writer and
//     repeat.
//
//   * The other user (within the kbfsedits package) will collate the
//     histories from multiple TlfHistory instances together using
//     `getHistory()` from each one.  It may also construct pretty
//     versions of individual edit histories for a particular TLF.
type TlfHistory struct {
	lock               sync.RWMutex
	byWriter           map[string]*writerNotifications
	computed           bool
	cachedHistory      writersByRevision
	cachedLoggedInUser string
}

// NewTlfHistory constructs a new TlfHistory instance.
func NewTlfHistory() *TlfHistory {
	return &TlfHistory{
		byWriter: make(map[string]*writerNotifications),
	}
}

// AddNotifications takes in a set of messages in this TLF by
// `writer`, and adds them to the history.  Once done adding messages,
// the caller should call `Recompute` to find out if more messages
// should be added for any particular writer.
func (th *TlfHistory) AddNotifications(
	writerName string, messages []string) (err error) {
	newEdits := make(notificationsByRevision, 0, len(messages))

	// Unmarshal and sort the new messages.
	for _, msg := range messages {
		var revList []NotificationMessage
		err := json.Unmarshal([]byte(msg), &revList)
		if err != nil {
			// The messages might be from a new version we don't
			// understand, so swallow the error.
			continue
		}

		for j := len(revList) - 1; j >= 0; j-- {
			revMsg := revList[j]
			if revMsg.Version != NotificationV2 {
				// Ignore messages that are too new for us to understand.
				continue
			}
			revMsg.numWithinRevision = j
			newEdits = append(newEdits, revMsg)
		}
	}

	th.lock.Lock()
	defer th.lock.Unlock()
	wn, existed := th.byWriter[writerName]
	if !existed {
		wn = &writerNotifications{writerName, nil}
	}
	oldLen := len(wn.notifications)
	newEdits = append(newEdits, wn.notifications...)
	sort.Sort(newEdits)
	wn.notifications = newEdits.uniquify()
	if len(wn.notifications) == oldLen {
		// No new messages.
		return nil
	}
	if !existed {
		th.byWriter[writerName] = wn
	}
	// Invalidate the cached results.
	th.computed = false
	th.cachedLoggedInUser = ""
	return nil
}

type fileEvent struct {
	delete  bool
	newName string
}

type recomputer struct {
	byWriter      map[string]*writerNotifications
	modifiedFiles map[string]map[string]bool // writer -> file -> bool
	fileEvents    map[string]fileEvent       // currentName -> ultimate fate
	numProcessed  map[string]int             // writer name -> num
}

func newRecomputer() *recomputer {
	return &recomputer{
		byWriter:      make(map[string]*writerNotifications),
		modifiedFiles: make(map[string]map[string]bool),
		fileEvents:    make(map[string]fileEvent),
		numProcessed:  make(map[string]int),
	}
}

// processNotification adds the notification to the recomputer's
// history if it is a create/modify for a file that hasn't yet been
// deleted.  If the file is renamed in a future revision, the added
// notification has the new name of the file.  processNotification
// should be called with notifications in reverse order of their
// revision number.
//
// It returns true if it has added enough notifications for the given
// writer, and the caller should not send any more for that writer.
func (r *recomputer) processNotification(
	writer string, notification NotificationMessage) (doTrim bool) {
	filename := notification.Filename
	r.numProcessed[writer]++

	// If the file is renamed in a future revision, rename it in the
	// notification.
	//
	// TODO(KBFS-3073): maybe we should check all the parent
	// directories for renames as well, so we can give a full, updated
	// path for older edits.  That would also help avoid showing edits
	// for files that were later deleted, but in a renamed directory.
	eventFilename := filename
	event, hasEvent := r.fileEvents[filename]
	if hasEvent && event.newName != "" {
		notification.Filename = event.newName
		filename = event.newName
	}

	// Keep only the creates and modifies for non-deleted files,
	// but remember the renames and deletes.
	switch notification.Type {
	case NotificationCreate, NotificationModify:
		// Disregard any file that's already been deleted.
		if hasEvent && event.delete {
			return false
		}

		// We only care about files, so skip dir and sym creates.
		if notification.FileType != EntryTypeFile {
			return false
		}

		// We only need one modify message per writer per file.
		if r.modifiedFiles[writer][filename] {
			return false
		}

		wn, ok := r.byWriter[writer]
		if !ok {
			wn = &writerNotifications{writer, nil}
			r.byWriter[writer] = wn
		}
		wn.notifications = append(wn.notifications, notification)

		modified, ok := r.modifiedFiles[writer]
		if !ok {
			modified = make(map[string]bool)
			r.modifiedFiles[writer] = modified
		}
		modified[filename] = true

		if len(wn.notifications) == maxEditsPerWriter {
			// We have enough edits for this user.
			return true
		}
	case NotificationRename:
		// If the file already has a final event, move that to the old
		// filename.  Otherwise, this is the final event.
		if hasEvent {
			r.fileEvents[notification.Params.OldFilename] = event
			delete(r.fileEvents, eventFilename)
		} else {
			r.fileEvents[notification.Params.OldFilename] =
				fileEvent{newName: eventFilename}
		}

		// The renamed file overwrote any existing file with the new
		// name.
		r.fileEvents[eventFilename] = fileEvent{delete: true}
	case NotificationDelete:
		r.fileEvents[eventFilename] = fileEvent{delete: true}
	}
	return false
}

func (th *TlfHistory) recomputeLocked(loggedInUser string) (
	history writersByRevision, writersWhoNeedMore map[string]bool) {
	writersWhoNeedMore = make(map[string]bool)

	// Copy the writer notifications into a heap.
	var writersHeap writersByRevision
	for _, wn := range th.byWriter {
		wnCopy := writerNotifications{
			writerName:    wn.writerName,
			notifications: make(notificationsByRevision, len(wn.notifications)),
		}
		copy(wnCopy.notifications, wn.notifications)
		writersHeap = append(writersHeap, &wnCopy)
	}
	heap.Init(&writersHeap)

	r := newRecomputer()

	// Iterate through the heap.  The writer with the next highest
	// revision will always be at index 0.  Process that writer's
	// first notification, then remove it and fix the heap so that the
	// next highest revision is at index 0.  That way events that
	// happen more recently (like deletes and renames) can be taken
	// into account when looking at older events.
	for writersHeap.Len() > 0 {
		nextWriter := writersHeap[0].writerName
		nextNotification := writersHeap[0].notifications[0]
		doTrim := r.processNotification(nextWriter, nextNotification)

		// Remove that notification, and fix the heap because this
		// writer has a different newest revision.
		if doTrim {
			// Trim all earlier revisions because they won't be needed
			// for the cached history.
			numProcessed := r.numProcessed[nextWriter]
			th.byWriter[nextWriter].notifications =
				th.byWriter[nextWriter].notifications[:numProcessed]
		} else {
			writersHeap[0].notifications = writersHeap[0].notifications[1:]
		}
		if len(writersHeap[0].notifications) == 0 || doTrim {
			heap.Pop(&writersHeap)
		} else {
			heap.Fix(&writersHeap, 0)
		}
	}

	history = make(writersByRevision, 0, len(r.byWriter))
	for writerName := range th.byWriter {
		wn := r.byWriter[writerName]
		if wn != nil && len(wn.notifications) > 0 {
			history = append(history, wn)
		}
		if wn == nil || len(wn.notifications) < maxEditsPerWriter {
			writersWhoNeedMore[writerName] = true
		}
	}
	sort.Sort(history)
	if len(history) > maxWritersPerHistory {
		// Garbage-collect any writers that don't appear in the history.
		loggedInIndex := -1
		for i := maxWritersPerHistory; i < len(history); i++ {
			if history[i].writerName == loggedInUser {
				// Don't purge the logged-in user.
				loggedInIndex = i
				continue
			}
			delete(th.byWriter, history[i].writerName)
			delete(writersWhoNeedMore, history[i].writerName)
		}
		if loggedInIndex > 0 {
			// Keep the logged-in user as the last entry.  Note that
			// `loggedInIndex` is guaranteed to be greater or equal to
			// `maxWritersPerHistory`, so this logic swaps in the
			// loggedIn entry (and doesn't duplicate it).
			loggedIn := history[loggedInIndex]
			history = history[:maxWritersPerHistory]
			history[maxWritersPerHistory-1] = loggedIn
		} else {
			history = history[:maxWritersPerHistory]
		}
	}
	th.computed = true
	th.cachedHistory = history
	th.cachedLoggedInUser = loggedInUser
	return history, writersWhoNeedMore
}

func (th *TlfHistory) getHistoryIfCached() (
	cached bool, history writersByRevision, loggedInUser string) {
	th.lock.RLock()
	defer th.lock.RUnlock()
	if th.computed {
		return true, th.cachedHistory, th.cachedLoggedInUser
	}
	return false, nil, ""
}

func (th *TlfHistory) getHistory(loggedInUser string) writersByRevision {
	cached, history, cachedLoggedInUser := th.getHistoryIfCached()
	if cached && loggedInUser == cachedLoggedInUser {
		return history
	}

	th.lock.Lock()
	defer th.lock.Unlock()
	if th.computed {
		// Maybe another goroutine got the lock and recomuted the
		// history since we checked above.
		return th.cachedHistory
	}
	history, _ = th.recomputeLocked(loggedInUser)
	return history
}

// Recompute processes (and caches) the history so that it reflects
// all recently-added notifications, and returns the names of writers
// which don't yet have the maximum number of edits in the history.
func (th *TlfHistory) Recompute(loggedInUser string) (
	writersWhoNeedMore map[string]bool) {
	th.lock.Lock()
	defer th.lock.Unlock()
	_, writersWhoNeedMore = th.recomputeLocked(loggedInUser)
	return writersWhoNeedMore
}
<commit_msg>kbfsedits: cleaner logged-in user swap<commit_after>// Copyright 2018 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package kbfsedits

import (
	"container/heap"
	"encoding/json"
	"sort"
	"sync"
)

const (
	// The max number of edits needed for each writer.
	maxEditsPerWriter    = 10
	maxWritersPerHistory = 10
)

type writerNotifications struct {
	writerName    string
	notifications notificationsByRevision
}

// writersByRevision sorts sets of per-writer notifications in reverse
// order by the revision of the latest notification for each writer.
type writersByRevision []*writerNotifications

func (wbr writersByRevision) Len() int {
	return len(wbr)
}

func (wbr writersByRevision) Less(i, j int) bool {
	// Some revisions come before no revisions.
	iHasZero := len(wbr[i].notifications) == 0
	jHasZero := len(wbr[j].notifications) == 0
	if jHasZero {
		return iHasZero
	} else if iHasZero {
		return false
	}

	// Reverse sort, so latest revisions come first.
	return wbr[i].notifications[0].Revision > wbr[j].notifications[0].Revision
}

func (wbr writersByRevision) Swap(i, j int) {
	wbr[i], wbr[j] = wbr[j], wbr[i]
}

func (wbr *writersByRevision) Push(x interface{}) {
	wn := x.(*writerNotifications)
	*wbr = append(*wbr, wn)
}

func (wbr *writersByRevision) Pop() interface{} {
	// The item to remove is the last item; heap has already swapped
	// it to the end.
	old := *wbr
	n := len(old)
	item := old[n-1]
	*wbr = old[0 : n-1]
	return item
}

// TlfHistory maintains a history of the last N file edits from each
// writer in the TLF.
//
// There will be two users of a TlfHistory instance:
//
//   * One user (likely something outside of the kbfsedits package,
//     e.g. libkbfs.folderBranchOps) will read notifications from the
//     corresponding TLF and add them to this history.  After adding a
//     batch or several batches of messages, it should call
//     `Recompute()`, and if some writers need more, earlier revisions,
//     it should fetch more notifications for the indicated writer and
//     repeat.
//
//   * The other user (within the kbfsedits package) will collate the
//     histories from multiple TlfHistory instances together using
//     `getHistory()` from each one.  It may also construct pretty
//     versions of individual edit histories for a particular TLF.
type TlfHistory struct {
	lock               sync.RWMutex
	byWriter           map[string]*writerNotifications
	computed           bool
	cachedHistory      writersByRevision
	cachedLoggedInUser string
}

// NewTlfHistory constructs a new TlfHistory instance.
func NewTlfHistory() *TlfHistory {
	return &TlfHistory{
		byWriter: make(map[string]*writerNotifications),
	}
}

// AddNotifications takes in a set of messages in this TLF by
// `writer`, and adds them to the history.  Once done adding messages,
// the caller should call `Recompute` to find out if more messages
// should be added for any particular writer.
func (th *TlfHistory) AddNotifications(
	writerName string, messages []string) (err error) {
	newEdits := make(notificationsByRevision, 0, len(messages))

	// Unmarshal and sort the new messages.
	for _, msg := range messages {
		var revList []NotificationMessage
		err := json.Unmarshal([]byte(msg), &revList)
		if err != nil {
			// The messages might be from a new version we don't
			// understand, so swallow the error.
			continue
		}

		for j := len(revList) - 1; j >= 0; j-- {
			revMsg := revList[j]
			if revMsg.Version != NotificationV2 {
				// Ignore messages that are too new for us to understand.
				continue
			}
			revMsg.numWithinRevision = j
			newEdits = append(newEdits, revMsg)
		}
	}

	th.lock.Lock()
	defer th.lock.Unlock()
	wn, existed := th.byWriter[writerName]
	if !existed {
		wn = &writerNotifications{writerName, nil}
	}
	oldLen := len(wn.notifications)
	newEdits = append(newEdits, wn.notifications...)
	sort.Sort(newEdits)
	wn.notifications = newEdits.uniquify()
	if len(wn.notifications) == oldLen {
		// No new messages.
		return nil
	}
	if !existed {
		th.byWriter[writerName] = wn
	}
	// Invalidate the cached results.
	th.computed = false
	th.cachedLoggedInUser = ""
	return nil
}

type fileEvent struct {
	delete  bool
	newName string
}

type recomputer struct {
	byWriter      map[string]*writerNotifications
	modifiedFiles map[string]map[string]bool // writer -> file -> bool
	fileEvents    map[string]fileEvent       // currentName -> ultimate fate
	numProcessed  map[string]int             // writer name -> num
}

func newRecomputer() *recomputer {
	return &recomputer{
		byWriter:      make(map[string]*writerNotifications),
		modifiedFiles: make(map[string]map[string]bool),
		fileEvents:    make(map[string]fileEvent),
		numProcessed:  make(map[string]int),
	}
}

// processNotification adds the notification to the recomputer's
// history if it is a create/modify for a file that hasn't yet been
// deleted.  If the file is renamed in a future revision, the added
// notification has the new name of the file.  processNotification
// should be called with notifications in reverse order of their
// revision number.
//
// It returns true if it has added enough notifications for the given
// writer, and the caller should not send any more for that writer.
func (r *recomputer) processNotification(
	writer string, notification NotificationMessage) (doTrim bool) {
	filename := notification.Filename
	r.numProcessed[writer]++

	// If the file is renamed in a future revision, rename it in the
	// notification.
	//
	// TODO(KBFS-3073): maybe we should check all the parent
	// directories for renames as well, so we can give a full, updated
	// path for older edits.  That would also help avoid showing edits
	// for files that were later deleted, but in a renamed directory.
	eventFilename := filename
	event, hasEvent := r.fileEvents[filename]
	if hasEvent && event.newName != "" {
		notification.Filename = event.newName
		filename = event.newName
	}

	// Keep only the creates and modifies for non-deleted files,
	// but remember the renames and deletes.
	switch notification.Type {
	case NotificationCreate, NotificationModify:
		// Disregard any file that's already been deleted.
		if hasEvent && event.delete {
			return false
		}

		// We only care about files, so skip dir and sym creates.
		if notification.FileType != EntryTypeFile {
			return false
		}

		// We only need one modify message per writer per file.
		if r.modifiedFiles[writer][filename] {
			return false
		}

		wn, ok := r.byWriter[writer]
		if !ok {
			wn = &writerNotifications{writer, nil}
			r.byWriter[writer] = wn
		}
		wn.notifications = append(wn.notifications, notification)

		modified, ok := r.modifiedFiles[writer]
		if !ok {
			modified = make(map[string]bool)
			r.modifiedFiles[writer] = modified
		}
		modified[filename] = true

		if len(wn.notifications) == maxEditsPerWriter {
			// We have enough edits for this user.
			return true
		}
	case NotificationRename:
		// If the file already has a final event, move that to the old
		// filename.  Otherwise, this is the final event.
		if hasEvent {
			r.fileEvents[notification.Params.OldFilename] = event
			delete(r.fileEvents, eventFilename)
		} else {
			r.fileEvents[notification.Params.OldFilename] =
				fileEvent{newName: eventFilename}
		}

		// The renamed file overwrote any existing file with the new
		// name.
		r.fileEvents[eventFilename] = fileEvent{delete: true}
	case NotificationDelete:
		r.fileEvents[eventFilename] = fileEvent{delete: true}
	}
	return false
}

func (th *TlfHistory) recomputeLocked(loggedInUser string) (
	history writersByRevision, writersWhoNeedMore map[string]bool) {
	writersWhoNeedMore = make(map[string]bool)

	// Copy the writer notifications into a heap.
	var writersHeap writersByRevision
	for _, wn := range th.byWriter {
		wnCopy := writerNotifications{
			writerName:    wn.writerName,
			notifications: make(notificationsByRevision, len(wn.notifications)),
		}
		copy(wnCopy.notifications, wn.notifications)
		writersHeap = append(writersHeap, &wnCopy)
	}
	heap.Init(&writersHeap)

	r := newRecomputer()

	// Iterate through the heap.  The writer with the next highest
	// revision will always be at index 0.  Process that writer's
	// first notification, then remove it and fix the heap so that the
	// next highest revision is at index 0.  That way events that
	// happen more recently (like deletes and renames) can be taken
	// into account when looking at older events.
	for writersHeap.Len() > 0 {
		nextWriter := writersHeap[0].writerName
		nextNotification := writersHeap[0].notifications[0]
		doTrim := r.processNotification(nextWriter, nextNotification)

		// Remove that notification, and fix the heap because this
		// writer has a different newest revision.
		if doTrim {
			// Trim all earlier revisions because they won't be needed
			// for the cached history.
			numProcessed := r.numProcessed[nextWriter]
			th.byWriter[nextWriter].notifications =
				th.byWriter[nextWriter].notifications[:numProcessed]
		} else {
			writersHeap[0].notifications = writersHeap[0].notifications[1:]
		}
		if len(writersHeap[0].notifications) == 0 || doTrim {
			heap.Pop(&writersHeap)
		} else {
			heap.Fix(&writersHeap, 0)
		}
	}

	history = make(writersByRevision, 0, len(r.byWriter))
	for writerName := range th.byWriter {
		wn := r.byWriter[writerName]
		if wn != nil && len(wn.notifications) > 0 {
			history = append(history, wn)
		}
		if wn == nil || len(wn.notifications) < maxEditsPerWriter {
			writersWhoNeedMore[writerName] = true
		}
	}
	sort.Sort(history)
	if len(history) > maxWritersPerHistory {
		// Garbage-collect any writers that don't appear in the history.
		loggedInIndex := -1
		for i := maxWritersPerHistory; i < len(history); i++ {
			if history[i].writerName == loggedInUser {
				// Don't purge the logged-in user.
				loggedInIndex = i
				continue
			}
			delete(th.byWriter, history[i].writerName)
			delete(writersWhoNeedMore, history[i].writerName)
		}
		if loggedInIndex > 0 {
			// Keep the logged-in user as the last entry.  Note that
			// `loggedInIndex` is guaranteed to be greater or equal to
			// `maxWritersPerHistory`, so this logic swaps in the
			// loggedIn entry (and doesn't duplicate it).
			history = append(
				history[:maxWritersPerHistory-1], history[loggedInIndex])
		} else {
			history = history[:maxWritersPerHistory]
		}
	}
	th.computed = true
	th.cachedHistory = history
	th.cachedLoggedInUser = loggedInUser
	return history, writersWhoNeedMore
}

func (th *TlfHistory) getHistoryIfCached() (
	cached bool, history writersByRevision, loggedInUser string) {
	th.lock.RLock()
	defer th.lock.RUnlock()
	if th.computed {
		return true, th.cachedHistory, th.cachedLoggedInUser
	}
	return false, nil, ""
}

func (th *TlfHistory) getHistory(loggedInUser string) writersByRevision {
	cached, history, cachedLoggedInUser := th.getHistoryIfCached()
	if cached && loggedInUser == cachedLoggedInUser {
		return history
	}

	th.lock.Lock()
	defer th.lock.Unlock()
	if th.computed {
		// Maybe another goroutine got the lock and recomuted the
		// history since we checked above.
		return th.cachedHistory
	}
	history, _ = th.recomputeLocked(loggedInUser)
	return history
}

// Recompute processes (and caches) the history so that it reflects
// all recently-added notifications, and returns the names of writers
// which don't yet have the maximum number of edits in the history.
func (th *TlfHistory) Recompute(loggedInUser string) (
	writersWhoNeedMore map[string]bool) {
	th.lock.Lock()
	defer th.lock.Unlock()
	_, writersWhoNeedMore = th.recomputeLocked(loggedInUser)
	return writersWhoNeedMore
}
<|endoftext|>


<commit_before>package buildpacks

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"runtime"
	"strings"

	"github.com/Masterminds/semver"
	pack "github.com/buildpacks/pack/pkg/client"
	"github.com/buildpacks/pack/pkg/logging"
	"github.com/docker/docker/client"
	"github.com/heroku/color"

	fn "knative.dev/func"
	"knative.dev/func/builders"
	"knative.dev/func/docker"
)

// DefaultName when no WithName option is provided to NewBuilder
const DefaultName = builders.Pack

var (
	DefaultBuilderImages = map[string]string{
		"node":       "gcr.io/paketo-buildpacks/builder:base",
		"nodejs":     "gcr.io/paketo-buildpacks/builder:base",
		"typescript": "gcr.io/paketo-buildpacks/builder:base",
		"go":         "gcr.io/paketo-buildpacks/builder:base",
		"python":     "gcr.io/paketo-buildpacks/builder:base",
		"quarkus":    "gcr.io/paketo-buildpacks/builder:base",
		"rust":       "gcr.io/paketo-buildpacks/builder:base",
		"springboot": "gcr.io/paketo-buildpacks/builder:base",
	}

	trustedBuilderImagePrefixes = []string{
		"quay.io/boson",
		"gcr.io/paketo-buildpacks",
		"docker.io/paketobuildpacks",
	}

	v330 = semver.MustParse("v3.3.0") // for checking podman version
)

// Builder will build Function using Pack.
type Builder struct {
	name    string
	verbose bool
	// in non-verbose mode contains std[err,out], so it can be printed on error
	outBuff bytes.Buffer
	logger  logging.Logger
	impl    Impl
}

// Impl allows for the underlying implementation to be mocked for tests.
type Impl interface {
	Build(context.Context, pack.BuildOptions) error
}

// NewBuilder instantiates a Buildpack-based Builder
func NewBuilder(options ...Option) *Builder {
	b := &Builder{name: DefaultName}
	for _, o := range options {
		o(b)
	}

	// Stream logs to stdout or buffer only for display on error.
	if b.verbose {
		b.logger = logging.NewLogWithWriters(color.Stdout(), color.Stderr(), logging.WithVerbose())
	} else {
		b.logger = logging.NewSimpleLogger(&b.outBuff)
	}

	return b
}

type Option func(*Builder)

func WithName(n string) Option {
	return func(b *Builder) {
		b.name = n
	}
}

func WithVerbose(v bool) Option {
	return func(b *Builder) {
		b.verbose = v
	}
}

func WithImpl(i Impl) Option {
	return func(b *Builder) {
		b.impl = i
	}
}

// Build the Function at path.
func (b *Builder) Build(ctx context.Context, f fn.Function) (err error) {
	// Builder image from the function if defined, default otherwise.
	image, err := BuilderImage(f, b.name)
	if err != nil {
		return
	}

	// Pack build options
	opts := pack.BuildOptions{
		AppPath:        f.Root,
		Image:          f.Image,
		LifecycleImage: "quay.io/boson/lifecycle:0.14.3",
		Builder:        image,
		Buildpacks:     f.Build.Buildpacks,
		ContainerConfig: struct {
			Network string
			Volumes []string
		}{Network: "", Volumes: nil},
	}
	if opts.Env, err = fn.Interpolate(f.Build.BuildEnvs); err != nil {
		return err
	}
	if runtime.GOOS == "linux" {
		opts.ContainerConfig.Network = "host"
	}

	var impl = b.impl
	// Instantiate the pack build client implementation
	// (and update build opts as necessary)
	if impl == nil {
		var (
			cli        client.CommonAPIClient
			dockerHost string
		)

		cli, dockerHost, err = docker.NewClient(client.DefaultDockerHost)
		if err != nil {
			return fmt.Errorf("cannot craete docker client: %w", err)
		}
		defer cli.Close()

		if impl, err = newImpl(ctx, cli, dockerHost, &opts, b.logger); err != nil {
			return fmt.Errorf("cannot create pack client: %w", err)
		}
	}

	// Perform the build
	if err = impl.Build(ctx, opts); err != nil {
		if ctx.Err() != nil {
			return // SIGINT
		} else if !b.verbose {
			err = fmt.Errorf("failed to build the function: %w", err)
			fmt.Fprintln(color.Stderr(), "")
			_, _ = io.Copy(color.Stderr(), &b.outBuff)
			fmt.Fprintln(color.Stderr(), "")
		}
	}
	return
}

// newImpl returns an instance of the builder implementation.  Note that this
// also mutates the provided options' DockerHost and TrustBuilder.
func newImpl(ctx context.Context, cli client.CommonAPIClient, dockerHost string, opts *pack.BuildOptions, logger logging.Logger) (impl Impl, err error) {
	opts.DockerHost = dockerHost

	daemonIsPodmanPreV330, err := podmanPreV330(ctx, cli)
	if err != nil {
		return
	}

	opts.TrustBuilder = func(_ string) bool {
		if daemonIsPodmanPreV330 {
			return false
		}
		for _, v := range trustedBuilderImagePrefixes {
			if strings.HasPrefix(opts.Builder, v) {
				return true
			}
		}
		return false
	}

	// Client with a logger which is enabled if in Verbose mode and a dockerClient that supports SSH docker daemon connection.
	return pack.NewClient(pack.WithLogger(logger), pack.WithDockerClient(cli))
}

// Builder Image chooses the correct builder image or defaults.
func BuilderImage(f fn.Function, builderName string) (string, error) {
	return builders.Image(f, builderName, DefaultBuilderImages)
}

// podmanPreV330 returns if the daemon is podman pre v330 or errors trying.
func podmanPreV330(ctx context.Context, cli client.CommonAPIClient) (b bool, err error) {
	version, err := cli.ServerVersion(ctx)
	if err != nil {
		return
	}

	for _, component := range version.Components {
		if component.Name == "Podman Engine" {
			v := semver.MustParse(version.Version)
			if v.Compare(v330) < 0 {
				return true, nil
			}
			break
		}
	}
	return
}

// Errors

type ErrRuntimeRequired struct{}

func (e ErrRuntimeRequired) Error() string {
	return "Pack requires the Function define a language runtime"
}

type ErrRuntimeNotSupported struct {
	Runtime string
}

func (e ErrRuntimeNotSupported) Error() string {
	return fmt.Sprintf("Pack builder has no default builder image for the '%v' language runtime.  Please provide one.", e.Runtime)
}
<commit_msg>chore: update lifecycle image to v0.15.0 (#1403)<commit_after>package buildpacks

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"runtime"
	"strings"

	"github.com/Masterminds/semver"
	pack "github.com/buildpacks/pack/pkg/client"
	"github.com/buildpacks/pack/pkg/logging"
	"github.com/docker/docker/client"
	"github.com/heroku/color"

	fn "knative.dev/func"
	"knative.dev/func/builders"
	"knative.dev/func/docker"
)

// DefaultName when no WithName option is provided to NewBuilder
const DefaultName = builders.Pack

var (
	DefaultBuilderImages = map[string]string{
		"node":       "gcr.io/paketo-buildpacks/builder:base",
		"nodejs":     "gcr.io/paketo-buildpacks/builder:base",
		"typescript": "gcr.io/paketo-buildpacks/builder:base",
		"go":         "gcr.io/paketo-buildpacks/builder:base",
		"python":     "gcr.io/paketo-buildpacks/builder:base",
		"quarkus":    "gcr.io/paketo-buildpacks/builder:base",
		"rust":       "gcr.io/paketo-buildpacks/builder:base",
		"springboot": "gcr.io/paketo-buildpacks/builder:base",
	}

	trustedBuilderImagePrefixes = []string{
		"quay.io/boson",
		"gcr.io/paketo-buildpacks",
		"docker.io/paketobuildpacks",
	}

	v330 = semver.MustParse("v3.3.0") // for checking podman version
)

// Builder will build Function using Pack.
type Builder struct {
	name    string
	verbose bool
	// in non-verbose mode contains std[err,out], so it can be printed on error
	outBuff bytes.Buffer
	logger  logging.Logger
	impl    Impl
}

// Impl allows for the underlying implementation to be mocked for tests.
type Impl interface {
	Build(context.Context, pack.BuildOptions) error
}

// NewBuilder instantiates a Buildpack-based Builder
func NewBuilder(options ...Option) *Builder {
	b := &Builder{name: DefaultName}
	for _, o := range options {
		o(b)
	}

	// Stream logs to stdout or buffer only for display on error.
	if b.verbose {
		b.logger = logging.NewLogWithWriters(color.Stdout(), color.Stderr(), logging.WithVerbose())
	} else {
		b.logger = logging.NewSimpleLogger(&b.outBuff)
	}

	return b
}

type Option func(*Builder)

func WithName(n string) Option {
	return func(b *Builder) {
		b.name = n
	}
}

func WithVerbose(v bool) Option {
	return func(b *Builder) {
		b.verbose = v
	}
}

func WithImpl(i Impl) Option {
	return func(b *Builder) {
		b.impl = i
	}
}

var DefaultLifecycleImage = "quay.io/boson/lifecycle@sha256:79dac4658ea5e9b42c3aece456f8a9c20f9e1a91d9d4648717967d88eaa7d9ef"

// Build the Function at path.
func (b *Builder) Build(ctx context.Context, f fn.Function) (err error) {
	// Builder image from the function if defined, default otherwise.
	image, err := BuilderImage(f, b.name)
	if err != nil {
		return
	}

	// Pack build options
	opts := pack.BuildOptions{
		AppPath:        f.Root,
		Image:          f.Image,
		LifecycleImage: DefaultLifecycleImage,
		Builder:        image,
		Buildpacks:     f.Build.Buildpacks,
		ContainerConfig: struct {
			Network string
			Volumes []string
		}{Network: "", Volumes: nil},
	}
	if opts.Env, err = fn.Interpolate(f.Build.BuildEnvs); err != nil {
		return err
	}
	if runtime.GOOS == "linux" {
		opts.ContainerConfig.Network = "host"
	}

	var impl = b.impl
	// Instantiate the pack build client implementation
	// (and update build opts as necessary)
	if impl == nil {
		var (
			cli        client.CommonAPIClient
			dockerHost string
		)

		cli, dockerHost, err = docker.NewClient(client.DefaultDockerHost)
		if err != nil {
			return fmt.Errorf("cannot craete docker client: %w", err)
		}
		defer cli.Close()

		if impl, err = newImpl(ctx, cli, dockerHost, &opts, b.logger); err != nil {
			return fmt.Errorf("cannot create pack client: %w", err)
		}
	}

	// Perform the build
	if err = impl.Build(ctx, opts); err != nil {
		if ctx.Err() != nil {
			return // SIGINT
		} else if !b.verbose {
			err = fmt.Errorf("failed to build the function: %w", err)
			fmt.Fprintln(color.Stderr(), "")
			_, _ = io.Copy(color.Stderr(), &b.outBuff)
			fmt.Fprintln(color.Stderr(), "")
		}
	}
	return
}

// newImpl returns an instance of the builder implementation.  Note that this
// also mutates the provided options' DockerHost and TrustBuilder.
func newImpl(ctx context.Context, cli client.CommonAPIClient, dockerHost string, opts *pack.BuildOptions, logger logging.Logger) (impl Impl, err error) {
	opts.DockerHost = dockerHost

	daemonIsPodmanPreV330, err := podmanPreV330(ctx, cli)
	if err != nil {
		return
	}

	opts.TrustBuilder = func(_ string) bool {
		if daemonIsPodmanPreV330 {
			return false
		}
		for _, v := range trustedBuilderImagePrefixes {
			if strings.HasPrefix(opts.Builder, v) {
				return true
			}
		}
		return false
	}

	// Client with a logger which is enabled if in Verbose mode and a dockerClient that supports SSH docker daemon connection.
	return pack.NewClient(pack.WithLogger(logger), pack.WithDockerClient(cli))
}

// Builder Image chooses the correct builder image or defaults.
func BuilderImage(f fn.Function, builderName string) (string, error) {
	return builders.Image(f, builderName, DefaultBuilderImages)
}

// podmanPreV330 returns if the daemon is podman pre v330 or errors trying.
func podmanPreV330(ctx context.Context, cli client.CommonAPIClient) (b bool, err error) {
	version, err := cli.ServerVersion(ctx)
	if err != nil {
		return
	}

	for _, component := range version.Components {
		if component.Name == "Podman Engine" {
			v := semver.MustParse(version.Version)
			if v.Compare(v330) < 0 {
				return true, nil
			}
			break
		}
	}
	return
}

// Errors

type ErrRuntimeRequired struct{}

func (e ErrRuntimeRequired) Error() string {
	return "Pack requires the Function define a language runtime"
}

type ErrRuntimeNotSupported struct {
	Runtime string
}

func (e ErrRuntimeNotSupported) Error() string {
	return fmt.Sprintf("Pack builder has no default builder image for the '%v' language runtime.  Please provide one.", e.Runtime)
}
<|endoftext|>


<commit_before>package unleash

import (
	log "github.com/Sirupsen/logrus"
	"github.com/gin-gonic/gin"
	"os"
)

// Global read only variable to be used to access global configuration
var (
	UnleashVersion = "0.1.0"
	Config         *Specification
)

// Struct holding everything needed to serve Unleash application
type Unleash struct {
	Engine *gin.Engine
	Config *Specification
}

// Initializers to be executed before the application runs
func (unleash *Unleash) Initialize(config *Specification) error {

	// Set the log level to debug
	logLevel, err := log.ParseLevel(config.LogLevel)
	if err != nil {
		return err
	}
	log.SetLevel(logLevel)

	// Configure runtime based configuration default values
	if config.WorkingDirectory == "" {
		config.WorkingDirectory = os.TempDir()
	}

	// Print all configuration variables
	config.Describe()

	// Assign the incoming configuration
	unleash.Config = config

	// FIXME: Attribute the configuration globally for ease of use
	Config = config

	return nil
}

// Initialize the Unleash application based on the gin http framework
func New() *Unleash {

	// Will be used to hold everything needed to serve Unleash
	var unleash Unleash

	// Create a default gin stack
	unleash.Engine = gin.New()

	// Create an empty configuration to avoid panic
	unleash.Config = &Specification{}

	// Routes
	// Github push event
	githubEvents := unleash.Engine.Group("/events/github", GithubHmacAuthenticator())
	githubEvents.POST("/push", GithubPushHandler)

	// Bitbucket push event
	bitbucketEvents := unleash.Engine.Group("/events/bitbucket", BitbucketHmacAuthenticator())
	bitbucketEvents.POST("/push", BitbucketPushHandler)

	// Info routes
	info := unleash.Engine.Group("/info")
	info.GET("/ping", PingHandler)
	info.GET("/status", StatusHandler)
	info.GET("/version", VersionHandler)

	return &unleash
}
<commit_msg>Fix comments<commit_after>package unleash

import (
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/gin-gonic/gin"
)

// Global read only variable to be used to access global configuration
var (
	UnleashVersion = "0.1.0"
	Config         *Specification
)

// Unleash struct holding everything needed to serve Unleash application
type Unleash struct {
	Engine *gin.Engine
	Config *Specification
}

// Initialize to be executed before the application runs
func (unleash *Unleash) Initialize(config *Specification) error {

	// Set the log level to debug
	logLevel, err := log.ParseLevel(config.LogLevel)
	if err != nil {
		return err
	}
	log.SetLevel(logLevel)

	// Configure runtime based configuration default values
	if config.WorkingDirectory == "" {
		config.WorkingDirectory = os.TempDir()
	}

	// Print all configuration variables
	config.Describe()

	// Assign the incoming configuration
	unleash.Config = config

	// FIXME: Attribute the configuration globally for ease of use
	Config = config

	return nil
}

// New initialize the Unleash application based on the gin http framework
func New() *Unleash {

	// Will be used to hold everything needed to serve Unleash
	var unleash Unleash

	// Create a default gin stack
	unleash.Engine = gin.New()

	// Create an empty configuration to avoid panic
	unleash.Config = &Specification{}

	// Routes
	// Github push event
	githubEvents := unleash.Engine.Group("/events/github", GithubHmacAuthenticator())
	githubEvents.POST("/push", GithubPushHandler)

	// Bitbucket push event
	bitbucketEvents := unleash.Engine.Group("/events/bitbucket", BitbucketHmacAuthenticator())
	bitbucketEvents.POST("/push", BitbucketPushHandler)

	// Info routes
	info := unleash.Engine.Group("/info")
	info.GET("/ping", PingHandler)
	info.GET("/status", StatusHandler)
	info.GET("/version", VersionHandler)

	return &unleash
}
<|endoftext|>


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

package misc

import (
	"fmt"
	"strings"

	"github.com/coreos/mantle/kola/cluster"
	"github.com/coreos/mantle/kola/register"
	"github.com/coreos/mantle/platform"
)

func init() {
	register.Register(&register.Test{
		Run:         SUIDFiles,
		ClusterSize: 1,
		Name:        "coreos.filesystem.suid",
		UserData:    `#cloud-config`,
	})
	register.Register(&register.Test{
		Run:         SGIDFiles,
		ClusterSize: 1,
		Name:        "coreos.filesystem.sgid",
		UserData:    `#cloud-config`,
	})
	register.Register(&register.Test{
		Run:         WritableFiles,
		ClusterSize: 1,
		Name:        "coreos.filesystem.writablefiles",
		UserData:    `#cloud-config`,
	})
	register.Register(&register.Test{
		Run:         WritableDirs,
		ClusterSize: 1,
		Name:        "coreos.filesystem.writabledirs",
		UserData:    `#cloud-config`,
	})
}

func sugidFiles(m platform.Machine, validfiles []string, mode string) error {
	badfiles := make([]string, 0, 0)

	command := fmt.Sprintf("sudo find / -path /sys -prune -o -path /proc -prune -o -path /var/lib/rkt -prune -o -type f -perm -%v -print", mode)

	output, err := m.SSH(command)
	if err != nil {
		return fmt.Errorf("Failed to run find: output %s, status: %v", output, err)
	}

	if string(output) == "" {
		return nil
	}

	files := strings.Split(string(output), "\n")
	for _, file := range files {
		var valid bool

		for _, validfile := range validfiles {
			if file == validfile {
				valid = true
			}
		}
		if valid != true {
			badfiles = append(badfiles, file)
		}
	}

	if len(badfiles) != 0 {
		return fmt.Errorf("Unknown SUID or SGID files found: %v", badfiles)
	}

	return nil
}

func SUIDFiles(c cluster.TestCluster) error {
	m := c.Machines()[0]

	validfiles := []string{
		"/usr/bin/chage",
		"/usr/bin/chfn",
		"/usr/bin/chsh",
		"/usr/bin/expiry",
		"/usr/bin/gpasswd",
		"/usr/bin/ksu",
		"/usr/bin/man",
		"/usr/bin/mandb",
		"/usr/bin/mount",
		"/usr/bin/newgrp",
		"/usr/bin/passwd",
		"/usr/bin/pkexec",
		"/usr/bin/umount",
		"/usr/bin/su",
		"/usr/bin/sudo",
		"/usr/lib64/polkit-1/polkit-agent-helper-1",
		"/usr/libexec/dbus-daemon-launch-helper",
		"/usr/sbin/mount.nfs",
		"/usr/sbin/unix_chkpwd",
	}

	return sugidFiles(m, validfiles, "4000")
}

func SGIDFiles(c cluster.TestCluster) error {
	m := c.Machines()[0]

	validfiles := []string{}

	return sugidFiles(m, validfiles, "2000")
}

func WritableFiles(c cluster.TestCluster) error {
	m := c.Machines()[0]

	output, err := m.SSH("sudo find / -regextype posix-extended -regex \"/(sys|proc)\" -prune -o -type f -perm -0002 -print")
	if err != nil {
		return fmt.Errorf("Failed to run find: output %s, status: %v", output, err)
	}

	if string(output) != "" {
		return fmt.Errorf("Unknown writable files found: %v", output)
	}

	return nil
}

func WritableDirs(c cluster.TestCluster) error {
	m := c.Machines()[0]

	output, err := m.SSH("sudo find / -regextype posix-extended -regex \"/(sys|proc)\" -prune -o -type d -perm -0002 -a ! -perm -1000 -print")
	if err != nil {
		return fmt.Errorf("Failed to run find: output %s, status: %v", output, err)
	}

	if string(output) != "" {
		return fmt.Errorf("Unknown writable directories found: %v", output)
	}

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

package misc

import (
	"fmt"
	"strings"

	"github.com/coreos/mantle/kola/cluster"
	"github.com/coreos/mantle/kola/register"
	"github.com/coreos/mantle/platform"
)

func init() {
	register.Register(&register.Test{
		Run:         SUIDFiles,
		ClusterSize: 1,
		Name:        "coreos.filesystem.suid",
		UserData:    `#cloud-config`,
	})
	register.Register(&register.Test{
		Run:         SGIDFiles,
		ClusterSize: 1,
		Name:        "coreos.filesystem.sgid",
		UserData:    `#cloud-config`,
	})
	register.Register(&register.Test{
		Run:         WritableFiles,
		ClusterSize: 1,
		Name:        "coreos.filesystem.writablefiles",
		UserData:    `#cloud-config`,
	})
	register.Register(&register.Test{
		Run:         WritableDirs,
		ClusterSize: 1,
		Name:        "coreos.filesystem.writabledirs",
		UserData:    `#cloud-config`,
	})
}

func sugidFiles(m platform.Machine, validfiles []string, mode string) error {
	badfiles := make([]string, 0, 0)

	command := fmt.Sprintf("sudo find / -path /sys -prune -o -path /proc -prune -o -path /var/lib/rkt -prune -o -type f -perm -%v -print", mode)

	output, err := m.SSH(command)
	if err != nil {
		return fmt.Errorf("Failed to run find: output %s, status: %v", output, err)
	}

	if string(output) == "" {
		return nil
	}

	files := strings.Split(string(output), "\n")
	for _, file := range files {
		var valid bool

		for _, validfile := range validfiles {
			if file == validfile {
				valid = true
			}
		}
		if valid != true {
			badfiles = append(badfiles, file)
		}
	}

	if len(badfiles) != 0 {
		return fmt.Errorf("Unknown SUID or SGID files found: %v", badfiles)
	}

	return nil
}

func SUIDFiles(c cluster.TestCluster) error {
	m := c.Machines()[0]

	validfiles := []string{
		"/usr/bin/chage",
		"/usr/bin/chfn",
		"/usr/bin/chsh",
		"/usr/bin/expiry",
		"/usr/bin/gpasswd",
		"/usr/bin/ksu",
		"/usr/bin/man",
		"/usr/bin/mandb",
		"/usr/bin/mount",
		"/usr/bin/newgrp",
		"/usr/bin/passwd",
		"/usr/bin/pkexec",
		"/usr/bin/umount",
		"/usr/bin/su",
		"/usr/bin/sudo",
		"/usr/lib64/polkit-1/polkit-agent-helper-1",
		"/usr/libexec/dbus-daemon-launch-helper",
		"/usr/sbin/mount.nfs",
		"/usr/sbin/unix_chkpwd",
	}

	return sugidFiles(m, validfiles, "4000")
}

func SGIDFiles(c cluster.TestCluster) error {
	m := c.Machines()[0]

	validfiles := []string{}

	return sugidFiles(m, validfiles, "2000")
}

func WritableFiles(c cluster.TestCluster) error {
	m := c.Machines()[0]

	output, err := m.SSH("sudo find / -path /sys -prune -o -path /proc -prune -o -path /var/lib/rkt -prune -o -type f -perm -0002 -print")
	if err != nil {
		return fmt.Errorf("Failed to run find: output %s, status: %v", output, err)
	}

	if string(output) != "" {
		return fmt.Errorf("Unknown writable files found: %v", output)
	}

	return nil
}

func WritableDirs(c cluster.TestCluster) error {
	m := c.Machines()[0]

	output, err := m.SSH("sudo find / -path /sys -prune -o -path /proc -prune -o -path /var/lib/rkt -prune -o -type d -perm -0002 -a ! -perm -1000 -print")
	if err != nil {
		return fmt.Errorf("Failed to run find: output %s, status: %v", output, err)
	}

	if string(output) != "" {
		return fmt.Errorf("Unknown writable directories found: %v", output)
	}

	return nil
}
<|endoftext|>


<commit_before>package url

import (
	"math/rand"
	"net/url"
	"time"
)

//region TYPES

type Url struct {
	Id 				string
	CreationDate 	time.Time
	Destination		string
}

type Repository interface {
	IdExists(id string) bool
	FindById(id string) *Url
	FindByUrl(url string) *Url
	Save(url Url) error
}

//endregion TYPES

//region CONST AND VARS

const (
	size    = 5
	symbols = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-+"
)

var repo Repository

//endregion CONST AND VARS

//region MAIN FUNCTIONS

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

//endregion MAIN FUNCTIONS

//region PUBLIC FUNCIONS

func ConfigRepository(r Repository) {
	repo = r
}

func Find(id string) *Url {
	return repo.FindById(id)
}

func GetUrl(destiny string) (u *Url, new bool, err error) {
	if u = repo.FindByUrl(destiny); u != nil {
		return u, false, nil
	}

	if _, err = url.ParseRequestURI(destiny); err != nil {
		return nil, false, err
	}

	url := Url{generateId(), time.Now(), destiny}
	repo.Save(url)

	return &url, true, nil
}

//endregion PUBLIC FUNCIONS

//region PRIVATE FUNCIONS

func generateId() {
	newId := func() string {
		id := make([]byte, size)

		for i := range id {
			id[i] = symbols[rand.Intn(len(symbols))]
		}

		return string(id)
	}

	for {
		if id := newId(); !repo.IdExists(id) {
			return id
		}
	}
}

//endregion PRIVATE FUNCIONS<commit_msg>More implementations.<commit_after>package url

import (
	"math/rand"
	"net/url"
	"time"
)

//region TYPES

type Url struct {
	Id              string
	CreationDate    time.Time
	Destination     string
}

type Repository interface {
	IdExists(id string) bool
	FindById(id string) *Url
	FindByUrl(url string) *Url
	Save(url Url) error
}

//endregion TYPES

//region CONST AND VARS

const (
	size    = 5
	symbols = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-+"
)

var repo Repository

//endregion CONST AND VARS

//region MAIN FUNCTIONS

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

//endregion MAIN FUNCTIONS

//region PUBLIC FUNCIONS

func ConfigRepository(r Repository) {
	repo = r
}

func Find(id string) *Url {
	return repo.FindById(id)
}

func GetUrl(destiny string) (u *Url, new bool, err error) {
	if u = repo.FindByUrl(destiny); u != nil {
		return u, false, nil
	}

	if _, err = url.ParseRequestURI(destiny); err != nil {
		return nil, false, err
	}

	url := Url{generateId(), time.Now(), destiny}
	repo.Save(url)

	return &url, true, nil
}

//endregion PUBLIC FUNCIONS

//region PRIVATE FUNCIONS

func generateId() {
	newId := func() string {
		id := make([]byte, size)

		for i := range id {
			id[i] = symbols[rand.Intn(len(symbols))]
		}

		return string(id)
	}

	for {
		if id := newId(); !repo.IdExists(id) {
			return id
		}
	}
}

//endregion PRIVATE FUNCIONS
<|endoftext|>