<commit_before>// Copyright (c) 2020 Shivaram Lingamneni <slingamn@cs.stanford.edu>
// released under the MIT license

package irc

import (
	"time"

	"github.com/goshuirc/irc-go/ircmsg"

	"github.com/oragono/oragono/irc/caps"
	"github.com/oragono/oragono/irc/utils"
)

// MessageCache caches serialized IRC messages.
// First call Initialize or InitializeSplitMessage, which records
// the parameters and builds the cache. Then call Send, which will
// either send a cached version of the message or dispatch to another
// send routine that can synthesize the necessary version on the fly.
type MessageCache struct {
	// these cache a single-line message (e.g., JOIN, or PRIVMSG with a 512-byte message)
	// one version is "plain" (legacy clients with no tags) and one is "full" (client has
	// the message-tags cap)
	plain    []byte
	fullTags []byte
	// these cache a multiline message (a PRIVMSG that was sent as a multiline batch)
	// one version is "plain" (legacy clients with no tags) and one is "full" (client has
	// the multiline cap)
	plainMultiline    [][]byte
	fullTagsMultiline [][]byte

	time        time.Time
	msgid       string
	accountName string
	tags        map[string]string
	source      string
	command     string

	params []string

	target       string
	splitMessage utils.SplitMessage
}

func addAllTags(msg *ircmsg.IrcMessage, tags map[string]string, serverTime time.Time, msgid, accountName string) {
	msg.UpdateTags(tags)
	msg.SetTag("time", serverTime.Format(IRCv3TimestampFormat))
	if accountName != "*" {
		msg.SetTag("account", accountName)
	}
	if msgid != "" {
		msg.SetTag("msgid", msgid)
	}
}

func (m *MessageCache) handleErr(server *Server, err error) bool {
	if err != nil {
		server.logger.Error("internal", "Error assembling message for sending", err.Error())
		// blank these out so Send will be a no-op
		m.fullTags = nil
		m.fullTagsMultiline = nil
		return true
	}
	return false
}

func (m *MessageCache) Initialize(server *Server, serverTime time.Time, msgid string, nickmask, accountName string, tags map[string]string, command string, params ...string) (err error) {
	m.time = serverTime
	m.msgid = msgid
	m.source = nickmask
	m.accountName = accountName
	m.tags = tags
	m.command = command
	m.params = params

	var msg ircmsg.IrcMessage
	config := server.Config()
	if config.Server.Compatibility.forceTrailing && commandsThatMustUseTrailing[command] {
		msg.ForceTrailing()
	}
	msg.Prefix = nickmask
	msg.Command = command
	msg.Params = make([]string, len(params))
	copy(msg.Params, params)
	m.plain, err = msg.LineBytesStrict(false, MaxLineLen)
	if m.handleErr(server, err) {
		return
	}

	addAllTags(&msg, tags, serverTime, msgid, accountName)
	m.fullTags, err = msg.LineBytesStrict(false, MaxLineLen)
	if m.handleErr(server, err) {
		return
	}
	return
}

func (m *MessageCache) InitializeSplitMessage(server *Server, nickmask, accountName string, tags map[string]string, command, target string, message utils.SplitMessage) (err error) {
	m.time = message.Time
	m.msgid = message.Msgid
	m.source = nickmask
	m.accountName = accountName
	m.tags = tags
	m.command = command
	m.target = target
	m.splitMessage = message

	config := server.Config()
	forceTrailing := config.Server.Compatibility.forceTrailing && commandsThatMustUseTrailing[command]

	if message.Is512() {
		isTagmsg := command == "TAGMSG"
		var msg ircmsg.IrcMessage
		if forceTrailing {
			msg.ForceTrailing()
		}

		msg.Prefix = nickmask
		msg.Command = command
		if isTagmsg {
			msg.Params = []string{target}
		} else {
			msg.Params = []string{target, message.Message}
		}
		m.params = msg.Params
		if !isTagmsg {
			m.plain, err = msg.LineBytesStrict(false, MaxLineLen)
			if m.handleErr(server, err) {
				return
			}
		}

		addAllTags(&msg, tags, message.Time, message.Msgid, accountName)
		m.fullTags, err = msg.LineBytesStrict(false, MaxLineLen)
		if m.handleErr(server, err) {
			return
		}
	} else {
		var msg ircmsg.IrcMessage
		if forceTrailing {
			msg.ForceTrailing()
		}
		msg.Prefix = nickmask
		msg.Command = command
		msg.Params = make([]string, 2)
		msg.Params[0] = target
		m.plainMultiline = make([][]byte, len(message.Split))
		for i, pair := range message.Split {
			msg.Params[1] = pair.Message
			m.plainMultiline[i], err = msg.LineBytesStrict(false, MaxLineLen)
			if m.handleErr(server, err) {
				return
			}
		}

		// we need to send the same batch ID to all recipient sessions;
		// use a uuidv4-alike to ensure that it won't collide
		batch := composeMultilineBatch(utils.GenerateSecretToken(), nickmask, accountName, tags, command, target, message)
		m.fullTagsMultiline = make([][]byte, len(batch))
		for i, msg := range batch {
			if forceTrailing {
				msg.ForceTrailing()
			}
			m.fullTagsMultiline[i], err = msg.LineBytesStrict(false, MaxLineLen)
			if m.handleErr(server, err) {
				return
			}
		}
	}
	return
}

func (m *MessageCache) Send(session *Session) {
	if m.fullTags != nil {
		// Initialize() path:
		if session.capabilities.Has(caps.MessageTags) {
			session.sendBytes(m.fullTags, false)
		} else if m.plain != nil {
			// plain == nil indicates a TAGMSG
			if !(session.capabilities.Has(caps.ServerTime) || session.capabilities.Has(caps.AccountTag)) {
				session.sendBytes(m.plain, false)
			} else {
				// slowpath
				session.sendFromClientInternal(false, m.time, m.msgid, m.source, m.accountName, nil, m.command, m.params...)
			}
		}
	} else if m.fullTagsMultiline != nil {
		// InitializeSplitMessage() path:
		if session.capabilities.Has(caps.Multiline) {
			for _, line := range m.fullTagsMultiline {
				session.sendBytes(line, false)
			}
		} else if !(session.capabilities.Has(caps.ServerTime) || session.capabilities.Has(caps.AccountTag)) {
			for _, line := range m.plainMultiline {
				session.sendBytes(line, false)
			}
		} else {
			// slowpath
			session.sendSplitMsgFromClientInternal(false, m.source, m.accountName, m.tags, m.command, m.target, m.splitMessage)
		}
	}
}
<commit_msg>shorten the cached batch ID for multilines<commit_after>// Copyright (c) 2020 Shivaram Lingamneni <slingamn@cs.stanford.edu>
// released under the MIT license

package irc

import (
	"time"

	"github.com/goshuirc/irc-go/ircmsg"

	"github.com/oragono/oragono/irc/caps"
	"github.com/oragono/oragono/irc/utils"
)

// MessageCache caches serialized IRC messages.
// First call Initialize or InitializeSplitMessage, which records
// the parameters and builds the cache. Then call Send, which will
// either send a cached version of the message or dispatch to another
// send routine that can synthesize the necessary version on the fly.
type MessageCache struct {
	// these cache a single-line message (e.g., JOIN, or PRIVMSG with a 512-byte message)
	// one version is "plain" (legacy clients with no tags) and one is "full" (client has
	// the message-tags cap)
	plain    []byte
	fullTags []byte
	// these cache a multiline message (a PRIVMSG that was sent as a multiline batch)
	// one version is "plain" (legacy clients with no tags) and one is "full" (client has
	// the multiline cap)
	plainMultiline    [][]byte
	fullTagsMultiline [][]byte

	time        time.Time
	msgid       string
	accountName string
	tags        map[string]string
	source      string
	command     string

	params []string

	target       string
	splitMessage utils.SplitMessage
}

func addAllTags(msg *ircmsg.IrcMessage, tags map[string]string, serverTime time.Time, msgid, accountName string) {
	msg.UpdateTags(tags)
	msg.SetTag("time", serverTime.Format(IRCv3TimestampFormat))
	if accountName != "*" {
		msg.SetTag("account", accountName)
	}
	if msgid != "" {
		msg.SetTag("msgid", msgid)
	}
}

func (m *MessageCache) handleErr(server *Server, err error) bool {
	if err != nil {
		server.logger.Error("internal", "Error assembling message for sending", err.Error())
		// blank these out so Send will be a no-op
		m.fullTags = nil
		m.fullTagsMultiline = nil
		return true
	}
	return false
}

func (m *MessageCache) Initialize(server *Server, serverTime time.Time, msgid string, nickmask, accountName string, tags map[string]string, command string, params ...string) (err error) {
	m.time = serverTime
	m.msgid = msgid
	m.source = nickmask
	m.accountName = accountName
	m.tags = tags
	m.command = command
	m.params = params

	var msg ircmsg.IrcMessage
	config := server.Config()
	if config.Server.Compatibility.forceTrailing && commandsThatMustUseTrailing[command] {
		msg.ForceTrailing()
	}
	msg.Prefix = nickmask
	msg.Command = command
	msg.Params = make([]string, len(params))
	copy(msg.Params, params)
	m.plain, err = msg.LineBytesStrict(false, MaxLineLen)
	if m.handleErr(server, err) {
		return
	}

	addAllTags(&msg, tags, serverTime, msgid, accountName)
	m.fullTags, err = msg.LineBytesStrict(false, MaxLineLen)
	if m.handleErr(server, err) {
		return
	}
	return
}

func (m *MessageCache) InitializeSplitMessage(server *Server, nickmask, accountName string, tags map[string]string, command, target string, message utils.SplitMessage) (err error) {
	m.time = message.Time
	m.msgid = message.Msgid
	m.source = nickmask
	m.accountName = accountName
	m.tags = tags
	m.command = command
	m.target = target
	m.splitMessage = message

	config := server.Config()
	forceTrailing := config.Server.Compatibility.forceTrailing && commandsThatMustUseTrailing[command]

	if message.Is512() {
		isTagmsg := command == "TAGMSG"
		var msg ircmsg.IrcMessage
		if forceTrailing {
			msg.ForceTrailing()
		}

		msg.Prefix = nickmask
		msg.Command = command
		if isTagmsg {
			msg.Params = []string{target}
		} else {
			msg.Params = []string{target, message.Message}
		}
		m.params = msg.Params
		if !isTagmsg {
			m.plain, err = msg.LineBytesStrict(false, MaxLineLen)
			if m.handleErr(server, err) {
				return
			}
		}

		addAllTags(&msg, tags, message.Time, message.Msgid, accountName)
		m.fullTags, err = msg.LineBytesStrict(false, MaxLineLen)
		if m.handleErr(server, err) {
			return
		}
	} else {
		var msg ircmsg.IrcMessage
		if forceTrailing {
			msg.ForceTrailing()
		}
		msg.Prefix = nickmask
		msg.Command = command
		msg.Params = make([]string, 2)
		msg.Params[0] = target
		m.plainMultiline = make([][]byte, len(message.Split))
		for i, pair := range message.Split {
			msg.Params[1] = pair.Message
			m.plainMultiline[i], err = msg.LineBytesStrict(false, MaxLineLen)
			if m.handleErr(server, err) {
				return
			}
		}

		// we need to send the same batch ID to all recipient sessions;
		// ensure it doesn't collide. a half-sized token has 64 bits of entropy,
		// so a collision isn't expected until there are on the order of 2**32
		// concurrent batches being relayed:
		batchID := utils.GenerateSecretToken()[:utils.SecretTokenLength/2]
		batch := composeMultilineBatch(batchID, nickmask, accountName, tags, command, target, message)
		m.fullTagsMultiline = make([][]byte, len(batch))
		for i, msg := range batch {
			if forceTrailing {
				msg.ForceTrailing()
			}
			m.fullTagsMultiline[i], err = msg.LineBytesStrict(false, MaxLineLen)
			if m.handleErr(server, err) {
				return
			}
		}
	}
	return
}

func (m *MessageCache) Send(session *Session) {
	if m.fullTags != nil {
		// Initialize() path:
		if session.capabilities.Has(caps.MessageTags) {
			session.sendBytes(m.fullTags, false)
		} else if m.plain != nil {
			// plain == nil indicates a TAGMSG
			if !(session.capabilities.Has(caps.ServerTime) || session.capabilities.Has(caps.AccountTag)) {
				session.sendBytes(m.plain, false)
			} else {
				// slowpath
				session.sendFromClientInternal(false, m.time, m.msgid, m.source, m.accountName, nil, m.command, m.params...)
			}
		}
	} else if m.fullTagsMultiline != nil {
		// InitializeSplitMessage() path:
		if session.capabilities.Has(caps.Multiline) {
			for _, line := range m.fullTagsMultiline {
				session.sendBytes(line, false)
			}
		} else if !(session.capabilities.Has(caps.ServerTime) || session.capabilities.Has(caps.AccountTag)) {
			for _, line := range m.plainMultiline {
				session.sendBytes(line, false)
			}
		} else {
			// slowpath
			session.sendSplitMsgFromClientInternal(false, m.source, m.accountName, m.tags, m.command, m.target, m.splitMessage)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	_ "github.com/looplab/logspout-logstash"
	_ "github.com/gliderlabs/logspout/transports/udp"
)
<commit_msg>Add httpstream module for monitor logspout queu.<commit_after>package main

import (
	_ "github.com/looplab/logspout-logstash"
	_ "github.com/gliderlabs/logspout/transports/udp"
	_ "github.com/gliderlabs/logspout/httpstream"
)
<|endoftext|>


<commit_before>package mom

import (
	wutil "github.com/ethanfrey/tenderize/wire"
	"github.com/tendermint/go-merkle"
)

// Key is designed to let you easily build compound indexes using the one database key
type Key interface {
	// Range assumes the key has one or more elements at the zero (nil) value
	// It should return two keys, the first is with those zero elements set the the minimum possible value
	// The second return value should be with the zero elements set to their maximum possible value
	Range() (min Key, max Key)
}

// mkey is designed to bridge Keys for go-wire
type mkey struct {
	Key
}

// Query can define a detailed range query based on a key
type Query struct {
	Key     Key
	Reverse bool
	Filter  func(Model) bool
}

// KeyToBytes returns the Key as a byte array for use in go-merkle
// Returns an error if some required fields are not set
func KeyToBytes(key Key) ([]byte, error) {
	return wutil.ToBinary(mkey{key})
}

// Load attempts to find the data matching the given key
// If the key or store data cannot be parsed, returns error
// If there is no data, Model is nil
func Load(store merkle.Tree, key Key) (Model, error) {
	k, err := KeyToBytes(key)
	if err != nil {
		return nil, err
	}

	_, data, exists := store.Get(k)
	if !exists || data == nil {
		return nil, nil
	}

	return ModelFromBytes(data)
}

// ByteRange attempts to take the range and serialize it, returns error if either fails
func ByteRange(key Key) (start []byte, end []byte, err error) {
	s, e := key.Range()
	start, err = KeyToBytes(s)
	if err != nil {
		return
	}
	end, err = KeyToBytes(e)
	return
}

// List returns all items that match this query
func List(store merkle.Tree, q Query) ([]Model, error) {
	return filter(store, q.Key, !q.Reverse, q.Filter)
}

// filter returns a list of all items that fit in the range of the key, optionally applying a filter
// if filter is nil, then return all items in that range
func filter(store merkle.Tree, key Key, ascending bool, filter func(Model) bool) ([]Model, error) {
	res := []Model{}
	start, end, err := ByteRange(key)
	if err != nil {
		return nil, err
	}

	store.IterateRange(start, end, ascending, func(k []byte, v []byte) bool {
		item, err := ModelFromBytes(v)
		if err == nil && (filter == nil || filter(item)) {
			res = append(res, item)
		}
		return false
	})
	return res, nil
}
<commit_msg>Add helper to deserialize key from bytes<commit_after>package mom

import (
	wutil "github.com/ethanfrey/tenderize/wire"
	"github.com/tendermint/go-merkle"
)

// Key is designed to let you easily build compound indexes using the one database key
type Key interface {
	// Range assumes the key has one or more elements at the zero (nil) value
	// It should return two keys, the first is with those zero elements set the the minimum possible value
	// The second return value should be with the zero elements set to their maximum possible value
	Range() (min Key, max Key)
}

// mkey is designed to bridge Keys for go-wire
type mkey struct {
	Key
}

// Query can define a detailed range query based on a key
type Query struct {
	Key     Key
	Reverse bool
	Filter  func(Model) bool
}

// KeyToBytes returns the Key as a byte array for use in go-merkle
// Returns an error if some required fields are not set
func KeyToBytes(key Key) ([]byte, error) {
	return wutil.ToBinary(mkey{key})
}

// KeyFromBytes recovers a Key object from arbitrary byte data (eg. from API)
func KeyFromBytes(data []byte) (Key, error) {
	// Is there an easier way
	holder := mkey{}
	err := wutil.FromBinary(data, &holder)
	return holder.Key, err
}

// Load attempts to find the data matching the given key
// If the key or store data cannot be parsed, returns error
// If there is no data, Model is nil
func Load(store merkle.Tree, key Key) (Model, error) {
	k, err := KeyToBytes(key)
	if err != nil {
		return nil, err
	}

	_, data, exists := store.Get(k)
	if !exists || data == nil {
		return nil, nil
	}

	return ModelFromBytes(data)
}

// ByteRange attempts to take the range and serialize it, returns error if either fails
func ByteRange(key Key) (start []byte, end []byte, err error) {
	s, e := key.Range()
	start, err = KeyToBytes(s)
	if err != nil {
		return
	}
	end, err = KeyToBytes(e)
	return
}

// List returns all items that match this query
func List(store merkle.Tree, q Query) ([]Model, error) {
	return filter(store, q.Key, !q.Reverse, q.Filter)
}

// filter returns a list of all items that fit in the range of the key, optionally applying a filter
// if filter is nil, then return all items in that range
func filter(store merkle.Tree, key Key, ascending bool, filter func(Model) bool) ([]Model, error) {
	res := []Model{}
	start, end, err := ByteRange(key)
	if err != nil {
		return nil, err
	}

	store.IterateRange(start, end, ascending, func(k []byte, v []byte) bool {
		item, err := ModelFromBytes(v)
		if err == nil && (filter == nil || filter(item)) {
			res = append(res, item)
		}
		return false
	})
	return res, nil
}
<|endoftext|>


<commit_before>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

   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 com

import (
	"errors"
	"log"
	"os"
	"path/filepath"
	"sync"

	"github.com/admpub/fsnotify"
)

var (
	DefaultMonitor      = NewMonitor()
	MonitorEventEmptyFn = func(string) {}
)

func NewMonitor() *MonitorEvent {
	return &MonitorEvent{
		Create:  MonitorEventEmptyFn,
		Delete:  MonitorEventEmptyFn,
		Modify:  MonitorEventEmptyFn,
		Chmod:   MonitorEventEmptyFn,
		Rename:  MonitorEventEmptyFn,
		filters: []func(string) bool{},
	}
}

//MonitorEvent 监控事件函数
type MonitorEvent struct {
	//文件事件
	Create func(string) //创建
	Delete func(string) //删除（包含文件夹和文件。因为已经删除，无法确定是文件夹还是文件）
	Modify func(string) //修改（包含修改权限。如果是文件夹，则内部的文件被更改也会触发此事件）
	Chmod  func(string) //修改权限（windows不支持）
	Rename func(string) //重命名

	//其它
	Channel chan bool //管道
	Debug   bool
	lock    *sync.Once
	watcher *fsnotify.Watcher
	filters []func(string) bool
}

func (m *MonitorEvent) AddFilter(args ...func(string) bool) *MonitorEvent {
	if m.filters == nil {
		m.filters = []func(string) bool{}
	}
	m.filters = append(m.filters, args...)
	return m
}

func (m *MonitorEvent) SetFilters(args ...func(string) bool) *MonitorEvent {
	m.filters = args
	return m
}

func (m *MonitorEvent) Watch(args ...func(string) bool) *MonitorEvent {
	m.SetFilters(args...)
	go func() {
		m.backendListen()
		<-m.Channel
	}()
	return m
}

func (m *MonitorEvent) Close() error {
	if m.Channel != nil {
		close(m.Channel)
	}
	if m.watcher != nil {
		return m.watcher.Close()
	}
	return nil
}

func (m *MonitorEvent) Watcher() *fsnotify.Watcher {
	if m.watcher == nil {
		var err error
		m.watcher, err = fsnotify.NewWatcher()
		m.lock = &sync.Once{}
		m.Channel = make(chan bool)
		m.filters = []func(string) bool{}
		if err != nil {
			log.Panic(err)
		}
	}
	return m.watcher
}

func (m *MonitorEvent) backendListen() *MonitorEvent {
	go m.listen()
	return m
}

func (m *MonitorEvent) AddDir(dir string) error {
	f, err := os.Stat(dir)
	if err != nil {
		return err
	}
	if !f.IsDir() {
		return errors.New(dir + ` is not dir.`)
	}
	err = filepath.Walk(dir, func(f string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			if m.Debug {
				log.Println(`[Monitor]`, `Add Watch:`, f)
			}
			return m.Watcher().Add(f)
		}
		return nil
	})
	return err
}

func (m *MonitorEvent) AddFile(file string) error {
	return m.Watcher().Add(file)
}

func (m *MonitorEvent) Remove(fileOrDir string) error {
	if m.watcher != nil {
		return m.watcher.Remove(fileOrDir)
	}
	return nil
}

func (m *MonitorEvent) listen() {
	for {
		watcher := m.Watcher()
		select {
		case ev := <-watcher.Events:
			if m.Debug {
				log.Println(`[Monitor]`, `Trigger Event:`, ev)
			}
			if m.filters != nil {
				var skip bool
				for _, filter := range m.filters {
					if !filter(ev.Name) {
						skip = true
						break
					}
				}
				if skip {
					break
				}
			}
			m.lock.Do(func() {
				switch ev.Op {
				case fsnotify.Create:
					if m.IsDir(ev.Name) {
						watcher.Add(ev.Name)
					}
					if m.Create != nil {
						m.Create(ev.Name)
					}
				case fsnotify.Remove:
					if m.Delete != nil {
						m.Delete(ev.Name)
					}
				case fsnotify.Write:
					if m.Modify != nil {
						m.Modify(ev.Name)
					}
				case fsnotify.Rename:
					if m.Rename != nil {
						m.Rename(ev.Name)
					}
				case fsnotify.Chmod:
					if m.Chmod != nil {
						m.Chmod(ev.Name)
					}
				}
				m.lock = &sync.Once{}
			})
		case err := <-watcher.Errors:
			if err != nil {
				log.Println("Watcher error:", err)
			}
		}
	}
}

func (m *MonitorEvent) IsDir(path string) bool {
	d, e := os.Stat(path)
	if e != nil {
		return false
	}
	return d.IsDir()
}

//Monitor 文件监测
func Monitor(rootDir string, callback *MonitorEvent, args ...func(string) bool) error {
	watcher := callback.Watcher()
	defer watcher.Close()
	callback.Watch(args...)
	err := callback.AddDir(rootDir)
	if err != nil {
		callback.Close()
		return err
	}
	return nil
}
<commit_msg>update<commit_after>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

   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 com

import (
	"errors"
	"log"
	"os"
	"path/filepath"

	"github.com/admpub/fsnotify"
)

var (
	DefaultMonitor      = NewMonitor()
	MonitorEventEmptyFn = func(string) {}
)

func NewMonitor() *MonitorEvent {
	return &MonitorEvent{
		Create:  MonitorEventEmptyFn,
		Delete:  MonitorEventEmptyFn,
		Modify:  MonitorEventEmptyFn,
		Chmod:   MonitorEventEmptyFn,
		Rename:  MonitorEventEmptyFn,
		filters: []func(string) bool{},
	}
}

//MonitorEvent 监控事件函数
type MonitorEvent struct {
	//文件事件
	Create func(string) //创建
	Delete func(string) //删除（包含文件夹和文件。因为已经删除，无法确定是文件夹还是文件）
	Modify func(string) //修改（包含修改权限。如果是文件夹，则内部的文件被更改也会触发此事件）
	Chmod  func(string) //修改权限（windows不支持）
	Rename func(string) //重命名

	//其它
	Channel chan bool //管道
	Debug   bool
	watcher *fsnotify.Watcher
	filters []func(string) bool
}

func (m *MonitorEvent) AddFilter(args ...func(string) bool) *MonitorEvent {
	if m.filters == nil {
		m.filters = []func(string) bool{}
	}
	m.filters = append(m.filters, args...)
	return m
}

func (m *MonitorEvent) SetFilters(args ...func(string) bool) *MonitorEvent {
	m.filters = args
	return m
}

func (m *MonitorEvent) Watch(args ...func(string) bool) *MonitorEvent {
	m.SetFilters(args...)
	go func() {
		m.backendListen()
		<-m.Channel
	}()
	return m
}

func (m *MonitorEvent) Close() error {
	if m.Channel != nil {
		close(m.Channel)
	}
	if m.watcher != nil {
		return m.watcher.Close()
	}
	return nil
}

func (m *MonitorEvent) Watcher() *fsnotify.Watcher {
	if m.watcher == nil {
		var err error
		m.watcher, err = fsnotify.NewWatcher()
		m.Channel = make(chan bool)
		m.filters = []func(string) bool{}
		if err != nil {
			log.Panic(err)
		}
	}
	return m.watcher
}

func (m *MonitorEvent) backendListen() *MonitorEvent {
	go m.listen()
	return m
}

func (m *MonitorEvent) AddDir(dir string) error {
	f, err := os.Stat(dir)
	if err != nil {
		return err
	}
	if !f.IsDir() {
		return errors.New(dir + ` is not dir.`)
	}
	err = filepath.Walk(dir, func(f string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			if m.Debug {
				log.Println(`[Monitor]`, `Add Watch:`, f)
			}
			return m.Watcher().Add(f)
		}
		return nil
	})
	return err
}

func (m *MonitorEvent) AddFile(file string) error {
	return m.Watcher().Add(file)
}

func (m *MonitorEvent) Remove(fileOrDir string) error {
	if m.watcher != nil {
		return m.watcher.Remove(fileOrDir)
	}
	return nil
}

func (m *MonitorEvent) listen() {
	for {
		watcher := m.Watcher()
		select {
		case ev := <-watcher.Events:
			if m.Debug {
				log.Println(`[Monitor]`, `Trigger Event:`, ev)
			}
			if m.filters != nil {
				var skip bool
				for _, filter := range m.filters {
					if !filter(ev.Name) {
						skip = true
						break
					}
				}
				if skip {
					break
				}
			}
			switch ev.Op {
			case fsnotify.Create:
				if m.IsDir(ev.Name) {
					watcher.Add(ev.Name)
				}
				if m.Create != nil {
					m.Create(ev.Name)
				}
			case fsnotify.Remove:
				if m.Delete != nil {
					m.Delete(ev.Name)
				}
			case fsnotify.Write:
				if m.Modify != nil {
					m.Modify(ev.Name)
				}
			case fsnotify.Rename:
				if m.Rename != nil {
					m.Rename(ev.Name)
				}
			case fsnotify.Chmod:
				if m.Chmod != nil {
					m.Chmod(ev.Name)
				}
			}
		case err := <-watcher.Errors:
			if err != nil {
				log.Println("Watcher error:", err)
			}
		}
	}
}

func (m *MonitorEvent) IsDir(path string) bool {
	d, e := os.Stat(path)
	if e != nil {
		return false
	}
	return d.IsDir()
}

//Monitor 文件监测
func Monitor(rootDir string, callback *MonitorEvent, args ...func(string) bool) error {
	watcher := callback.Watcher()
	defer watcher.Close()
	callback.Watch(args...)
	err := callback.AddDir(rootDir)
	if err != nil {
		callback.Close()
		return err
	}
	return nil
}
<|endoftext|>


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

// Package beam provides a simple, powerful model for building both batch and
// streaming parallel data processing pipelines.
//
// TODO(herohde) 6/2/2017: add short overview of each important concept (multiple
// paragraphs), how they fit together, and an example of a working pipeline.
//
// Here is a typical example of use:
//
//    // Create an empty pipeline
//    p := beam.NewPipeline()
//
//    // A root PTransform, like textio.Read, gets added to the Pipeline by
//    // being applied:
//    lines := textio.Read(p, "protocol://path/file*.txt")
//
//    // A Pipeline can have multiple root transforms:
//    moreLines :=  textio.Read(p, "protocol://other/path/file*.txt")
//
//    // Further PTransforms can be applied, in an arbitrary (acyclic) graph.
//    // Subsequent PTransforms (and intermediate PCollections etc.) are
//    // implicitly part of the same Pipeline.
//    all := beam.Flatten(p, lines, moreLines)
//    words := beam.ParDo(p, func (line string, emit func(string))) {
//         for _, s := range strings.FieldsFunc(s, unicode.IsPunct) {
//             emit(strings.TrimSpace(s)))
//         }
//    }, all)
//    formatted := beam.ParDo(p, string.ToUpper, words)
//    textio.Write(p, "protocol://output/path", formatted)
//
//    // Primitive PTransforms aren't executed when they're applied, rather
//    // they're just added to the Pipeline.  Once the whole Pipeline of
//    // PTransforms is constructed, the Pipeline's PTransforms can be run
//    // using a PipelineRunner.  The local runner executes the Pipeline
//    // directly, sequentially, in this one process, which is useful for
//    // unit tests and simple experiments:
//    if err := local.Run(context.Background(), p); err != nil {
//        log.Fatalf("Pipeline failed: %v", err)
//    }
//
// See: https://beam.apache.org/documentation/programming-guide
package beam
<commit_msg>Adding more godoc for the main beam package.<commit_after>// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License.  You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package beam is an implementation of the Apache Beam (https://beam.apache.org)
// programming model in Go.  Beam provides a simple, powerful model for
// building both batch and streaming parallel data processing pipelines.
//
// In order to start creating the pipeline for execution, a Pipeline object is needed.
//
// 	 p := beam.NewPipeline()
//
// The pipeline object encapsulates all the data and steps in your processing task.
// It is the basis for creating the pipeline's data sets as PCollections and its operations
// as transforms.
//
// The PCollection abstraction represents a potentially distributed,
// multi-element data set. You can think of a PCollection as “pipeline” data;
// Beam transforms use PCollection objects as inputs and outputs. As such, if
// you want to work with data in your pipeline, it must be in the form of a
// PCollection.
//
//   // Start by reading text from an input files.
//   lines := textio.Read(p, "protocol://path/file*.txt")
//
// Transforms are added to the pipeline so they are part of the work to be
// executed.  Since this transform has no PCollection as an input, it is
// considered a 'root transform'
//
//    // A pipeline can have multiple root transforms
//    moreLines :=  textio.Read(p, "protocol://other/path/file*.txt")
//
// Further transforms can be applied, creating an arbitrary, acyclic graph.
// Subsequent transforms (and the intermediate PCollections they produce) are
// attached to the same pipeline.
//    all := beam.Flatten(p, lines, moreLines)
//    wordRegexp := regexp.MustCompile(`[a-zA-Z]+('[a-z])?`)
//    words := beam.ParDo(p, func (line string, emit func(string))) {
//         for _, word := range wordRegexp.FindAllString(line, -1) {
//             emit(word)
//         }
//    }, all)
//    formatted := beam.ParDo(p, string.ToUpper, words)
//    textio.Write(p, "protocol://output/path", formatted)
//
// Applying a transform adds it to the pipeline, rather than executing it
// immediately.  Once the whole pipeline of transforms is constructed, the
// pipeline can be executed by a PipelineRunner.  The local runner executes the
// transforms directly, sequentially, in this one process, which is useful for
// unit tests and simple experiments:
//    if err := local.Run(context.Background(), p); err != nil {
//        log.Fatalf("Pipeline failed: %v", err)
//    }
//
// See: https://beam.apache.org/documentation/programming-guide
package beam
<|endoftext|>


<commit_before>// Copyright 2016-2017 Authors of Cilium
//
// 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 k8s

import (
	"fmt"
	"net"

	"github.com/cilium/cilium/pkg/annotation"
	"github.com/cilium/cilium/pkg/cidr"
	"github.com/cilium/cilium/pkg/logging/logfields"
	"github.com/cilium/cilium/pkg/node"
	"github.com/cilium/cilium/pkg/node/addressing"
	"github.com/cilium/cilium/pkg/option"

	"github.com/sirupsen/logrus"
	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
)

// ParseNodeAddressType converts a Kubernetes NodeAddressType to a Cilium
// NodeAddressType. If the Kubernetes NodeAddressType does not have a
// corresponding Cilium AddressType, returns an error.
func ParseNodeAddressType(k8sAddress v1.NodeAddressType) (addressing.AddressType, error) {

	var err error
	convertedAddr := addressing.AddressType(k8sAddress)

	switch convertedAddr {
	case addressing.NodeExternalDNS, addressing.NodeExternalIP, addressing.NodeHostName, addressing.NodeInternalIP, addressing.NodeInternalDNS:
	default:
		err = fmt.Errorf("invalid Kubernetes NodeAddressType %s", convertedAddr)
	}
	return convertedAddr, err
}

// ParseNode parses a kubernetes node to a cilium node
func ParseNode(k8sNode *v1.Node, source node.Source) *node.Node {
	scopedLog := log.WithFields(logrus.Fields{
		logfields.NodeName:  k8sNode.Name,
		logfields.K8sNodeID: k8sNode.UID,
	})
	addrs := []node.Address{}
	for _, addr := range k8sNode.Status.Addresses {
		// We only care about this address types,
		// we ignore all other types.
		switch addr.Type {
		case v1.NodeInternalIP, v1.NodeExternalIP:
		default:
			continue
		}
		ip := net.ParseIP(addr.Address)
		if ip == nil {
			scopedLog.WithFields(logrus.Fields{
				logfields.IPAddr: addr.Address,
				"type":           addr.Type,
			}).Warn("Ignoring invalid node IP")
			continue
		}

		addressType, err := ParseNodeAddressType(addr.Type)

		if err != nil {
			scopedLog.WithError(err).Warn("invalid address type for node")
		}

		na := node.Address{
			Type: addressType,
			IP:   ip,
		}
		addrs = append(addrs, na)
	}

	k8sNodeAddHostIP := func(annotation string) {
		if ciliumInternalIP, ok := k8sNode.Annotations[annotation]; !ok {
			scopedLog.Debugf("Missing %s. Annotation required when IPSec Enabled", annotation)
		} else if ip := net.ParseIP(ciliumInternalIP); ip == nil {
			scopedLog.Debugf("ParseIP %s error", ciliumInternalIP)
		} else {
			na := node.Address{
				Type: addressing.NodeCiliumInternalIP,
				IP:   ip,
			}
			addrs = append(addrs, na)
			scopedLog.Debugf("Add NodeCiliumInternalIP: %s", ip)
		}
	}

	k8sNodeAddHostIP(annotation.CiliumHostIP)
	k8sNodeAddHostIP(annotation.CiliumHostIPv6)

	newNode := &node.Node{
		Name:        k8sNode.Name,
		Cluster:     option.Config.ClusterName,
		IPAddresses: addrs,
		Source:      source,
	}

	if len(k8sNode.Spec.PodCIDR) != 0 {
		if allocCIDR, err := cidr.ParseCIDR(k8sNode.Spec.PodCIDR); err != nil {
			scopedLog.WithError(err).WithField(logfields.V4Prefix, k8sNode.Spec.PodCIDR).Warn("Invalid PodCIDR value for node")
		} else {
			if allocCIDR.IP.To4() != nil {
				newNode.IPv4AllocCIDR = allocCIDR
			} else {
				newNode.IPv6AllocCIDR = allocCIDR
			}
		}
	}
	// Spec.PodCIDR takes precedence since it's
	// the CIDR assigned by k8s controller manager
	// In case it's invalid or empty then we fall back to our annotations.
	if newNode.IPv4AllocCIDR == nil {
		if ipv4CIDR, ok := k8sNode.Annotations[annotation.V4CIDRName]; !ok {
			scopedLog.Debug("Empty IPv4 CIDR annotation in node")
		} else {
			allocCIDR, err := cidr.ParseCIDR(ipv4CIDR)
			if err != nil {
				scopedLog.WithError(err).WithField(logfields.V4Prefix, ipv4CIDR).Error("BUG, invalid IPv4 annotation CIDR in node")
			} else {
				newNode.IPv4AllocCIDR = allocCIDR
			}
		}
	}

	if newNode.IPv6AllocCIDR == nil {
		if ipv6CIDR, ok := k8sNode.Annotations[annotation.V6CIDRName]; !ok {
			scopedLog.Debug("Empty IPv6 CIDR annotation in node")
		} else {
			allocCIDR, err := cidr.ParseCIDR(ipv6CIDR)
			if err != nil {
				scopedLog.WithError(err).WithField(logfields.V6Prefix, ipv6CIDR).Error("BUG, invalid IPv6 annotation CIDR in node")
			} else {
				newNode.IPv6AllocCIDR = allocCIDR
			}
		}
	}

	if newNode.IPv4HealthIP == nil {
		if healthIP, ok := k8sNode.Annotations[annotation.V4HealthName]; !ok {
			scopedLog.Debug("Empty IPv4 health endpoint annotation in node")
		} else if ip := net.ParseIP(healthIP); ip == nil {
			scopedLog.WithField(logfields.V4HealthIP, healthIP).Error("BUG, invalid IPv4 health endpoint annotation in node")
		} else {
			newNode.IPv4HealthIP = ip
		}
	}

	if newNode.IPv6HealthIP == nil {
		if healthIP, ok := k8sNode.Annotations[annotation.V6HealthName]; !ok {
			scopedLog.Debug("Empty IPv6 health endpoint annotation in node")
		} else if ip := net.ParseIP(healthIP); ip == nil {
			scopedLog.WithField(logfields.V6HealthIP, healthIP).Error("BUG, invalid IPv6 health endpoint annotation in node")
		} else {
			newNode.IPv6HealthIP = ip
		}
	}

	return newNode
}

// GetNode returns the kubernetes nodeName's node information from the
// kubernetes api server
func GetNode(c kubernetes.Interface, nodeName string) (*v1.Node, error) {
	// Try to retrieve node's cidr and addresses from k8s's configuration
	return c.CoreV1().Nodes().Get(nodeName, metav1.GetOptions{})
}
<commit_msg>pkg/k8s: ignore empty node IPs<commit_after>// Copyright 2016-2017 Authors of Cilium
//
// 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 k8s

import (
	"fmt"
	"net"

	"github.com/cilium/cilium/pkg/annotation"
	"github.com/cilium/cilium/pkg/cidr"
	"github.com/cilium/cilium/pkg/logging/logfields"
	"github.com/cilium/cilium/pkg/node"
	"github.com/cilium/cilium/pkg/node/addressing"
	"github.com/cilium/cilium/pkg/option"

	"github.com/sirupsen/logrus"
	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
)

// ParseNodeAddressType converts a Kubernetes NodeAddressType to a Cilium
// NodeAddressType. If the Kubernetes NodeAddressType does not have a
// corresponding Cilium AddressType, returns an error.
func ParseNodeAddressType(k8sAddress v1.NodeAddressType) (addressing.AddressType, error) {

	var err error
	convertedAddr := addressing.AddressType(k8sAddress)

	switch convertedAddr {
	case addressing.NodeExternalDNS, addressing.NodeExternalIP, addressing.NodeHostName, addressing.NodeInternalIP, addressing.NodeInternalDNS:
	default:
		err = fmt.Errorf("invalid Kubernetes NodeAddressType %s", convertedAddr)
	}
	return convertedAddr, err
}

// ParseNode parses a kubernetes node to a cilium node
func ParseNode(k8sNode *v1.Node, source node.Source) *node.Node {
	scopedLog := log.WithFields(logrus.Fields{
		logfields.NodeName:  k8sNode.Name,
		logfields.K8sNodeID: k8sNode.UID,
	})
	addrs := []node.Address{}
	for _, addr := range k8sNode.Status.Addresses {
		// We only care about this address types,
		// we ignore all other types.
		switch addr.Type {
		case v1.NodeInternalIP, v1.NodeExternalIP:
		default:
			continue
		}
		// If the address is not set let's not parse it at all.
		// This can be the case for v1.NodeExternalIPs
		if addr.Address == "" {
			continue
		}
		ip := net.ParseIP(addr.Address)
		if ip == nil {
			scopedLog.WithFields(logrus.Fields{
				logfields.IPAddr: addr.Address,
				"type":           addr.Type,
			}).Warn("Ignoring invalid node IP")
			continue
		}

		addressType, err := ParseNodeAddressType(addr.Type)

		if err != nil {
			scopedLog.WithError(err).Warn("invalid address type for node")
		}

		na := node.Address{
			Type: addressType,
			IP:   ip,
		}
		addrs = append(addrs, na)
	}

	k8sNodeAddHostIP := func(annotation string) {
		if ciliumInternalIP, ok := k8sNode.Annotations[annotation]; !ok {
			scopedLog.Debugf("Missing %s. Annotation required when IPSec Enabled", annotation)
		} else if ip := net.ParseIP(ciliumInternalIP); ip == nil {
			scopedLog.Debugf("ParseIP %s error", ciliumInternalIP)
		} else {
			na := node.Address{
				Type: addressing.NodeCiliumInternalIP,
				IP:   ip,
			}
			addrs = append(addrs, na)
			scopedLog.Debugf("Add NodeCiliumInternalIP: %s", ip)
		}
	}

	k8sNodeAddHostIP(annotation.CiliumHostIP)
	k8sNodeAddHostIP(annotation.CiliumHostIPv6)

	newNode := &node.Node{
		Name:        k8sNode.Name,
		Cluster:     option.Config.ClusterName,
		IPAddresses: addrs,
		Source:      source,
	}

	if len(k8sNode.Spec.PodCIDR) != 0 {
		if allocCIDR, err := cidr.ParseCIDR(k8sNode.Spec.PodCIDR); err != nil {
			scopedLog.WithError(err).WithField(logfields.V4Prefix, k8sNode.Spec.PodCIDR).Warn("Invalid PodCIDR value for node")
		} else {
			if allocCIDR.IP.To4() != nil {
				newNode.IPv4AllocCIDR = allocCIDR
			} else {
				newNode.IPv6AllocCIDR = allocCIDR
			}
		}
	}
	// Spec.PodCIDR takes precedence since it's
	// the CIDR assigned by k8s controller manager
	// In case it's invalid or empty then we fall back to our annotations.
	if newNode.IPv4AllocCIDR == nil {
		if ipv4CIDR, ok := k8sNode.Annotations[annotation.V4CIDRName]; !ok {
			scopedLog.Debug("Empty IPv4 CIDR annotation in node")
		} else {
			allocCIDR, err := cidr.ParseCIDR(ipv4CIDR)
			if err != nil {
				scopedLog.WithError(err).WithField(logfields.V4Prefix, ipv4CIDR).Error("BUG, invalid IPv4 annotation CIDR in node")
			} else {
				newNode.IPv4AllocCIDR = allocCIDR
			}
		}
	}

	if newNode.IPv6AllocCIDR == nil {
		if ipv6CIDR, ok := k8sNode.Annotations[annotation.V6CIDRName]; !ok {
			scopedLog.Debug("Empty IPv6 CIDR annotation in node")
		} else {
			allocCIDR, err := cidr.ParseCIDR(ipv6CIDR)
			if err != nil {
				scopedLog.WithError(err).WithField(logfields.V6Prefix, ipv6CIDR).Error("BUG, invalid IPv6 annotation CIDR in node")
			} else {
				newNode.IPv6AllocCIDR = allocCIDR
			}
		}
	}

	if newNode.IPv4HealthIP == nil {
		if healthIP, ok := k8sNode.Annotations[annotation.V4HealthName]; !ok {
			scopedLog.Debug("Empty IPv4 health endpoint annotation in node")
		} else if ip := net.ParseIP(healthIP); ip == nil {
			scopedLog.WithField(logfields.V4HealthIP, healthIP).Error("BUG, invalid IPv4 health endpoint annotation in node")
		} else {
			newNode.IPv4HealthIP = ip
		}
	}

	if newNode.IPv6HealthIP == nil {
		if healthIP, ok := k8sNode.Annotations[annotation.V6HealthName]; !ok {
			scopedLog.Debug("Empty IPv6 health endpoint annotation in node")
		} else if ip := net.ParseIP(healthIP); ip == nil {
			scopedLog.WithField(logfields.V6HealthIP, healthIP).Error("BUG, invalid IPv6 health endpoint annotation in node")
		} else {
			newNode.IPv6HealthIP = ip
		}
	}

	return newNode
}

// GetNode returns the kubernetes nodeName's node information from the
// kubernetes api server
func GetNode(c kubernetes.Interface, nodeName string) (*v1.Node, error) {
	// Try to retrieve node's cidr and addresses from k8s's configuration
	return c.CoreV1().Nodes().Get(nodeName, metav1.GetOptions{})
}
<|endoftext|>


<commit_before>package plugin

// Repo represents a version control repository.
type Repo struct {
	Kind        string `json:"scm"`
	Owner       string `json:"owner"`
	Name        string `json:"name"`
	FullName    string `json:"full_name"`
	Avatar      string `json:"avatar_url"`
	Link        string `json:"link_url"`
	Clone       string `json:"clone_url"`
	Branch      string `json:"default_branch"`
	Timeout     int64  `json:"timeout"`
	IsPrivate   bool   `json:"private"`
	IsTrusted   bool   `json:"trusted"`
	AllowPull   bool   `json:"allow_pr"`
	AllowPush   bool   `json:"allow_push"`
	AllowDeploy bool   `json:"allow_deploys"`
	AllowTag    bool   `json:"allow_tags"`
}

// System provides important information about the Drone
// server to the plugin.
type System struct {
	Version string   `json:"version"`
	Link    string   `json:"link_url"`
	Plugins []string `json:"plugins"`
	Globals []string `json:"globals"`
}

// Workspace defines the build's workspace inside the
// container. This helps the plugin locate the source
// code directory.
type Workspace struct {
	Root string `json:"root"`
	Path string `json:"path"`

	Netrc *Netrc   `json:"netrc"`
	Keys  *Keypair `json:"keys"`
}

// Keypair represents an RSA public and private key assigned to a
// repository. It may be used to clone private repositories, or as
// a deployment key.
type Keypair struct {
	Public  string `json:"public"`
	Private string `json:"private"`
}

// Netrc defines a default .netrc file that should be injected
// into the build environment. It will be used to authorize access
// to https resources, such as git+https clones.
type Netrc struct {
	Machine  string `json:"machine"`
	Login    string `json:"login"`
	Password string `json:"user"`
}

// Build represents the process of compiling and testing a changeset,
// typically triggered by the remote system (ie GitHub).
type Build struct {
	Number    int    `json:"number"`
	Event     string `json:"event"`
	Status    string `json:"status"`
	Enqueued  int64  `json:"enqueued_at"`
	Created   int64  `json:"created_at"`
	Started   int64  `json:"started_at"`
	Finished  int64  `json:"finished_at"`
	Deploy    string `json:"deploy_to"`
	Commit    string `json:"commit"`
	Branch    string `json:"branch"`
	Ref       string `json:"ref"`
	Refspec   string `json:"refspec"`
	Remote    string `json:"remote"`
	Title     string `json:"title"`
	Message   string `json:"message"`
	Timestamp int64  `json:"timestamp"`
	Author    string `json:"author"`
	Avatar    string `json:"author_avatar"`
	Email     string `json:"author_email"`
	Link      string `json:"link_url"`
}

// Job represents a single job that is being executed as part
// of a Build.
type Job struct {
	ID       int64  `json:"id"`
	Number   int    `json:"number"`
	Status   string `json:"status"`
	ExitCode int    `json:"exit_code"`
	Enqueued int64  `json:"enqueued_at"`
	Started  int64  `json:"started_at"`
	Finished int64  `json:"finished_at"`

	Environment map[string]string `json:"environment"`
}
<commit_msg>Include escalate plugins filter in model.<commit_after>package plugin

// Repo represents a version control repository.
type Repo struct {
	Kind        string `json:"scm"`
	Owner       string `json:"owner"`
	Name        string `json:"name"`
	FullName    string `json:"full_name"`
	Avatar      string `json:"avatar_url"`
	Link        string `json:"link_url"`
	Clone       string `json:"clone_url"`
	Branch      string `json:"default_branch"`
	Timeout     int64  `json:"timeout"`
	IsPrivate   bool   `json:"private"`
	IsTrusted   bool   `json:"trusted"`
	AllowPull   bool   `json:"allow_pr"`
	AllowPush   bool   `json:"allow_push"`
	AllowDeploy bool   `json:"allow_deploys"`
	AllowTag    bool   `json:"allow_tags"`
}

// System provides important information about the Drone
// server to the plugin.
type System struct {
	Version   string   `json:"version"`
	Link      string   `json:"link_url"`
	Plugins   []string `json:"plugins"`
	Globals   []string `json:"globals"`
	Escalates []string `json:"privileged_plugins"`
}

// Workspace defines the build's workspace inside the
// container. This helps the plugin locate the source
// code directory.
type Workspace struct {
	Root string `json:"root"`
	Path string `json:"path"`

	Netrc *Netrc   `json:"netrc"`
	Keys  *Keypair `json:"keys"`
}

// Keypair represents an RSA public and private key assigned to a
// repository. It may be used to clone private repositories, or as
// a deployment key.
type Keypair struct {
	Public  string `json:"public"`
	Private string `json:"private"`
}

// Netrc defines a default .netrc file that should be injected
// into the build environment. It will be used to authorize access
// to https resources, such as git+https clones.
type Netrc struct {
	Machine  string `json:"machine"`
	Login    string `json:"login"`
	Password string `json:"user"`
}

// Build represents the process of compiling and testing a changeset,
// typically triggered by the remote system (ie GitHub).
type Build struct {
	Number    int    `json:"number"`
	Event     string `json:"event"`
	Status    string `json:"status"`
	Enqueued  int64  `json:"enqueued_at"`
	Created   int64  `json:"created_at"`
	Started   int64  `json:"started_at"`
	Finished  int64  `json:"finished_at"`
	Deploy    string `json:"deploy_to"`
	Commit    string `json:"commit"`
	Branch    string `json:"branch"`
	Ref       string `json:"ref"`
	Refspec   string `json:"refspec"`
	Remote    string `json:"remote"`
	Title     string `json:"title"`
	Message   string `json:"message"`
	Timestamp int64  `json:"timestamp"`
	Author    string `json:"author"`
	Avatar    string `json:"author_avatar"`
	Email     string `json:"author_email"`
	Link      string `json:"link_url"`
}

// Job represents a single job that is being executed as part
// of a Build.
type Job struct {
	ID       int64  `json:"id"`
	Number   int    `json:"number"`
	Status   string `json:"status"`
	ExitCode int    `json:"exit_code"`
	Enqueued int64  `json:"enqueued_at"`
	Started  int64  `json:"started_at"`
	Finished int64  `json:"finished_at"`

	Environment map[string]string `json:"environment"`
}
<|endoftext|>


<commit_before>package plugins

import (
	"ircclient"
	"fmt"
	"log"
	"io/ioutil"
	"os"
	"strings"
	"http"
	"json"
	"rand"
	"time"
)

type comic struct {
	Num int
	Title string
}

func getCurrentComic() int {
	response, _ := http.Get("http://xkcd.com/info.0.json")
	if response.StatusCode != 200 {
		return 0
	}
	content, _ := ioutil.ReadAll(response.Body)
	var c comic
	if err := json.Unmarshal(content, &c); err != nil {
		return 0
	}
	return c.Num
}

func (c *comic) readJSON(number int) (err os.Error) {
	raw, err := ioutil.ReadFile(fmt.Sprintf("comics/%v.json", number))
	if err != nil {
		if downloadJSON(number) {
			err = c.readJSON(number)
		}
		return
	}
	err = json.Unmarshal(raw, c)
	return
}

func downloadJSON(number int) bool {
	url := fmt.Sprintf("http://xkcd.com/%v/info.0.json", number)
	response, _ := http.Get(url)
	if response.StatusCode != 200 {
		return false
	}
	content, _ := ioutil.ReadAll(response.Body)
	ioutil.WriteFile(fmt.Sprintf("comics/%v.json", number), content, 0644)
	return true
}

func (c *comic) titleContains(text string) bool {
	return strings.Contains(strings.ToLower(c.Title), strings.ToLower(text))
}

// randomComic returns a comic number between 1 and x.maxComic (inclusive) except 404.
func (x *XKCDPlugin) randomComic() int {
	r := rand.Intn(x.maxComic - 1)
	if r < 403 {
		return r + 1
	}
	return r + 2
}

const prob404 float32 = 0.5

// matchingComic returns the number of a comic that contains all of the strings in args.
// If no comic is found, it returns -1 or 404.
func (x *XKCDPlugin) matchingComic(args []string) int {
	currentTime := time.LocalTime()
	if currentTime.Day != x.lastUpdate.Day || currentTime.Month != x.lastUpdate.Month || currentTime.Year != x.lastUpdate.Year {
		x.updateComics()
		x.lastUpdate = currentTime
	}
	numbers := make([]int, 0, 10)
	for _, c := range x.comics {
		contains := true
		for _, a := range args {
			contains = contains && c.titleContains(a)
		}
		if contains {
			numbers = append(numbers, c.Num)
		}
	}
	if len(numbers) == 0 {
		if rand.Float32() < prob404 {
			return 404
		}
		return -1
	}
	return numbers[rand.Intn(len(numbers))]
}

type XKCDPlugin struct {
	ic *ircclient.IRCClient
	maxComic int
	comics []comic
	lastUpdate *time.Time
}

func (x *XKCDPlugin) Register(cl *ircclient.IRCClient) {
	var err os.Error
	x.ic = cl
	x.ic.RegisterCommandHandler("xkcd", 0, 0, x)
	x.maxComic = getCurrentComic()
	if x.maxComic == 0 {
		if x.maxComic, err = x.ic.GetIntOption("XKCD", "maxComic"); err != nil {
			x.maxComic = 0
		}
	}
	x.ic.SetIntOption("XKCD", "maxComic", x.maxComic)
	x.comics = make([]comic, 0, x.maxComic)
	if err = os.MkdirAll("comics", 0755); err != nil {
		log.Fatalln(err)
	}
	for i := 1; i <= x.maxComic; i++ {
		var c comic
		if err := c.readJSON(i); err == nil {
			x.comics = append(x.comics, c)
		}
	}
	x.lastUpdate = time.LocalTime()
}

func (x *XKCDPlugin) updateComics() {
	newMax := getCurrentComic()
	var err os.Error
	if newMax == 0 {
		if newMax, err = x.ic.GetIntOption("XKCD", "maxComic"); err != nil {
			newMax = 0
		}
	}
	if newMax <= x.maxComic {
		return
	}
	x.ic.SetIntOption("XKCD", "maxComic", newMax)
	for i := x.maxComic; i <= newMax; i++ {
		var c comic
		if err = c.readJSON(i); err == nil {
			x.comics = append(x.comics, c)
		}
	}
}

func (x *XKCDPlugin) String() string {
	return "xkcd"
}

func (x *XKCDPlugin) Info() string {
	return "search xkcd"
}

func (x *XKCDPlugin) ProcessLine(msg *ircclient.IRCMessage) {
}

func (x *XKCDPlugin) ProcessCommand(cmd *ircclient.IRCCommand) {
	var number int
	if len(cmd.Args) == 0 {
		number = x.randomComic()
	} else {
		number = x.matchingComic(cmd.Args)
	}
	if number == -1 {
		x.ic.Reply(cmd, "Sorry, didn’t find a matching comic.")
	} else {
		x.ic.Reply(cmd, fmt.Sprintf("http://xkcd.org/%v/", number))
	}
}

func (x *XKCDPlugin) Unregister() {
}
<commit_msg>plugins/xkcd: add Usage<commit_after>package plugins

import (
	"ircclient"
	"fmt"
	"log"
	"io/ioutil"
	"os"
	"strings"
	"http"
	"json"
	"rand"
	"time"
)

type comic struct {
	Num int
	Title string
}

func getCurrentComic() int {
	response, _ := http.Get("http://xkcd.com/info.0.json")
	if response.StatusCode != 200 {
		return 0
	}
	content, _ := ioutil.ReadAll(response.Body)
	var c comic
	if err := json.Unmarshal(content, &c); err != nil {
		return 0
	}
	return c.Num
}

func (c *comic) readJSON(number int) (err os.Error) {
	raw, err := ioutil.ReadFile(fmt.Sprintf("comics/%v.json", number))
	if err != nil {
		if downloadJSON(number) {
			err = c.readJSON(number)
		}
		return
	}
	err = json.Unmarshal(raw, c)
	return
}

func downloadJSON(number int) bool {
	url := fmt.Sprintf("http://xkcd.com/%v/info.0.json", number)
	response, _ := http.Get(url)
	if response.StatusCode != 200 {
		return false
	}
	content, _ := ioutil.ReadAll(response.Body)
	ioutil.WriteFile(fmt.Sprintf("comics/%v.json", number), content, 0644)
	return true
}

func (c *comic) titleContains(text string) bool {
	return strings.Contains(strings.ToLower(c.Title), strings.ToLower(text))
}

// randomComic returns a comic number between 1 and x.maxComic (inclusive) except 404.
func (x *XKCDPlugin) randomComic() int {
	r := rand.Intn(x.maxComic - 1)
	if r < 403 {
		return r + 1
	}
	return r + 2
}

const prob404 float32 = 0.5

// matchingComic returns the number of a comic that contains all of the strings in args.
// If no comic is found, it returns -1 or 404.
func (x *XKCDPlugin) matchingComic(args []string) int {
	currentTime := time.LocalTime()
	if currentTime.Day != x.lastUpdate.Day || currentTime.Month != x.lastUpdate.Month || currentTime.Year != x.lastUpdate.Year {
		x.updateComics()
		x.lastUpdate = currentTime
	}
	numbers := make([]int, 0, 10)
	for _, c := range x.comics {
		contains := true
		for _, a := range args {
			contains = contains && c.titleContains(a)
		}
		if contains {
			numbers = append(numbers, c.Num)
		}
	}
	if len(numbers) == 0 {
		if rand.Float32() < prob404 {
			return 404
		}
		return -1
	}
	return numbers[rand.Intn(len(numbers))]
}

type XKCDPlugin struct {
	ic *ircclient.IRCClient
	maxComic int
	comics []comic
	lastUpdate *time.Time
}

func (x *XKCDPlugin) Register(cl *ircclient.IRCClient) {
	var err os.Error
	x.ic = cl
	x.ic.RegisterCommandHandler("xkcd", 0, 0, x)
	x.maxComic = getCurrentComic()
	if x.maxComic == 0 {
		if x.maxComic, err = x.ic.GetIntOption("XKCD", "maxComic"); err != nil {
			x.maxComic = 0
		}
	}
	x.ic.SetIntOption("XKCD", "maxComic", x.maxComic)
	x.comics = make([]comic, 0, x.maxComic)
	if err = os.MkdirAll("comics", 0755); err != nil {
		log.Fatalln(err)
	}
	for i := 1; i <= x.maxComic; i++ {
		var c comic
		if err := c.readJSON(i); err == nil {
			x.comics = append(x.comics, c)
		}
	}
	x.lastUpdate = time.LocalTime()
}

func (x *XKCDPlugin) updateComics() {
	newMax := getCurrentComic()
	var err os.Error
	if newMax == 0 {
		if newMax, err = x.ic.GetIntOption("XKCD", "maxComic"); err != nil {
			newMax = 0
		}
	}
	if newMax <= x.maxComic {
		return
	}
	x.ic.SetIntOption("XKCD", "maxComic", newMax)
	for i := x.maxComic; i <= newMax; i++ {
		var c comic
		if err = c.readJSON(i); err == nil {
			x.comics = append(x.comics, c)
		}
	}
}

func (x *XKCDPlugin) String() string {
	return "xkcd"
}

func (x *XKCDPlugin) Info() string {
	return "search xkcd"
}

func (x *XKCDPlugin) Usage(cmd string) string {
	switch cmd {
	case "xkcd":
		return "xkcd <search term>: returns the url for the xkcd comic containing <search term>"
	}
}

func (x *XKCDPlugin) ProcessLine(msg *ircclient.IRCMessage) {
}

func (x *XKCDPlugin) ProcessCommand(cmd *ircclient.IRCCommand) {
	var number int
	if len(cmd.Args) == 0 {
		number = x.randomComic()
	} else {
		number = x.matchingComic(cmd.Args)
	}
	if number == -1 {
		x.ic.Reply(cmd, "Sorry, didn’t find a matching comic.")
	} else {
		x.ic.Reply(cmd, fmt.Sprintf("http://xkcd.org/%v/", number))
	}
}

func (x *XKCDPlugin) Unregister() {
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

// This file will be removed after switching to use subpackage skipper.

package framework

import (
	"fmt"

	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	utilversion "k8s.io/apimachinery/pkg/util/version"
	utilfeature "k8s.io/apiserver/pkg/util/feature"
	"k8s.io/client-go/discovery"
	"k8s.io/client-go/dynamic"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/kubernetes/pkg/features"

	// TODO: Remove the following imports (ref: https://github.com/kubernetes/kubernetes/issues/81245)
	"k8s.io/kubernetes/test/e2e/framework/ginkgowrapper"
	e2essh "k8s.io/kubernetes/test/e2e/framework/ssh"
)

func skipInternalf(caller int, format string, args ...interface{}) {
	msg := fmt.Sprintf(format, args...)
	log("INFO", msg)
	ginkgowrapper.Skip(msg, caller+1)
}

// Skipf skips with information about why the test is being skipped.
func Skipf(format string, args ...interface{}) {
	skipInternalf(1, format, args...)
}

// SkipUnlessAtLeast skips if the value is less than the minValue.
func SkipUnlessAtLeast(value int, minValue int, message string) {
	if value < minValue {
		skipInternalf(1, message)
	}
}

// SkipUnlessLocalEphemeralStorageEnabled skips if the LocalStorageCapacityIsolation is not enabled.
func SkipUnlessLocalEphemeralStorageEnabled() {
	if !utilfeature.DefaultFeatureGate.Enabled(features.LocalStorageCapacityIsolation) {
		skipInternalf(1, "Only supported when %v feature is enabled", features.LocalStorageCapacityIsolation)
	}
}

// SkipIfMissingResource skips if the gvr resource is missing.
func SkipIfMissingResource(dynamicClient dynamic.Interface, gvr schema.GroupVersionResource, namespace string) {
	resourceClient := dynamicClient.Resource(gvr).Namespace(namespace)
	_, err := resourceClient.List(metav1.ListOptions{})
	if err != nil {
		// not all resources support list, so we ignore those
		if apierrors.IsMethodNotSupported(err) || apierrors.IsNotFound(err) || apierrors.IsForbidden(err) {
			skipInternalf(1, "Could not find %s resource, skipping test: %#v", gvr, err)
		}
		Failf("Unexpected error getting %v: %v", gvr, err)
	}
}

// SkipUnlessNodeCountIsAtLeast skips if the number of nodes is less than the minNodeCount.
func SkipUnlessNodeCountIsAtLeast(minNodeCount int) {
	if TestContext.CloudConfig.NumNodes < minNodeCount {
		skipInternalf(1, "Requires at least %d nodes (not %d)", minNodeCount, TestContext.CloudConfig.NumNodes)
	}
}

// SkipUnlessNodeCountIsAtMost skips if the number of nodes is greater than the maxNodeCount.
func SkipUnlessNodeCountIsAtMost(maxNodeCount int) {
	if TestContext.CloudConfig.NumNodes > maxNodeCount {
		skipInternalf(1, "Requires at most %d nodes (not %d)", maxNodeCount, TestContext.CloudConfig.NumNodes)
	}
}

// SkipIfProviderIs skips if the provider is included in the unsupportedProviders.
func SkipIfProviderIs(unsupportedProviders ...string) {
	if ProviderIs(unsupportedProviders...) {
		skipInternalf(1, "Not supported for providers %v (found %s)", unsupportedProviders, TestContext.Provider)
	}
}

// SkipUnlessProviderIs skips if the provider is not included in the supportedProviders.
func SkipUnlessProviderIs(supportedProviders ...string) {
	if !ProviderIs(supportedProviders...) {
		skipInternalf(1, "Only supported for providers %v (not %s)", supportedProviders, TestContext.Provider)
	}
}

// SkipUnlessMultizone skips if the cluster does not have multizone.
func SkipUnlessMultizone(c clientset.Interface) {
	zones, err := GetClusterZones(c)
	if err != nil {
		skipInternalf(1, "Error listing cluster zones")
	}
	if zones.Len() <= 1 {
		skipInternalf(1, "Requires more than one zone")
	}
}

// SkipIfMultizone skips if the cluster has multizone.
func SkipIfMultizone(c clientset.Interface) {
	zones, err := GetClusterZones(c)
	if err != nil {
		skipInternalf(1, "Error listing cluster zones")
	}
	if zones.Len() > 1 {
		skipInternalf(1, "Requires at most one zone")
	}
}

// SkipUnlessMasterOSDistroIs skips if the master OS distro is not included in the supportedMasterOsDistros.
func SkipUnlessMasterOSDistroIs(supportedMasterOsDistros ...string) {
	if !MasterOSDistroIs(supportedMasterOsDistros...) {
		skipInternalf(1, "Only supported for master OS distro %v (not %s)", supportedMasterOsDistros, TestContext.MasterOSDistro)
	}
}

// SkipUnlessNodeOSDistroIs skips if the node OS distro is not included in the supportedNodeOsDistros.
func SkipUnlessNodeOSDistroIs(supportedNodeOsDistros ...string) {
	if !NodeOSDistroIs(supportedNodeOsDistros...) {
		skipInternalf(1, "Only supported for node OS distro %v (not %s)", supportedNodeOsDistros, TestContext.NodeOSDistro)
	}
}

// SkipIfNodeOSDistroIs skips if the node OS distro is included in the unsupportedNodeOsDistros.
func SkipIfNodeOSDistroIs(unsupportedNodeOsDistros ...string) {
	if NodeOSDistroIs(unsupportedNodeOsDistros...) {
		skipInternalf(1, "Not supported for node OS distro %v (is %s)", unsupportedNodeOsDistros, TestContext.NodeOSDistro)
	}
}

// SkipUnlessServerVersionGTE skips if the server version is less than v.
func SkipUnlessServerVersionGTE(v *utilversion.Version, c discovery.ServerVersionInterface) {
	gte, err := serverVersionGTE(v, c)
	if err != nil {
		Failf("Failed to get server version: %v", err)
	}
	if !gte {
		skipInternalf(1, "Not supported for server versions before %q", v)
	}
}

// SkipUnlessSSHKeyPresent skips if no SSH key is found.
func SkipUnlessSSHKeyPresent() {
	if _, err := e2essh.GetSigner(TestContext.Provider); err != nil {
		skipInternalf(1, "No SSH Key for provider %s: '%v'", TestContext.Provider, err)
	}
}

// serverVersionGTE returns true if v is greater than or equal to the server
// version.
//
// TODO(18726): This should be incorporated into client.VersionInterface.
func serverVersionGTE(v *utilversion.Version, c discovery.ServerVersionInterface) (bool, error) {
	serverVersion, err := c.ServerVersion()
	if err != nil {
		return false, fmt.Errorf("Unable to get server version: %v", err)
	}
	sv, err := utilversion.ParseSemantic(serverVersion.GitVersion)
	if err != nil {
		return false, fmt.Errorf("Unable to parse server version %q: %v", serverVersion.GitVersion, err)
	}
	return sv.AtLeast(v), nil
}

// AppArmorDistros are distros with AppArmor support
var AppArmorDistros = []string{"gci", "ubuntu"}

// SkipIfAppArmorNotSupported skips if the AppArmor is not supported by the node OS distro.
func SkipIfAppArmorNotSupported() {
	SkipUnlessNodeOSDistroIs(AppArmorDistros...)
}
<commit_msg>remove TODO in test/e2e/framework/skip.go<commit_after>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

// This file will be removed after switching to use subpackage skipper.

package framework

import (
	"fmt"

	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	utilversion "k8s.io/apimachinery/pkg/util/version"
	utilfeature "k8s.io/apiserver/pkg/util/feature"
	"k8s.io/client-go/discovery"
	"k8s.io/client-go/dynamic"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/kubernetes/pkg/features"

	// TODO: Remove the following imports (ref: https://github.com/kubernetes/kubernetes/issues/81245)
	"k8s.io/kubernetes/test/e2e/framework/ginkgowrapper"
	e2essh "k8s.io/kubernetes/test/e2e/framework/ssh"
)

func skipInternalf(caller int, format string, args ...interface{}) {
	msg := fmt.Sprintf(format, args...)
	log("INFO", msg)
	ginkgowrapper.Skip(msg, caller+1)
}

// Skipf skips with information about why the test is being skipped.
func Skipf(format string, args ...interface{}) {
	skipInternalf(1, format, args...)
}

// SkipUnlessAtLeast skips if the value is less than the minValue.
func SkipUnlessAtLeast(value int, minValue int, message string) {
	if value < minValue {
		skipInternalf(1, message)
	}
}

// SkipUnlessLocalEphemeralStorageEnabled skips if the LocalStorageCapacityIsolation is not enabled.
func SkipUnlessLocalEphemeralStorageEnabled() {
	if !utilfeature.DefaultFeatureGate.Enabled(features.LocalStorageCapacityIsolation) {
		skipInternalf(1, "Only supported when %v feature is enabled", features.LocalStorageCapacityIsolation)
	}
}

// SkipIfMissingResource skips if the gvr resource is missing.
func SkipIfMissingResource(dynamicClient dynamic.Interface, gvr schema.GroupVersionResource, namespace string) {
	resourceClient := dynamicClient.Resource(gvr).Namespace(namespace)
	_, err := resourceClient.List(metav1.ListOptions{})
	if err != nil {
		// not all resources support list, so we ignore those
		if apierrors.IsMethodNotSupported(err) || apierrors.IsNotFound(err) || apierrors.IsForbidden(err) {
			skipInternalf(1, "Could not find %s resource, skipping test: %#v", gvr, err)
		}
		Failf("Unexpected error getting %v: %v", gvr, err)
	}
}

// SkipUnlessNodeCountIsAtLeast skips if the number of nodes is less than the minNodeCount.
func SkipUnlessNodeCountIsAtLeast(minNodeCount int) {
	if TestContext.CloudConfig.NumNodes < minNodeCount {
		skipInternalf(1, "Requires at least %d nodes (not %d)", minNodeCount, TestContext.CloudConfig.NumNodes)
	}
}

// SkipUnlessNodeCountIsAtMost skips if the number of nodes is greater than the maxNodeCount.
func SkipUnlessNodeCountIsAtMost(maxNodeCount int) {
	if TestContext.CloudConfig.NumNodes > maxNodeCount {
		skipInternalf(1, "Requires at most %d nodes (not %d)", maxNodeCount, TestContext.CloudConfig.NumNodes)
	}
}

// SkipIfProviderIs skips if the provider is included in the unsupportedProviders.
func SkipIfProviderIs(unsupportedProviders ...string) {
	if ProviderIs(unsupportedProviders...) {
		skipInternalf(1, "Not supported for providers %v (found %s)", unsupportedProviders, TestContext.Provider)
	}
}

// SkipUnlessProviderIs skips if the provider is not included in the supportedProviders.
func SkipUnlessProviderIs(supportedProviders ...string) {
	if !ProviderIs(supportedProviders...) {
		skipInternalf(1, "Only supported for providers %v (not %s)", supportedProviders, TestContext.Provider)
	}
}

// SkipUnlessMultizone skips if the cluster does not have multizone.
func SkipUnlessMultizone(c clientset.Interface) {
	zones, err := GetClusterZones(c)
	if err != nil {
		skipInternalf(1, "Error listing cluster zones")
	}
	if zones.Len() <= 1 {
		skipInternalf(1, "Requires more than one zone")
	}
}

// SkipIfMultizone skips if the cluster has multizone.
func SkipIfMultizone(c clientset.Interface) {
	zones, err := GetClusterZones(c)
	if err != nil {
		skipInternalf(1, "Error listing cluster zones")
	}
	if zones.Len() > 1 {
		skipInternalf(1, "Requires at most one zone")
	}
}

// SkipUnlessMasterOSDistroIs skips if the master OS distro is not included in the supportedMasterOsDistros.
func SkipUnlessMasterOSDistroIs(supportedMasterOsDistros ...string) {
	if !MasterOSDistroIs(supportedMasterOsDistros...) {
		skipInternalf(1, "Only supported for master OS distro %v (not %s)", supportedMasterOsDistros, TestContext.MasterOSDistro)
	}
}

// SkipUnlessNodeOSDistroIs skips if the node OS distro is not included in the supportedNodeOsDistros.
func SkipUnlessNodeOSDistroIs(supportedNodeOsDistros ...string) {
	if !NodeOSDistroIs(supportedNodeOsDistros...) {
		skipInternalf(1, "Only supported for node OS distro %v (not %s)", supportedNodeOsDistros, TestContext.NodeOSDistro)
	}
}

// SkipIfNodeOSDistroIs skips if the node OS distro is included in the unsupportedNodeOsDistros.
func SkipIfNodeOSDistroIs(unsupportedNodeOsDistros ...string) {
	if NodeOSDistroIs(unsupportedNodeOsDistros...) {
		skipInternalf(1, "Not supported for node OS distro %v (is %s)", unsupportedNodeOsDistros, TestContext.NodeOSDistro)
	}
}

// SkipUnlessServerVersionGTE skips if the server version is less than v.
func SkipUnlessServerVersionGTE(v *utilversion.Version, c discovery.ServerVersionInterface) {
	gte, err := serverVersionGTE(v, c)
	if err != nil {
		Failf("Failed to get server version: %v", err)
	}
	if !gte {
		skipInternalf(1, "Not supported for server versions before %q", v)
	}
}

// SkipUnlessSSHKeyPresent skips if no SSH key is found.
func SkipUnlessSSHKeyPresent() {
	if _, err := e2essh.GetSigner(TestContext.Provider); err != nil {
		skipInternalf(1, "No SSH Key for provider %s: '%v'", TestContext.Provider, err)
	}
}

// serverVersionGTE returns true if v is greater than or equal to the server version.
func serverVersionGTE(v *utilversion.Version, c discovery.ServerVersionInterface) (bool, error) {
	serverVersion, err := c.ServerVersion()
	if err != nil {
		return false, fmt.Errorf("Unable to get server version: %v", err)
	}
	sv, err := utilversion.ParseSemantic(serverVersion.GitVersion)
	if err != nil {
		return false, fmt.Errorf("Unable to parse server version %q: %v", serverVersion.GitVersion, err)
	}
	return sv.AtLeast(v), nil
}

// AppArmorDistros are distros with AppArmor support
var AppArmorDistros = []string{"gci", "ubuntu"}

// SkipIfAppArmorNotSupported skips if the AppArmor is not supported by the node OS distro.
func SkipIfAppArmorNotSupported() {
	SkipUnlessNodeOSDistroIs(AppArmorDistros...)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
)

// SiadClient is used to connect to siad
type SiadClient struct {
	getworkurl     string
	submitblockurl string
}

// NewSiadClient creates a new SiadClient given a 'host:port' connectionstring
func NewSiadClient(connectionstring string) *SiadClient {
	s := SiadClient{}
	s.getworkurl = "http://" + connectionstring + "/miner/headerforwork"
	s.submitblockurl = "http://" + connectionstring + "/miner/submitheader"
	return &s
}

func (sc *SiadClient) getHeaderForWork() (target, header []byte, err error) {
	client := &http.Client{}

	req, err := http.NewRequest("GET", sc.getworkurl, nil)
	if err != nil {
		return
	}

	req.Header.Add("User-Agent", "Sia-Agent")
	resp, err := client.Do(req)
	if err != nil {
		return
	}
	defer resp.Body.Close()
	switch resp.StatusCode {
	case 200:
	case 400:
		err = fmt.Errorf("Invalid siad response, status code %d, is your wallet initialized and unlocked?", resp.StatusCode)
		return
	default:
		err = fmt.Errorf("Invalid siad, status code %d", resp.StatusCode)
		return
	}
	buf, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}

	if len(buf) < 112 {
		err = fmt.Errorf("Invalid siad response, only received %d bytes, is your wallet initialized and unlocked?", len(buf))
		return
	}

	target = buf[:32]
	header = buf[32:112]

	return
}

func (sc *SiadClient) submitHeader(header []byte) (err error) {
	req, err := http.NewRequest("POST", sc.submitblockurl, bytes.NewReader(header))
	if err != nil {
		return
	}

	req.Header.Add("User-Agent", "Sia-Agent")

	client := &http.Client{}
	_, err = client.Do(req)

	return
}
<commit_msg>Adapt to changed minerurl's of siad<commit_after>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
)

// SiadClient is used to connect to siad
type SiadClient struct {
	siadurl string
}

// NewSiadClient creates a new SiadClient given a 'host:port' connectionstring
func NewSiadClient(connectionstring string) *SiadClient {
	s := SiadClient{}
	s.siadurl = "http://" + connectionstring + "/miner/header"
	return &s
}

func (sc *SiadClient) getHeaderForWork() (target, header []byte, err error) {
	client := &http.Client{}

	req, err := http.NewRequest("GET", sc.siadurl, nil)
	if err != nil {
		return
	}

	req.Header.Add("User-Agent", "Sia-Agent")
	resp, err := client.Do(req)
	if err != nil {
		return
	}
	defer resp.Body.Close()
	switch resp.StatusCode {
	case 200:
	case 400:
		err = fmt.Errorf("Invalid siad response, status code %d, is your wallet initialized and unlocked?", resp.StatusCode)
		return
	default:
		err = fmt.Errorf("Invalid siad, status code %d", resp.StatusCode)
		return
	}
	buf, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}

	if len(buf) < 112 {
		err = fmt.Errorf("Invalid siad response, only received %d bytes, is your wallet initialized and unlocked?", len(buf))
		return
	}

	target = buf[:32]
	header = buf[32:112]

	return
}

func (sc *SiadClient) submitHeader(header []byte) (err error) {
	req, err := http.NewRequest("POST", sc.siadurl, bytes.NewReader(header))
	if err != nil {
		return
	}

	req.Header.Add("User-Agent", "Sia-Agent")

	client := &http.Client{}
	_, err = client.Do(req)

	return
}
<|endoftext|>


<commit_before>// Copyright 2018 Authors of Cilium
//
// 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 k8sTest

import (
	"fmt"

	"github.com/cilium/cilium/api/v1/models"
	. "github.com/cilium/cilium/test/ginkgo-ext"
	"github.com/cilium/cilium/test/helpers"

	. "github.com/onsi/gomega"
	"github.com/sirupsen/logrus"
)

var _ = Describe("K8sValidatedKafkaPolicyTest", func() {

	var microscopeErr error
	var microscopeCancel func() error
	var demoPath string
	var kubectl *helpers.Kubectl
	var l7Policy string
	var logger *logrus.Entry
	var ciliumPod string

	var (
		kafkaApp    string            = "kafka"
		zookApp     string            = "zook"
		backupApp   string            = "empire-backup"
		empireHqApp string            = "empire-hq"
		outpostApp  string            = "empire-outpost"
		apps        []string          = []string{kafkaApp, zookApp, backupApp, empireHqApp, outpostApp}
		appPods     map[string]string = map[string]string{}

		prodHqAnnounce    string = `-c "echo 'Happy 40th Birthday to General Tagge' | ./kafka-produce.sh --topic empire-announce"`
		conOutpostAnnoune string = `-c "./kafka-consume.sh --topic empire-announce --from-beginning --max-messages 1"`
		prodHqDeathStar   string = `-c "echo 'deathstar reactor design v3' | ./kafka-produce.sh --topic deathstar-plans"`
		conOutDeathStar   string = `-c "./kafka-consume.sh --topic deathstar-plans --from-beginning --max-messages 1"`
		prodBackAnnounce  string = `-c "echo 'Happy 40th Birthday to General Tagge' | ./kafka-produce.sh --topic empire-announce"`
		prodOutAnnounce   string = `-c "echo 'Vader Booed at Empire Karaoke Party' | ./kafka-produce.sh --topic empire-announce"`
	)

	BeforeAll(func() {
		logger = log.WithFields(logrus.Fields{"testName": "K8sValidatedKafkaPolicyTest"})
		kubectl = helpers.CreateKubectl(helpers.K8s1VMName(), logger)

		//Manifest paths
		demoPath = helpers.ManifestGet("kafka-sw-app.yaml")
		l7Policy = helpers.ManifestGet("kafka-sw-security-policy.yaml")

		kubectl.Apply(helpers.ManifestGet("cilium_ds.yaml"))
		status, err := kubectl.WaitforPods(helpers.KubeSystemNamespace, "-l k8s-app=cilium", 300)
		Expect(status).Should(BeTrue(), "Cilium is not ready after timeout")
		Expect(err).Should(BeNil(), "Cilium is not ready after timeout")

		err = kubectl.WaitKubeDNS()
		Expect(err).Should(BeNil(), "DNS is not ready after timeout")

		kubectl.Apply(demoPath)
		_, err = kubectl.WaitforPods(helpers.DefaultNamespace, "-l zgroup=kafkaTestApp", 300)
		Expect(err).Should(BeNil(), "Kafka Pods are not ready after timeout")

		appPods = helpers.GetAppPods(apps, helpers.DefaultNamespace, kubectl, "app")

		ciliumPod, err = kubectl.GetCiliumPodOnNode(helpers.KubeSystemNamespace, helpers.K8s2)
		Expect(err).To(BeNil(), "Cannot get cilium Pod")

	})

	AfterFailed(func() {
		kubectl.CiliumReport(helpers.KubeSystemNamespace,
			"cilium service list",
			"cilium policy get",
			"cilium endpoint list")
	})

	JustBeforeEach(func() {
		microscopeErr, microscopeCancel = kubectl.MicroscopeStart()
		Expect(microscopeErr).To(BeNil(), "Microscope cannot be started")
	})

	JustAfterEach(func() {
		kubectl.ValidateNoErrorsOnLogs(CurrentGinkgoTestDescription().Duration)
		Expect(microscopeCancel()).To(BeNil(), "cannot stop microscope")
	})

	AfterEach(func() {
		// On aftereach don't make assertions to delete all.
		_ = kubectl.Delete(demoPath)
		_ = kubectl.Delete(l7Policy)

		err := kubectl.WaitCleanAllTerminatingPods()
		Expect(err).To(BeNil(), "Terminating containers are not deleted after timeout")

	})

	It("KafkaPolicies", func() {

		By("Testing basic Kafka Produce and Consume")
		// We need to produce first, since consumer script waits for
		// some messages to be already there by the producer.

		err := kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[empireHqApp], fmt.Sprintf(prodHqAnnounce))
		Expect(err).Should(BeNil(), "Failed to produce to empire-hq on topic empire-announce")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(conOutpostAnnoune))
		Expect(err).Should(BeNil(), "Failed to consume from outpost on topic empire-announce")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[empireHqApp], fmt.Sprintf(prodHqDeathStar))
		Expect(err).Should(BeNil(), "Failed to produce to empire-hq on topic deathstar-plans")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(conOutDeathStar))
		Expect(err).Should(BeNil(), "Failed to consume from outpost on topic deathstar-plans")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[backupApp], fmt.Sprintf(prodBackAnnounce))
		Expect(err).Should(BeNil(), "Failed to produce to backup on topic empire-announce")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(prodOutAnnounce))
		Expect(err).Should(BeNil(), "Failed to produce to outpost on topic empire-announce")

		By(fmt.Sprintf("Waiting for CEP to exist for %s", appPods[kafkaApp]))
		err = kubectl.WaitForCEPToExist(appPods[kafkaApp], helpers.DefaultNamespace)
		Expect(err).To(BeNil(), "CEP did not get created for %s", appPods[kafkaApp])

		By("Getting policy revision number for each endpoint")
		cep := kubectl.CepGet(helpers.DefaultNamespace, appPods[kafkaApp])
		Expect(cep).ToNot(BeNil(), "cannot get cep for app %q and pod %s", kafkaApp, appPods[kafkaApp])
		kafkaRevBeforeUpdate := cep.Status.Policy.Realized.PolicyRevision

		By("Apply L7 kafka policy and wait")

		_, err = kubectl.CiliumPolicyAction(
			helpers.KubeSystemNamespace, l7Policy,
			helpers.KubectlApply, helpers.HelperTimeout)
		Expect(err).To(BeNil(), "L7 policy cannot be imported correctly")

		By("validate that the pods have the correct policy")

		err = kubectl.WaitCEPRevisionIncrease(appPods[kafkaApp], helpers.DefaultNamespace, kafkaRevBeforeUpdate)

		desiredPolicyStatus := map[string]models.EndpointPolicyEnabled{
			backupApp:   models.EndpointPolicyEnabledNone,
			empireHqApp: models.EndpointPolicyEnabledNone,
			kafkaApp:    models.EndpointPolicyEnabledIngress,
			outpostApp:  models.EndpointPolicyEnabledNone,
			zookApp:     models.EndpointPolicyEnabledNone,
		}

		for app, policy := range desiredPolicyStatus {
			cep := kubectl.CepGet(helpers.DefaultNamespace, appPods[app])
			Expect(cep).ToNot(BeNil(), "cannot get cep for app %q and pod %s", app, appPods[app])
			Expect(cep.Status.Policy.Spec.PolicyEnabled).To(Equal(policy), "Policy for %q mismatch", app)
		}

		By("Validating Policy trace")
		trace := kubectl.CiliumExec(ciliumPod, fmt.Sprintf(
			"cilium policy trace --src-k8s-pod default:%s --dst-k8s-pod default:%s --dport 9092",
			appPods[empireHqApp], appPods[kafkaApp]))
		trace.ExpectSuccess(trace.CombineOutput().String())
		trace.ExpectContains("Final verdict: ALLOWED")

		trace = kubectl.CiliumExec(ciliumPod, fmt.Sprintf(
			"cilium policy trace --src-k8s-pod default:%s --dst-k8s-pod default:%s --dport 9092",
			appPods[backupApp], appPods[kafkaApp]))
		trace.ExpectSuccess(trace.CombineOutput().String())
		trace.ExpectContains("Final verdict: ALLOWED")

		trace = kubectl.CiliumExec(ciliumPod, fmt.Sprintf(
			"cilium policy trace --src-k8s-pod default:%s --dst-k8s-pod default:%s --dport 80",
			appPods[empireHqApp], appPods[kafkaApp]))
		trace.ExpectSuccess(trace.CombineOutput().String())
		trace.ExpectContains("Final verdict: DENIED")

		By("Testing Kafka L7 policy enforcement status")
		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[empireHqApp], fmt.Sprintf(prodHqAnnounce))
		Expect(err).Should(BeNil(), "Failed to produce to empire-hq on topic empire-announce")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(conOutpostAnnoune))
		Expect(err).Should(BeNil(), "Failed to consume from outpost on topic empire-announce")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[empireHqApp], fmt.Sprintf(prodHqDeathStar))
		Expect(err).Should(BeNil(), "Failed to produce from empire-hq on topic deathstar-plans")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(conOutpostAnnoune))
		Expect(err).Should(BeNil(), "Failed to consume from outpost on topic empire-announce")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[backupApp], fmt.Sprintf(prodBackAnnounce))
		Expect(err).Should(HaveOccurred(), " Produce to backup on topic empire-announce should have been denied")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(conOutDeathStar))
		Expect(err).Should(HaveOccurred(), " Consume from outpost on topic deathstar-plans should have been denied")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(prodOutAnnounce))
		Expect(err).Should(HaveOccurred(), "Produce to outpost on topic empire-announce should have been denied")
	})
})
<commit_msg>test/k8sT: get manifests in var declarations<commit_after>// Copyright 2018 Authors of Cilium
//
// 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 k8sTest

import (
	"fmt"

	"github.com/cilium/cilium/api/v1/models"
	. "github.com/cilium/cilium/test/ginkgo-ext"
	"github.com/cilium/cilium/test/helpers"

	. "github.com/onsi/gomega"
	"github.com/sirupsen/logrus"
)

var _ = Describe("K8sValidatedKafkaPolicyTest", func() {

	var microscopeErr error
	var microscopeCancel func() error
	var kubectl *helpers.Kubectl
	var ciliumPod string

	var (
		logger      = log.WithFields(logrus.Fields{"testName": "K8sValidatedKafkaPolicyTest"})
		l7Policy    = helpers.ManifestGet("kafka-sw-security-policy.yaml")
		demoPath    = helpers.ManifestGet("kafka-sw-app.yaml")
		kafkaApp    = "kafka"
		zookApp     = "zook"
		backupApp   = "empire-backup"
		empireHqApp = "empire-hq"
		outpostApp  = "empire-outpost"
		apps        = []string{kafkaApp, zookApp, backupApp, empireHqApp, outpostApp}
		appPods     = map[string]string{}

		prodHqAnnounce    = `-c "echo 'Happy 40th Birthday to General Tagge' | ./kafka-produce.sh --topic empire-announce"`
		conOutpostAnnoune = `-c "./kafka-consume.sh --topic empire-announce --from-beginning --max-messages 1"`
		prodHqDeathStar   = `-c "echo 'deathstar reactor design v3' | ./kafka-produce.sh --topic deathstar-plans"`
		conOutDeathStar   = `-c "./kafka-consume.sh --topic deathstar-plans --from-beginning --max-messages 1"`
		prodBackAnnounce  = `-c "echo 'Happy 40th Birthday to General Tagge' | ./kafka-produce.sh --topic empire-announce"`
		prodOutAnnounce   = `-c "echo 'Vader Booed at Empire Karaoke Party' | ./kafka-produce.sh --topic empire-announce"`
	)

	BeforeAll(func() {
		logger = log.WithFields(logrus.Fields{"testName": "K8sValidatedKafkaPolicyTest"})
		kubectl = helpers.CreateKubectl(helpers.K8s1VMName(), logger)

		kubectl.Apply(helpers.ManifestGet("cilium_ds.yaml"))
		status, err := kubectl.WaitforPods(helpers.KubeSystemNamespace, "-l k8s-app=cilium", 300)
		Expect(status).Should(BeTrue(), "Cilium is not ready after timeout")
		Expect(err).Should(BeNil(), "Cilium is not ready after timeout")

		err = kubectl.WaitKubeDNS()
		Expect(err).Should(BeNil(), "DNS is not ready after timeout")

		kubectl.Apply(demoPath)
		_, err = kubectl.WaitforPods(helpers.DefaultNamespace, "-l zgroup=kafkaTestApp", 300)
		Expect(err).Should(BeNil(), "Kafka Pods are not ready after timeout")

		appPods = helpers.GetAppPods(apps, helpers.DefaultNamespace, kubectl, "app")

		ciliumPod, err = kubectl.GetCiliumPodOnNode(helpers.KubeSystemNamespace, helpers.K8s2)
		Expect(err).To(BeNil(), "Cannot get cilium Pod")

	})

	AfterFailed(func() {
		kubectl.CiliumReport(helpers.KubeSystemNamespace,
			"cilium service list",
			"cilium policy get",
			"cilium endpoint list")
	})

	JustBeforeEach(func() {
		microscopeErr, microscopeCancel = kubectl.MicroscopeStart()
		Expect(microscopeErr).To(BeNil(), "Microscope cannot be started")
	})

	JustAfterEach(func() {
		kubectl.ValidateNoErrorsOnLogs(CurrentGinkgoTestDescription().Duration)
		Expect(microscopeCancel()).To(BeNil(), "cannot stop microscope")
	})

	AfterEach(func() {
		// On aftereach don't make assertions to delete all.
		_ = kubectl.Delete(demoPath)
		_ = kubectl.Delete(l7Policy)

		err := kubectl.WaitCleanAllTerminatingPods()
		Expect(err).To(BeNil(), "Terminating containers are not deleted after timeout")

	})

	It("KafkaPolicies", func() {

		By("Testing basic Kafka Produce and Consume")
		// We need to produce first, since consumer script waits for
		// some messages to be already there by the producer.

		err := kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[empireHqApp], fmt.Sprintf(prodHqAnnounce))
		Expect(err).Should(BeNil(), "Failed to produce to empire-hq on topic empire-announce")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(conOutpostAnnoune))
		Expect(err).Should(BeNil(), "Failed to consume from outpost on topic empire-announce")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[empireHqApp], fmt.Sprintf(prodHqDeathStar))
		Expect(err).Should(BeNil(), "Failed to produce to empire-hq on topic deathstar-plans")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(conOutDeathStar))
		Expect(err).Should(BeNil(), "Failed to consume from outpost on topic deathstar-plans")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[backupApp], fmt.Sprintf(prodBackAnnounce))
		Expect(err).Should(BeNil(), "Failed to produce to backup on topic empire-announce")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(prodOutAnnounce))
		Expect(err).Should(BeNil(), "Failed to produce to outpost on topic empire-announce")

		By(fmt.Sprintf("Waiting for CEP to exist for %s", appPods[kafkaApp]))
		err = kubectl.WaitForCEPToExist(appPods[kafkaApp], helpers.DefaultNamespace)
		Expect(err).To(BeNil(), "CEP did not get created for %s", appPods[kafkaApp])

		By("Getting policy revision number for each endpoint")
		cep := kubectl.CepGet(helpers.DefaultNamespace, appPods[kafkaApp])
		Expect(cep).ToNot(BeNil(), "cannot get cep for app %q and pod %s", kafkaApp, appPods[kafkaApp])
		kafkaRevBeforeUpdate := cep.Status.Policy.Realized.PolicyRevision

		By("Apply L7 kafka policy and wait")

		_, err = kubectl.CiliumPolicyAction(
			helpers.KubeSystemNamespace, l7Policy,
			helpers.KubectlApply, helpers.HelperTimeout)
		Expect(err).To(BeNil(), "L7 policy cannot be imported correctly")

		By("validate that the pods have the correct policy")

		err = kubectl.WaitCEPRevisionIncrease(appPods[kafkaApp], helpers.DefaultNamespace, kafkaRevBeforeUpdate)

		desiredPolicyStatus := map[string]models.EndpointPolicyEnabled{
			backupApp:   models.EndpointPolicyEnabledNone,
			empireHqApp: models.EndpointPolicyEnabledNone,
			kafkaApp:    models.EndpointPolicyEnabledIngress,
			outpostApp:  models.EndpointPolicyEnabledNone,
			zookApp:     models.EndpointPolicyEnabledNone,
		}

		for app, policy := range desiredPolicyStatus {
			cep := kubectl.CepGet(helpers.DefaultNamespace, appPods[app])
			Expect(cep).ToNot(BeNil(), "cannot get cep for app %q and pod %s", app, appPods[app])
			Expect(cep.Status.Policy.Spec.PolicyEnabled).To(Equal(policy), "Policy for %q mismatch", app)
		}

		By("Validating Policy trace")
		trace := kubectl.CiliumExec(ciliumPod, fmt.Sprintf(
			"cilium policy trace --src-k8s-pod default:%s --dst-k8s-pod default:%s --dport 9092",
			appPods[empireHqApp], appPods[kafkaApp]))
		trace.ExpectSuccess(trace.CombineOutput().String())
		trace.ExpectContains("Final verdict: ALLOWED")

		trace = kubectl.CiliumExec(ciliumPod, fmt.Sprintf(
			"cilium policy trace --src-k8s-pod default:%s --dst-k8s-pod default:%s --dport 9092",
			appPods[backupApp], appPods[kafkaApp]))
		trace.ExpectSuccess(trace.CombineOutput().String())
		trace.ExpectContains("Final verdict: ALLOWED")

		trace = kubectl.CiliumExec(ciliumPod, fmt.Sprintf(
			"cilium policy trace --src-k8s-pod default:%s --dst-k8s-pod default:%s --dport 80",
			appPods[empireHqApp], appPods[kafkaApp]))
		trace.ExpectSuccess(trace.CombineOutput().String())
		trace.ExpectContains("Final verdict: DENIED")

		By("Testing Kafka L7 policy enforcement status")
		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[empireHqApp], fmt.Sprintf(prodHqAnnounce))
		Expect(err).Should(BeNil(), "Failed to produce to empire-hq on topic empire-announce")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(conOutpostAnnoune))
		Expect(err).Should(BeNil(), "Failed to consume from outpost on topic empire-announce")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[empireHqApp], fmt.Sprintf(prodHqDeathStar))
		Expect(err).Should(BeNil(), "Failed to produce from empire-hq on topic deathstar-plans")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(conOutpostAnnoune))
		Expect(err).Should(BeNil(), "Failed to consume from outpost on topic empire-announce")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[backupApp], fmt.Sprintf(prodBackAnnounce))
		Expect(err).Should(HaveOccurred(), " Produce to backup on topic empire-announce should have been denied")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(conOutDeathStar))
		Expect(err).Should(HaveOccurred(), " Consume from outpost on topic deathstar-plans should have been denied")

		err = kubectl.ExecKafkaPodCmd(
			helpers.DefaultNamespace, appPods[outpostApp], fmt.Sprintf(prodOutAnnounce))
		Expect(err).Should(HaveOccurred(), "Produce to outpost on topic empire-announce should have been denied")
	})
})
<|endoftext|>


<commit_before>//  Copyright 2017 Walter Schulze
//
//  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 test

import (
	"testing"
)

func TestUniqueInt64s(t *testing.T) {
	input := []int64{1, 2, 3, 2, 1}
	want := []int64{1, 2, 3}
	got := deriveUniqueInt64s(input)
	if len(got) != len(want) {
		t.Fatalf("got too long: %#v", got)
	}
	for _, g := range got {
		if !deriveContainsInt64s(want, g) {
			t.Fatalf("did not get %d", g)
		}
	}
}

func TestUniqueStructs(t *testing.T) {
	var b *BuiltInTypes
	b1 := random(b).(*BuiltInTypes)
	b2 := random(b).(*BuiltInTypes)
	b3 := random(b).(*BuiltInTypes)
	input := []*BuiltInTypes{b1, b2, b3, b2, b1}
	want := []*BuiltInTypes{b1, b2, b3}
	got := deriveUniqueStructs(input)
	if len(got) != len(want) {
		t.Fatalf("got too long: %#v", got)
	}
	for _, g := range got {
		if !deriveContainsStruct(want, g) {
			t.Fatalf("did not get %#v", g)
		}
	}
}

func TestUniqueStructsWithoutPointers(t *testing.T) {
	var b *PtrToBuiltInTypes
	b1 := random(b).(*PtrToBuiltInTypes)
	b2 := random(b).(*PtrToBuiltInTypes)
	b3 := random(b).(*PtrToBuiltInTypes)
	input := []PtrToBuiltInTypes{*b1, *b2, *b3, *b2, *b1}
	want := []PtrToBuiltInTypes{*b1, *b2, *b3}
	got := deriveUniqueStructsPtrs(input)
	if len(got) != len(want) {
		t.Fatalf("got too long: %#v", got)
	}
	for _, g := range got {
		if !deriveContainsStructPtr(want, g) {
			t.Fatalf("did not get %#v", g)
		}
	}
}
<commit_msg>add missing nil checking in test file<commit_after>//  Copyright 2017 Walter Schulze
//
//  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 test

import (
	"testing"
)

func TestUniqueInt64s(t *testing.T) {
	input := []int64{1, 2, 3, 2, 1}
	want := []int64{1, 2, 3}
	got := deriveUniqueInt64s(input)
	if len(got) != len(want) {
		t.Fatalf("got too long: %#v", got)
	}
	for _, g := range got {
		if !deriveContainsInt64s(want, g) {
			t.Fatalf("did not get %d", g)
		}
	}
}

func TestUniqueStructs(t *testing.T) {
	randomWithoutNil := func() *BuiltInTypes {
		var b *BuiltInTypes
		for b == nil {
			b = random(b).(*BuiltInTypes)
		}
		return b
	}
	b1 := randomWithoutNil()
	b2 := randomWithoutNil()
	b3 := randomWithoutNil()
	input := []*BuiltInTypes{b1, b2, b3, b2, b1, nil, nil}
	want := []*BuiltInTypes{b1, b2, b3, nil}
	got := deriveUniqueStructs(input)
	if len(got) != len(want) {
		t.Fatalf("got too long: %#v", got)
	}
	for _, g := range got {
		if !deriveContainsStruct(want, g) {
			t.Fatalf("did not get %#v", g)
		}
	}
}

func TestUniqueStructsWithoutPointers(t *testing.T) {
	randomWithoutNil := func() PtrToBuiltInTypes {
		var b *PtrToBuiltInTypes
		for b == nil {
			b = random(b).(*PtrToBuiltInTypes)
		}
		return *b
	}
	b1 := randomWithoutNil()
	b2 := randomWithoutNil()
	b3 := randomWithoutNil()
	input := []PtrToBuiltInTypes{b1, b2, b3, b2, b1}
	want := []PtrToBuiltInTypes{b1, b2, b3}
	got := deriveUniqueStructsPtrs(input)
	if len(got) != len(want) {
		t.Fatalf("got too long: %#v", got)
	}
	for _, g := range got {
		if !deriveContainsStructPtr(want, g) {
			t.Fatalf("did not get %#v", g)
		}
	}
}
<|endoftext|>