<commit_before>// Copyright (c) 2020 Somia Reality Oy. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"encoding/binary"
	"errors"
	"flag"
	"image"
	_ "image/gif"
	"image/jpeg"
	_ "image/png"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"sync"
	"sync/atomic"
	"syscall"

	"github.com/disintegration/imaging"
	jpegstructure "github.com/dsoprea/go-jpeg-image-structure"
	"github.com/ninchat/thumq"
	_ "golang.org/x/image/bmp"
	_ "golang.org/x/image/tiff"
	"google.golang.org/protobuf/proto"
)

const exifTagIDOrientation = 0x112

type orientation uint16

const (
	_                  orientation = iota
	orientationTopLeft             // Upper left.
	orientationTopRight
	orientationBottomRight // Lower right.
	orientationBottomLeft
	orientationLeftTop
	orientationRightTop // Upper right.
	orientationRightBottom
	orientationLeftBottom // Lower left.
)

type subImager interface {
	SubImage(image.Rectangle) image.Image
}

func main() {
	log.SetFlags(0)

	returned := false

	defer func() {
		if !returned {
			x := recover()
			if err, ok := x.(error); ok {
				log.Fatal(err)
			} else {
				panic(x)
			}
		}
	}()

	panickyMain()
	returned = true
}

func panickyMain() {
	flag.Parse()
	if flag.NArg() != 1 {
		panic(errors.New("need exactly one argument: listen socket filename"))
	}
	address := flag.Arg(0)

	signals := make(chan os.Signal)
	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
	signal.Ignore(syscall.SIGPIPE)

	listener, err := net.Listen("unix", address)
	check(err)
	defer listener.Close()

	var shutdown uint32

	go func() {
		<-signals
		atomic.StoreUint32(&shutdown, 1)
		listener.Close()
	}()

	var group sync.WaitGroup
	defer group.Wait()

	for {
		conn, err := listener.Accept()
		if err != nil {
			if atomic.LoadUint32(&shutdown) == 1 {
				return
			}
			panic(err)
		}

		group.Add(1)
		go func() {
			defer group.Done()
			handle(conn)
		}()
	}
}

func handle(conn net.Conn) {
	defer func() {
		if x := recover(); x != nil {
			if err, ok := x.(error); ok {
				log.Print(err)
			} else {
				panic(x)
			}
		}
	}()

	defer conn.Close()

	req := new(thumq.Request)
	check(proto.Unmarshal(receive(conn), req))

	res, data := process(req, receive(conn))

	head, err := proto.Marshal(res)
	check(err)

	send(conn, head)
	send(conn, data)
}

func receive(conn net.Conn) []byte {
	size := make([]byte, 4)

	_, err := io.ReadFull(conn, size)
	check(err)

	buf := make([]byte, binary.LittleEndian.Uint32(size))

	_, err = io.ReadFull(conn, buf)
	check(err)

	return buf
}

func send(conn net.Conn, buf []byte) {
	size := make([]byte, 4)
	binary.LittleEndian.PutUint32(size, uint32(len(buf)))

	_, err := conn.Write(size)
	check(err)

	_, err = conn.Write(buf)
	check(err)
}

func process(req *thumq.Request, data []byte) (*thumq.Response, []byte) {
	res := new(thumq.Response)

	m, format, err := image.Decode(bytes.NewReader(data))
	if err != nil {
		res.SourceType = detectMIMEType(data)
		return res, nil
	}

	var ori orientation

	switch format {
	case "jpeg":
		res.SourceType = "image/jpeg"
		ori = parseJPEGOrientation(data)

	case "bmp", "gif", "png", "tiff":
		res.SourceType = "image/" + format

	default: // Imports may have registerd unexpected handlers.
		log.Print("decoded image in unsupported format:", format)
		res.SourceType = detectMIMEType(data)
		return res, nil
	}

	m = convert(m, req, res, ori)

	buf := new(bytes.Buffer)
	check(jpeg.Encode(buf, m, nil))
	return res, buf.Bytes()
}

func parseJPEGOrientation(data []byte) (ori orientation) {
	media, _ := jpegstructure.NewJpegMediaParser().ParseBytes(data)
	if media == nil {
		return
	}

	_, _, tags, _ := media.(*jpegstructure.SegmentList).DumpExif()

	for _, tag := range tags {
		if tag.TagId == exifTagIDOrientation {
			if array, ok := tag.Value.([]uint16); ok && len(array) != 0 {
				ori = orientation(array[0])
			}
			break
		}
	}

	return
}

func convert(m image.Image, req *thumq.Request, res *thumq.Response, ori orientation) image.Image {
	m = fixOrientation(m, ori)

	if req.Crop == thumq.Request_TOP_SQUARE {
		m = cropTopSquare(m)
	}

	m = scale(m, int(req.Scale))

	size := m.Bounds()
	res.NailWidth = uint32(size.Dx())
	res.NailHeight = uint32(size.Dy())
	return m
}

func fixOrientation(m image.Image, ori orientation) image.Image {
	switch ori {
	case orientationTopLeft:

	case orientationTopRight:
		m = imaging.FlipH(m)

	case orientationBottomRight:
		m = imaging.Rotate180(m)

	case orientationBottomLeft:
		m = imaging.FlipV(m)

	case orientationLeftTop:
		m = imaging.FlipV(m)
		m = imaging.Rotate270(m)

	case orientationRightTop:
		m = imaging.Rotate270(m)

	case orientationRightBottom:
		m = imaging.FlipV(m)
		m = imaging.Rotate90(m)

	case orientationLeftBottom:
		m = imaging.Rotate90(m)
	}

	return m
}

func cropTopSquare(m image.Image) image.Image {
	var rect image.Rectangle

	size := m.Bounds()
	width := size.Dx()
	height := size.Dy()

	if width < height {
		rect = image.Rect(0, 0, width, width)
	} else {
		x := (width - height) / 2
		rect = image.Rect(x, 0, x+height, height)
	}

	return m.(subImager).SubImage(rect)
}

func scale(m image.Image, scale int) image.Image {
	size := m.Bounds()
	width := size.Dx()
	height := size.Dy()

	if width > scale || height > scale {
		if width < height {
			width = int(int64(scale) * int64(width) / int64(height))
			height = scale
		} else {
			height = int(int64(scale) * int64(height) / int64(width))
			width = scale
		}

		m = imaging.Resize(m, width, height, imaging.Lanczos)
	}

	return m
}

func detectMIMEType(data []byte) string {
	switch mime := http.DetectContentType(data); mime {
	case "application/octet-stream": // Unknown, really.
		return ""

	default:
		return mime
	}
}

func check(err error) {
	if err != nil {
		panic(err)
	}
}
<commit_msg>cmd: use buffered signal channel<commit_after>// Copyright (c) 2020 Somia Reality Oy. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"encoding/binary"
	"errors"
	"flag"
	"image"
	_ "image/gif"
	"image/jpeg"
	_ "image/png"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"sync"
	"sync/atomic"
	"syscall"

	"github.com/disintegration/imaging"
	jpegstructure "github.com/dsoprea/go-jpeg-image-structure"
	"github.com/ninchat/thumq"
	_ "golang.org/x/image/bmp"
	_ "golang.org/x/image/tiff"
	"google.golang.org/protobuf/proto"
)

const exifTagIDOrientation = 0x112

type orientation uint16

const (
	_                  orientation = iota
	orientationTopLeft             // Upper left.
	orientationTopRight
	orientationBottomRight // Lower right.
	orientationBottomLeft
	orientationLeftTop
	orientationRightTop // Upper right.
	orientationRightBottom
	orientationLeftBottom // Lower left.
)

type subImager interface {
	SubImage(image.Rectangle) image.Image
}

func main() {
	log.SetFlags(0)

	returned := false

	defer func() {
		if !returned {
			x := recover()
			if err, ok := x.(error); ok {
				log.Fatal(err)
			} else {
				panic(x)
			}
		}
	}()

	panickyMain()
	returned = true
}

func panickyMain() {
	flag.Parse()
	if flag.NArg() != 1 {
		panic(errors.New("need exactly one argument: listen socket filename"))
	}
	address := flag.Arg(0)

	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
	signal.Ignore(syscall.SIGPIPE)

	listener, err := net.Listen("unix", address)
	check(err)
	defer listener.Close()

	var shutdown uint32

	go func() {
		<-signals
		atomic.StoreUint32(&shutdown, 1)
		listener.Close()
	}()

	var group sync.WaitGroup
	defer group.Wait()

	for {
		conn, err := listener.Accept()
		if err != nil {
			if atomic.LoadUint32(&shutdown) == 1 {
				return
			}
			panic(err)
		}

		group.Add(1)
		go func() {
			defer group.Done()
			handle(conn)
		}()
	}
}

func handle(conn net.Conn) {
	defer func() {
		if x := recover(); x != nil {
			if err, ok := x.(error); ok {
				log.Print(err)
			} else {
				panic(x)
			}
		}
	}()

	defer conn.Close()

	req := new(thumq.Request)
	check(proto.Unmarshal(receive(conn), req))

	res, data := process(req, receive(conn))

	head, err := proto.Marshal(res)
	check(err)

	send(conn, head)
	send(conn, data)
}

func receive(conn net.Conn) []byte {
	size := make([]byte, 4)

	_, err := io.ReadFull(conn, size)
	check(err)

	buf := make([]byte, binary.LittleEndian.Uint32(size))

	_, err = io.ReadFull(conn, buf)
	check(err)

	return buf
}

func send(conn net.Conn, buf []byte) {
	size := make([]byte, 4)
	binary.LittleEndian.PutUint32(size, uint32(len(buf)))

	_, err := conn.Write(size)
	check(err)

	_, err = conn.Write(buf)
	check(err)
}

func process(req *thumq.Request, data []byte) (*thumq.Response, []byte) {
	res := new(thumq.Response)

	m, format, err := image.Decode(bytes.NewReader(data))
	if err != nil {
		res.SourceType = detectMIMEType(data)
		return res, nil
	}

	var ori orientation

	switch format {
	case "jpeg":
		res.SourceType = "image/jpeg"
		ori = parseJPEGOrientation(data)

	case "bmp", "gif", "png", "tiff":
		res.SourceType = "image/" + format

	default: // Imports may have registerd unexpected handlers.
		log.Print("decoded image in unsupported format:", format)
		res.SourceType = detectMIMEType(data)
		return res, nil
	}

	m = convert(m, req, res, ori)

	buf := new(bytes.Buffer)
	check(jpeg.Encode(buf, m, nil))
	return res, buf.Bytes()
}

func parseJPEGOrientation(data []byte) (ori orientation) {
	media, _ := jpegstructure.NewJpegMediaParser().ParseBytes(data)
	if media == nil {
		return
	}

	_, _, tags, _ := media.(*jpegstructure.SegmentList).DumpExif()

	for _, tag := range tags {
		if tag.TagId == exifTagIDOrientation {
			if array, ok := tag.Value.([]uint16); ok && len(array) != 0 {
				ori = orientation(array[0])
			}
			break
		}
	}

	return
}

func convert(m image.Image, req *thumq.Request, res *thumq.Response, ori orientation) image.Image {
	m = fixOrientation(m, ori)

	if req.Crop == thumq.Request_TOP_SQUARE {
		m = cropTopSquare(m)
	}

	m = scale(m, int(req.Scale))

	size := m.Bounds()
	res.NailWidth = uint32(size.Dx())
	res.NailHeight = uint32(size.Dy())
	return m
}

func fixOrientation(m image.Image, ori orientation) image.Image {
	switch ori {
	case orientationTopLeft:

	case orientationTopRight:
		m = imaging.FlipH(m)

	case orientationBottomRight:
		m = imaging.Rotate180(m)

	case orientationBottomLeft:
		m = imaging.FlipV(m)

	case orientationLeftTop:
		m = imaging.FlipV(m)
		m = imaging.Rotate270(m)

	case orientationRightTop:
		m = imaging.Rotate270(m)

	case orientationRightBottom:
		m = imaging.FlipV(m)
		m = imaging.Rotate90(m)

	case orientationLeftBottom:
		m = imaging.Rotate90(m)
	}

	return m
}

func cropTopSquare(m image.Image) image.Image {
	var rect image.Rectangle

	size := m.Bounds()
	width := size.Dx()
	height := size.Dy()

	if width < height {
		rect = image.Rect(0, 0, width, width)
	} else {
		x := (width - height) / 2
		rect = image.Rect(x, 0, x+height, height)
	}

	return m.(subImager).SubImage(rect)
}

func scale(m image.Image, scale int) image.Image {
	size := m.Bounds()
	width := size.Dx()
	height := size.Dy()

	if width > scale || height > scale {
		if width < height {
			width = int(int64(scale) * int64(width) / int64(height))
			height = scale
		} else {
			height = int(int64(scale) * int64(height) / int64(width))
			width = scale
		}

		m = imaging.Resize(m, width, height, imaging.Lanczos)
	}

	return m
}

func detectMIMEType(data []byte) string {
	switch mime := http.DetectContentType(data); mime {
	case "application/octet-stream": // Unknown, really.
		return ""

	default:
		return mime
	}
}

func check(err error) {
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package daemon

import (
	"os"
	"os/exec"
	"os/user"
)

// Service constants
const (
	rootPrivileges = "You must have root user privileges. Possibly using 'sudo' command should help"
	success        = "\t\t\t\t\t[  \033[32mOK\033[0m  ]" // Show colored "OK"
	failed         = "\t\t\t\t\t[\033[31mFAILED\033[0m]" // Show colored "FAILED"
)

// Lookup path for executable file
func executablePath(name string) (string, error) {
	if path, err := exec.LookPath(name); err == nil {
		_, err := os.Stat(path)
		if os.IsNotExist(err) {
			return execPath()
		}
		return path, nil
	}
	return execPath()
}

// Check root rights to use system service
func checkPrivileges() bool {

	if user, err := user.Current(); err == nil && user.Gid == "0" {
		return true
	}
	return false
}
<commit_msg>bugfix: forget to delete helper.go<commit_after><|endoftext|>


<commit_before>package winrmcp

import (
	"errors"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"time"

	"github.com/dylanmei/iso8601"
	"github.com/masterzen/winrm/winrm"
)

type Winrmcp struct {
	client *winrm.Client
	config *Config
}

type Config struct {
	Auth                  Auth
	Https                 bool
	Insecure              bool
	CACertBytes           []byte
	OperationTimeout      time.Duration
	MaxOperationsPerShell int
}

type Auth struct {
	User     string
	Password string
}

func New(addr string, config *Config) (*Winrmcp, error) {
	endpoint, err := parseEndpoint(addr, config.Https, config.Insecure, config.CACertBytes)
	if err != nil {
		return nil, err
	}
	if config == nil {
		config = &Config{}
	}

	params := winrm.DefaultParameters()
	if config.OperationTimeout.Seconds() > 0 {
		params.Timeout = iso8601.FormatDuration(config.OperationTimeout)
	}
	client, err := winrm.NewClientWithParameters(
		endpoint, config.Auth.User, config.Auth.Password, params)
	return &Winrmcp{client, config}, err
}

func (fs *Winrmcp) Copy(fromPath, toPath string) error {
	f, err := os.Open(fromPath)
	if err != nil {
		return errors.New(fmt.Sprintf("Couldn't read file %s: %v", fromPath, err))
	}

	defer f.Close()
	fi, err := f.Stat()
	if err != nil {
		return errors.New(fmt.Sprintf("Couldn't stat file %s: %v", fromPath, err))
	}

	if !fi.IsDir() {
		return fs.Write(toPath, f)
	} else {
		fw := fileWalker{
			client:  fs.client,
			config:  fs.config,
			toDir:   toPath,
			fromDir: fromPath,
		}
		return filepath.Walk(fromPath, fw.copyFile)
	}
}

func (fs *Winrmcp) Write(toPath string, src io.Reader) error {
	return doCopy(fs.client, fs.config, src, winPath(toPath))
}

func (fs *Winrmcp) List(remotePath string) ([]FileItem, error) {
	return fetchList(fs.client, winPath(remotePath))
}

type fileWalker struct {
	client  *winrm.Client
	config  *Config
	toDir   string
	fromDir string
}

func (fw *fileWalker) copyFile(fromPath string, fi os.FileInfo, err error) error {
	if err != nil {
		return err
	}

	if !shouldUploadFile(fi) {
		return nil
	}

	hostPath, _ := filepath.Abs(fromPath)
	fromDir, _ := filepath.Abs(fw.fromDir)
	relPath, _ := filepath.Rel(fromDir, hostPath)
	toPath := filepath.Join(fw.toDir, relPath)

	f, err := os.Open(hostPath)
	if err != nil {
		return errors.New(fmt.Sprintf("Couldn't read file %s: %v", fromPath, err))
	}

	return doCopy(fw.client, fw.config, f, winPath(toPath))
}

func shouldUploadFile(fi os.FileInfo) bool {
	// Ignore dir entries and OS X special hidden file
	return !fi.IsDir() && ".DS_Store" != fi.Name()
}
<commit_msg>Udpated winrmcp dep<commit_after>package winrmcp

import (
	"errors"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"github.com/dylanmei/iso8601"
	"github.com/masterzen/winrm/winrm"
)

type Winrmcp struct {
	client *winrm.Client
	config *Config
}

type Config struct {
	Auth                  Auth
	Https                 bool
	Insecure              bool
	CACertBytes           []byte
	OperationTimeout      time.Duration
	MaxOperationsPerShell int
	TransportDecorator    func(*http.Transport) http.RoundTripper
}

type Auth struct {
	User     string
	Password string
}

func New(addr string, config *Config) (*Winrmcp, error) {
	endpoint, err := parseEndpoint(addr, config.Https, config.Insecure, config.CACertBytes)
	if err != nil {
		return nil, err
	}
	if config == nil {
		config = &Config{}
	}

	params := winrm.DefaultParameters()
	if config.TransportDecorator != nil {
		params.TransportDecorator = config.TransportDecorator
	}

	if config.OperationTimeout.Seconds() > 0 {
		params.Timeout = iso8601.FormatDuration(config.OperationTimeout)
	}
	client, err := winrm.NewClientWithParameters(
		endpoint, config.Auth.User, config.Auth.Password, params)
	return &Winrmcp{client, config}, err
}

func (fs *Winrmcp) Copy(fromPath, toPath string) error {
	f, err := os.Open(fromPath)
	if err != nil {
		return errors.New(fmt.Sprintf("Couldn't read file %s: %v", fromPath, err))
	}

	defer f.Close()
	fi, err := f.Stat()
	if err != nil {
		return errors.New(fmt.Sprintf("Couldn't stat file %s: %v", fromPath, err))
	}

	if !fi.IsDir() {
		return fs.Write(toPath, f)
	} else {
		fw := fileWalker{
			client:  fs.client,
			config:  fs.config,
			toDir:   toPath,
			fromDir: fromPath,
		}
		return filepath.Walk(fromPath, fw.copyFile)
	}
}

func (fs *Winrmcp) Write(toPath string, src io.Reader) error {
	return doCopy(fs.client, fs.config, src, winPath(toPath))
}

func (fs *Winrmcp) List(remotePath string) ([]FileItem, error) {
	return fetchList(fs.client, winPath(remotePath))
}

type fileWalker struct {
	client  *winrm.Client
	config  *Config
	toDir   string
	fromDir string
}

func (fw *fileWalker) copyFile(fromPath string, fi os.FileInfo, err error) error {
	if err != nil {
		return err
	}

	if !shouldUploadFile(fi) {
		return nil
	}

	hostPath, _ := filepath.Abs(fromPath)
	fromDir, _ := filepath.Abs(fw.fromDir)
	relPath, _ := filepath.Rel(fromDir, hostPath)
	toPath := filepath.Join(fw.toDir, relPath)

	f, err := os.Open(hostPath)
	if err != nil {
		return errors.New(fmt.Sprintf("Couldn't read file %s: %v", fromPath, err))
	}

	return doCopy(fw.client, fw.config, f, winPath(toPath))
}

func shouldUploadFile(fi os.FileInfo) bool {
	// Ignore dir entries and OS X special hidden file
	return !fi.IsDir() && ".DS_Store" != fi.Name()
}
<|endoftext|>


<commit_before>package junos

// Establishing a session
func Example() {
	jnpr, err := junos.NewSession(host, user, password)
	if err != nil {
		log.Fatal(err)
	}
	defer jnpr.Close()
}

// To View the entire configuration, use the keyword "full" for the first
// argument. If anything else outside of "full" is specified, it will return
// the configuration of the specified top-level stanza only. So "security" would return everything
// under the "security" stanza.
func Example_viewConfiguration() {
	// Output format can be "text" or "xml"
	config, err := jnpr.GetConfig("full", "text")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(config)
}

// Comparing and Rolling Back Configurations
func Example_rollbackConfigurations() {
	// If you want to view the difference between the current configuration and a rollback
	// one, then you can use the ConfigDiff() function to specify a previous config:
	diff, err := jnpr.ConfigDiff(3)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(diff)

	// You can rollback to a previous state, or the rescue configuration by using
	// the RollbackConfig() function:
	err := jnpr.RollbackConfig(3)
	if err != nil {
		fmt.Println(err)
	}

	// Create a rescue config from the active configuration.
	jnpr.Rescue("save")

	// You can also delete a rescue config.
	jnpr.Rescue("delete")

	// Rollback to the "rescue" configuration.
	err := jnpr.RollbackConfig("rescue")
	if err != nil {
		fmt.Println(err)
	}
}

// Device Configuration
func Example_configuringDevices() {
	// When configuring a device, it is good practice to lock the configuration database,
	// load the config, commit the configuration, and then unlock the configuration database.
	// You can do this with the following functions: Lock(), Commit(), Unlock()

	// Multiple ways to commit a configuration

	// Commit the configuration as normal
	Commit()

	// Check the configuration for any syntax errors (NOTE: you must still issue a Commit() afterwards)
	CommitCheck()

	// Commit at a later time, i.e. 4:30 PM
	CommitAt("16:30:00")

	// Rollback configuration if a Commit() is not issued within the given <minutes>.
	CommitConfirm(15)

	// You can configure the Junos device by uploading a local file, or pulling from an
	// FTP/HTTP server. The LoadConfig() function takes three arguments:

	// filename or URL, format, and a boolean (true/false) "commit-on-load"

	// If you specify a URL, it must be in the following format:

	// ftp://<username>:<password>@hostname/pathname/file-name
	// http://<username>:<password>@hostname/pathname/file-name

	// Note: The default value for the FTP path variable is the user’s home directory. Thus,
	// by default the file path to the configuration file is relative to the user directory.
	// To specify an absolute path when using FTP, start the path with the characters %2F;
	// for example: ftp://username:password@hostname/%2Fpath/filename.

	// The format of the commands within the file must be one of the following types:

	// set
	// system name-server 1.1.1.1

	// text
	// system {
	//     name-server 1.1.1.1;
	// }

	// xml
	// <system>
	//     <name-server>
	//         <name>1.1.1.1</name>
	//     </name-server>
	// </system>

	// If the third option is "true" then after the configuration is loaded, a commit
	// will be issued. If set to "false," you will have to commit the configuration
	// using one of the Commit() functions.
	jnpr.Lock()
	err := jnpr.LoadConfig("path-to-file.txt", "set", true)
	if err != nil {
		fmt.Println(err)
	}
	jnpr.Unlock()
}
<commit_msg>Added more examples<commit_after>package junos

// Establishing a session
func Example() {
	jnpr, err := junos.NewSession(host, user, password)
	if err != nil {
		log.Fatal(err)
	}
	defer jnpr.Close()
}

// To View the entire configuration, use the keyword "full" for the first
// argument. If anything else outside of "full" is specified, it will return
// the configuration of the specified top-level stanza only. So "security" would return everything
// under the "security" stanza.
func Example_viewConfiguration() {
	// Output format can be "text" or "xml"
	config, err := jnpr.GetConfig("full", "text")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(config)
}

// Comparing and Rolling Back Configurations
func Example_rollbackConfigurations() {
	// If you want to view the difference between the current configuration and a rollback
	// one, then you can use the ConfigDiff() function to specify a previous config:
	diff, err := jnpr.ConfigDiff(3)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(diff)

	// You can rollback to a previous state, or the rescue configuration by using
	// the RollbackConfig() function:
	err := jnpr.RollbackConfig(3)
	if err != nil {
		fmt.Println(err)
	}

	// Create a rescue config from the active configuration.
	jnpr.Rescue("save")

	// You can also delete a rescue config.
	jnpr.Rescue("delete")

	// Rollback to the "rescue" configuration.
	err := jnpr.RollbackConfig("rescue")
	if err != nil {
		fmt.Println(err)
	}
}

// Device Configuration
func Example_configuringDevices() {
	// Use the LoadConfig() function to load the configuration from a file.

	// When configuring a device, it is good practice to lock the configuration database,
	// load the config, commit the configuration, and then unlock the configuration database.
	// You can do this with the following functions: Lock(), Commit(), Unlock()

	// Multiple ways to commit a configuration

	// Commit the configuration as normal
	Commit()

	// Check the configuration for any syntax errors (NOTE: you must still issue a Commit() afterwards)
	CommitCheck()

	// Commit at a later time, i.e. 4:30 PM
	CommitAt("16:30:00")

	// Rollback configuration if a Commit() is not issued within the given <minutes>.
	CommitConfirm(15)

	// You can configure the Junos device by uploading a local file, or pulling from an
	// FTP/HTTP server. The LoadConfig() function takes three arguments:

	// filename or URL, format, and a boolean (true/false) "commit-on-load"

	// If you specify a URL, it must be in the following format:

	// ftp://<username>:<password>@hostname/pathname/file-name
	// http://<username>:<password>@hostname/pathname/file-name

	// Note: The default value for the FTP path variable is the user’s home directory. Thus,
	// by default the file path to the configuration file is relative to the user directory.
	// To specify an absolute path when using FTP, start the path with the characters %2F;
	// for example: ftp://username:password@hostname/%2Fpath/filename.

	// The format of the commands within the file must be one of the following types:

	// set
	// system name-server 1.1.1.1

	// text
	// system {
	//     name-server 1.1.1.1;
	// }

	// xml
	// <system>
	//     <name-server>
	//         <name>1.1.1.1</name>
	//     </name-server>
	// </system>

	// If the third option is "true" then after the configuration is loaded, a commit
	// will be issued. If set to "false," you will have to commit the configuration
	// using one of the Commit() functions.
	jnpr.Lock()
	err := jnpr.LoadConfig("path-to-file.txt", "set", true)
	if err != nil {
		fmt.Println(err)
	}
	jnpr.Unlock()
}
<|endoftext|>


<commit_before>// Copyright 2017 Pilosa Corp.
//
// 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.
//
//go:generate statik -src=../webui -dest=..
//
// Package statik contains static assets for the Web UI. `go generate` or
// `make generate-statik` will produce statik.go, which is ignored by git.

package statik

import (
	"net/http"

	"github.com/pilosa/pilosa"
	"github.com/rakyll/statik/fs"
)

// Ensure nopFileSystem implements interface.
var _ pilosa.FileSystem = &FileSystem{}

// FileSystem represents a static FileSystem.
type FileSystem struct{}

// New is a statik implementation of FileSystem New method.
func (s *FileSystem) New() (http.FileSystem, error) {
	return fs.New()
}
<commit_msg>Remove empty line between godoc and package declaration<commit_after>// Copyright 2017 Pilosa Corp.
//
// 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.
//
//go:generate statik -src=../webui -dest=..
//
// Package statik contains static assets for the Web UI. `go generate` or
// `make generate-statik` will produce statik.go, which is ignored by git.
package statik

import (
	"net/http"

	"github.com/pilosa/pilosa"
	"github.com/rakyll/statik/fs"
)

// Ensure nopFileSystem implements interface.
var _ pilosa.FileSystem = &FileSystem{}

// FileSystem represents a static FileSystem.
type FileSystem struct{}

// New is a statik implementation of FileSystem New method.
func (s *FileSystem) New() (http.FileSystem, error) {
	return fs.New()
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Google LLC

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

    https://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.
*/

// The unused_deps binary prints out buildozer commands for removing
// unused Java dependencies from java_library Bazel rules.
package main

import (
	"bufio"
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"strings"

	"github.com/bazelbuild/buildtools/build"
	"github.com/bazelbuild/buildtools/config"
	depspb "github.com/bazelbuild/buildtools/deps_proto"
	"github.com/bazelbuild/buildtools/edit"
	eapb "github.com/bazelbuild/buildtools/extra_actions_base_proto"
	"github.com/bazelbuild/buildtools/labels"
	"github.com/golang/protobuf/proto"
)

var (
	buildVersion     = "redacted"
	buildScmRevision = "redacted"

	version             = flag.Bool("version", false, "Print the version of unused_deps")
	buildTool           = flag.String("build_tool", config.DefaultBuildTool, config.BuildToolHelp)
	extraActionFileName = flag.String("extra_action_file", "", config.ExtraActionFileNameHelp)
	outputFileName      = flag.String("output_file", "", "used only with extra_action_file")
	buildOptions        = stringList("extra_build_flags", "Extra build flags to use when building the targets.")

	blazeFlags = []string{"--tool_tag=unused_deps", "--keep_going", "--color=yes", "--curses=yes"}

	aspect = `
# Explicitly creates a params file for a Javac action.
def _javac_params(target, ctx):
    params = []
    for action in target.actions:
        if not action.mnemonic == "Javac":
            continue
        output = ctx.actions.declare_file("%s.javac_params" % target.label.name)
        args = ctx.actions.args()
        args.add_all(action.argv)
        ctx.actions.write(
            output = output,
            content = args,
        )
        params.append(output)
    return [OutputGroupInfo(unused_deps_outputs = depset(params))]

javac_params = aspect(
    implementation = _javac_params,
)
`
)

func stringList(name, help string) func() []string {
	f := flag.String(name, "", help)
	return func() []string {
		if *f == "" {
			return nil
		}
		res := strings.Split(*f, ",")
		for i := range res {
			res[i] = strings.TrimSpace(res[i])
		}
		return res
	}
}

// getJarPath prints the path to the output jar file specified in the extra_action file at path.
func getJarPath(path string) (string, error) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return "", err
	}
	i := &eapb.ExtraActionInfo{}
	if err := proto.Unmarshal(data, i); err != nil {
		return "", err
	}
	ext, err := proto.GetExtension(i, eapb.E_JavaCompileInfo_JavaCompileInfo)
	if err != nil {
		return "", err
	}
	jci, ok := ext.(*eapb.JavaCompileInfo)
	if !ok {
		return "", errors.New("no JavaCompileInfo in " + path)
	}
	return jci.GetOutputjar(), nil
}

// writeUnusedDeps writes the labels of unused direct deps, one per line, to outputFileName.
func writeUnusedDeps(jarPath, outputFileName string) {
	depsPath := strings.Replace(jarPath, ".jar", ".jdeps", 1)
	paramsPath := jarPath + "-2.params"
	file, _ := os.Create(outputFileName)
	for dep := range unusedDeps(depsPath, directDepParams(paramsPath)) {
		file.WriteString(dep + "\n")
	}
}

func cmdWithStderr(name string, arg ...string) *exec.Cmd {
	cmd := exec.Command(name, arg...)
	cmd.Stderr = os.Stderr
	return cmd
}

// blazeInfo retrieves the blaze info value for a given key.
func blazeInfo(key string) (value string) {
	out, err := cmdWithStderr(*buildTool, "info", key).Output()
	if err != nil {
		log.Printf("'%s info %s' failed: %s", *buildTool, key, err)
	}
	return strings.TrimSpace(bytes.NewBuffer(out).String())
}

// inputFileName returns a blaze output file name from which to read input.
func inputFileName(blazeBin, pkg, ruleName, extension string) string {
	name := fmt.Sprintf("%s/%s/lib%s.%s", blazeBin, pkg, ruleName, extension) // *_library
	if _, err := os.Stat(name); err == nil {
		return name
	}
	// lazily let the caller handle it if this doesn't exist
	return fmt.Sprintf("%s/%s/%s.%s", blazeBin, pkg, ruleName, extension) // *_{binary,test}
}

// directDepParams reads the jar-2.params files, looking for a
// "--direct_dependencies" argument.  When found, the direct dependencies are
// returned as a map from jar file names to labels.
func directDepParams(blazeOutputPath string, paramsFileNames ...string) (depsByJar map[string]string) {
	depsByJar = make(map[string]string)
	errs := make([]error, 0)
	for _, paramsFileName := range paramsFileNames {
		data, err := ioutil.ReadFile(paramsFileName)
		if err != nil {
			errs = append(errs, err)
			continue
		}
		// The classpath param exceeds MaxScanTokenSize, so we scan just the
		// dependencies section.
		directDepsFlag := []byte("--direct_dependencies")
		arg := bytes.Index(data, directDepsFlag)
		if arg < 0 {
			continue
		}
		first := arg + len(directDepsFlag) + 1

		scanner := bufio.NewScanner(bytes.NewReader(data[first:]))
		for scanner.Scan() {
			jar := scanner.Text()
			if strings.HasPrefix(jar, "--") {
				break
			}
			label, err := jarManifestValue(blazeOutputPath+strings.TrimPrefix(jar, "bazel-out"), "Target-Label")
			if err != nil {
				continue
			}
			if len(label) > 2 && label[0] == '@' && label[1] == '@' {
				label = label[1:]
			}
			depsByJar[jar] = label
		}
		if err := scanner.Err(); err != nil {
			log.Printf("reading %s: %s", paramsFileName, err)
		}
	}
	if len(errs) == len(paramsFileNames) {
		for _, err := range errs {
			log.Println(err)
		}
	}
	return depsByJar
}

// unusedDeps returns a set of labels that are unused deps.
// It reads Dependencies proto messages from depsFileName (a jdeps file), which indicate deps used
// at compile time, and returns those values in the depsByJar map that aren't used at compile time.
func unusedDeps(depsFileName string, depsByJar map[string]string) (unusedDeps map[string]bool) {
	unusedDeps = make(map[string]bool)
	data, err := ioutil.ReadFile(depsFileName)
	if err != nil {
		log.Println(err)
		return unusedDeps
	}
	dependencies := &depspb.Dependencies{}
	if err := proto.Unmarshal(data, dependencies); err != nil {
		log.Println(err)
		return unusedDeps
	}
	for _, label := range depsByJar {
		unusedDeps[label] = true
	}
	for _, dependency := range dependencies.Dependency {
		if *dependency.Kind == depspb.Dependency_EXPLICIT {
			delete(unusedDeps, depsByJar[*dependency.Path])
		}
	}
	return unusedDeps
}

// parseBuildFile tries to read and parse the contents of buildFileName.
func parseBuildFile(buildFileName string) (buildFile *build.File, err error) {
	data, err := ioutil.ReadFile(buildFileName)
	if err != nil {
		return nil, err
	}
	return build.Parse(buildFileName, data)
}

// getDepsExpr tries to parse the content of buildFileName and return the deps Expr for ruleName.
func getDepsExpr(buildFileName string, ruleName string) build.Expr {
	buildFile, err := parseBuildFile(buildFileName)
	if buildFile == nil {
		log.Printf("%s when parsing %s", err, buildFileName)
		return nil
	}
	rule := edit.FindRuleByName(buildFile, ruleName)
	if rule == nil {
		log.Printf("%s not found in %s", ruleName, buildFileName)
		return nil
	}
	depsExpr := rule.Attr("deps")
	if depsExpr == nil {
		log.Printf("no deps attribute for %s in %s", ruleName, buildFileName)
	}
	return depsExpr
}

// hasRuntimeComment returns true if expr has an EOL comment containing the word "runtime".
// TODO(bazel-team): delete when this comment convention is extinct
func hasRuntimeComment(expr build.Expr) bool {
	for _, comment := range expr.Comment().Suffix {
		if strings.Contains(strings.ToLower(comment.Token), "runtime") {
			return true
		}
	}
	return false
}

// printCommands prints, for each key in the deps map, a buildozer command
// to remove that entry from the deps attribute of the rule identified by label.
// Returns true if at least one command was printed, or false otherwise.
func printCommands(label string, deps map[string]bool) (anyCommandPrinted bool) {
	buildFileName, pkg, ruleName := edit.InterpretLabel(label)
	depsExpr := getDepsExpr(buildFileName, ruleName)
	for _, li := range edit.AllLists(depsExpr) {
		for _, elem := range li.List {
			for dep := range deps {
				str, ok := elem.(*build.StringExpr)
				if ok && labels.Equal(str.Value, dep, pkg) {
					if hasRuntimeComment(str) {
						fmt.Printf("buildozer 'move deps runtime_deps %s' %s\n", str.Value, label)
					} else {
						fmt.Printf("buildozer 'remove deps %s' %s\n", str.Value, label)
					}
					anyCommandPrinted = true
				}
			}
		}
	}
	return anyCommandPrinted
}

// setupAspect creates a workspace in a tmpdir and populates it with an aspect,
// which is used with --override_repository below.
func setupAspect() (string, error) {
	tmp, err := ioutil.TempDir(os.TempDir(), "unused_deps")
	if err != nil {
		return "", err
	}
	for _, f := range []string{"WORKSPACE", "BUILD"} {
		if err := ioutil.WriteFile(path.Join(tmp, f), []byte{}, 0666); err != nil {
			return "", err
		}
	}
	if err := ioutil.WriteFile(path.Join(tmp, "unused_deps.bzl"), []byte(aspect), 0666); err != nil {
		return "", err
	}
	return tmp, nil
}

func usage() {
	fmt.Fprintf(os.Stderr, `usage: unused_deps TARGET...

For Java rules in TARGETs, prints commands to delete deps unused at compile time.
Note these may be used at run time; see documentation for more information.
`)
	os.Exit(2)
}

func main() {
	flag.Usage = usage
	flag.Parse()
	if *version {
		fmt.Printf("unused_deps version: %s \n", buildVersion)
		fmt.Printf("unused_deps scm revision: %s \n", buildScmRevision)
		os.Exit(0)
	}

	if *extraActionFileName != "" {
		jarPath, err := getJarPath(*extraActionFileName)
		if err != nil {
			log.Fatal(err)
		}
		writeUnusedDeps(jarPath, *outputFileName)
		return
	}
	targetPatterns := flag.Args()
	if len(targetPatterns) == 0 {
		targetPatterns = []string{"//..."}
	}
	queryCmd := append([]string{"query"}, blazeFlags...)
	queryCmd = append(
		queryCmd, fmt.Sprintf("kind('(java|android)_*', %s)", strings.Join(targetPatterns, " + ")))

	log.Printf("running: %s %s", *buildTool, strings.Join(queryCmd, " "))
	queryOut, err := cmdWithStderr(*buildTool, queryCmd...).Output()
	if err != nil {
		log.Print(err)
	}
	if len(queryOut) == 0 {
		fmt.Fprintln(os.Stderr, "found no targets of kind (java|android)_*")
		usage()
	}

	aspectDir, err := setupAspect()
	if err != nil {
		log.Print(err)
		os.Exit(1)
	}
	defer func() {
		os.RemoveAll(aspectDir)
	}()

	buildCmd := []string{"build"}
	buildCmd = append(buildCmd, blazeFlags...)
	buildCmd = append(buildCmd, config.DefaultExtraBuildFlags...)
	buildCmd = append(buildCmd, "--output_groups=+unused_deps_outputs")
	buildCmd = append(buildCmd, "--override_repository=unused_deps="+aspectDir)
	buildCmd = append(buildCmd, "--aspects=@unused_deps//:unused_deps.bzl%javac_params")
	buildCmd = append(buildCmd, buildOptions()...)

	blazeArgs := append(buildCmd, targetPatterns...)

	log.Printf("running: %s %s", *buildTool, strings.Join(blazeArgs, " "))
	cmdWithStderr(*buildTool, blazeArgs...).Run()
	blazeBin := blazeInfo(config.DefaultBinDir)
	blazeOutputPath := blazeInfo(config.DefaultOutputPath)
	fmt.Fprintf(os.Stderr, "\n") // vertical space between build output and unused_deps output

	anyCommandPrinted := false
	for _, label := range strings.Fields(string(queryOut)) {
		_, pkg, ruleName := edit.InterpretLabel(label)
		depsByJar := directDepParams(blazeOutputPath, inputFileName(blazeBin, pkg, ruleName, "javac_params"))
		depsToRemove := unusedDeps(inputFileName(blazeBin, pkg, ruleName, "jdeps"), depsByJar)
		// TODO(bazel-team): instead of printing, have buildifier-like modes?
		anyCommandPrinted = printCommands(label, depsToRemove) || anyCommandPrinted
	}
	if !anyCommandPrinted {
		fmt.Fprintln(os.Stderr, "No unused deps found.")
	}
}
<commit_msg>Support Kotlin Rules (#927)<commit_after>/*
Copyright 2017 Google LLC

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

    https://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.
*/

// The unused_deps binary prints out buildozer commands for removing
// unused Java dependencies from java_library Bazel rules.
package main

import (
	"bufio"
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"strings"

	"github.com/bazelbuild/buildtools/build"
	"github.com/bazelbuild/buildtools/config"
	depspb "github.com/bazelbuild/buildtools/deps_proto"
	"github.com/bazelbuild/buildtools/edit"
	eapb "github.com/bazelbuild/buildtools/extra_actions_base_proto"
	"github.com/bazelbuild/buildtools/labels"
	"github.com/golang/protobuf/proto"
)

var (
	buildVersion     = "redacted"
	buildScmRevision = "redacted"

	version             = flag.Bool("version", false, "Print the version of unused_deps")
	buildTool           = flag.String("build_tool", config.DefaultBuildTool, config.BuildToolHelp)
	extraActionFileName = flag.String("extra_action_file", "", config.ExtraActionFileNameHelp)
	outputFileName      = flag.String("output_file", "", "used only with extra_action_file")
	buildOptions        = stringList("extra_build_flags", "Extra build flags to use when building the targets.")

	blazeFlags = []string{"--tool_tag=unused_deps", "--keep_going", "--color=yes", "--curses=yes"}

	aspect = `
# Explicitly creates a params file for a Javac action.
def _javac_params(target, ctx):
    params = []
    for action in target.actions:
        if not action.mnemonic == "Javac" and not action.mnemonic == "KotlinCompile":
            continue
        output = ctx.actions.declare_file("%s.javac_params" % target.label.name)
        args = ctx.actions.args()
        args.add_all(action.argv)
        ctx.actions.write(
            output = output,
            content = args,
        )
        params.append(output)
        break
    return [OutputGroupInfo(unused_deps_outputs = depset(params))]

javac_params = aspect(
    implementation = _javac_params,
)
`
)

func stringList(name, help string) func() []string {
	f := flag.String(name, "", help)
	return func() []string {
		if *f == "" {
			return nil
		}
		res := strings.Split(*f, ",")
		for i := range res {
			res[i] = strings.TrimSpace(res[i])
		}
		return res
	}
}

// getJarPath prints the path to the output jar file specified in the extra_action file at path.
func getJarPath(path string) (string, error) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return "", err
	}
	i := &eapb.ExtraActionInfo{}
	if err := proto.Unmarshal(data, i); err != nil {
		return "", err
	}
	ext, err := proto.GetExtension(i, eapb.E_JavaCompileInfo_JavaCompileInfo)
	if err != nil {
		return "", err
	}
	jci, ok := ext.(*eapb.JavaCompileInfo)
	if !ok {
		return "", errors.New("no JavaCompileInfo in " + path)
	}
	return jci.GetOutputjar(), nil
}

// writeUnusedDeps writes the labels of unused direct deps, one per line, to outputFileName.
func writeUnusedDeps(jarPath, outputFileName string) {
	depsPath := strings.Replace(jarPath, ".jar", ".jdeps", 1)
	paramsPath := jarPath + "-2.params"
	file, _ := os.Create(outputFileName)
	for dep := range unusedDeps(depsPath, directDepParams(paramsPath)) {
		file.WriteString(dep + "\n")
	}
}

func cmdWithStderr(name string, arg ...string) *exec.Cmd {
	cmd := exec.Command(name, arg...)
	cmd.Stderr = os.Stderr
	return cmd
}

// blazeInfo retrieves the blaze info value for a given key.
func blazeInfo(key string) (value string) {
	out, err := cmdWithStderr(*buildTool, "info", key).Output()
	if err != nil {
		log.Printf("'%s info %s' failed: %s", *buildTool, key, err)
	}
	return strings.TrimSpace(bytes.NewBuffer(out).String())
}

// inputFileName returns a blaze output file name from which to read input.
func inputFileName(blazeBin, pkg, ruleName, extension string) string {
	name := fmt.Sprintf("%s/%s/lib%s.%s", blazeBin, pkg, ruleName, extension) // *_library
	if _, err := os.Stat(name); err == nil {
		return name
	}
	// lazily let the caller handle it if this doesn't exist
	return fmt.Sprintf("%s/%s/%s.%s", blazeBin, pkg, ruleName, extension) // *_{binary,test}
}

// directDepParams reads the jar-2.params files, looking for a
// "--direct_dependencies" argument.  When found, the direct dependencies are
// returned as a map from jar file names to labels.
func directDepParams(blazeOutputPath string, paramsFileNames ...string) (depsByJar map[string]string) {
	depsByJar = make(map[string]string)
	errs := make([]error, 0)
	for _, paramsFileName := range paramsFileNames {
		data, err := ioutil.ReadFile(paramsFileName)
		if err != nil {
			errs = append(errs, err)
			continue
		}
		// The classpath param exceeds MaxScanTokenSize, so we scan just the
		// dependencies section.
		directDepsFlag := []byte("--direct_dependencies")
		arg := bytes.Index(data, directDepsFlag)
		if arg < 0 {
			continue
		}
		first := arg + len(directDepsFlag) + 1

		scanner := bufio.NewScanner(bytes.NewReader(data[first:]))
		for scanner.Scan() {
			jar := scanner.Text()
			if strings.HasPrefix(jar, "--") {
				break
			}
			label, err := jarManifestValue(blazeOutputPath+strings.TrimPrefix(jar, "bazel-out"), "Target-Label")
			if err != nil {
				continue
			}
			if len(label) > 2 && label[0] == '@' && label[1] == '@' {
				label = label[1:]
			}
			depsByJar[jar] = label
		}
		if err := scanner.Err(); err != nil {
			log.Printf("reading %s: %s", paramsFileName, err)
		}
	}
	if len(errs) == len(paramsFileNames) {
		for _, err := range errs {
			log.Println(err)
		}
	}
	return depsByJar
}

// unusedDeps returns a set of labels that are unused deps.
// It reads Dependencies proto messages from depsFileName (a jdeps file), which indicate deps used
// at compile time, and returns those values in the depsByJar map that aren't used at compile time.
func unusedDeps(depsFileName string, depsByJar map[string]string) (unusedDeps map[string]bool) {
	unusedDeps = make(map[string]bool)
	data, err := ioutil.ReadFile(depsFileName)
	if err != nil {
		log.Println(err)
		return unusedDeps
	}
	dependencies := &depspb.Dependencies{}
	if err := proto.Unmarshal(data, dependencies); err != nil {
		log.Println(err)
		return unusedDeps
	}
	for _, label := range depsByJar {
		unusedDeps[label] = true
	}
	for _, dependency := range dependencies.Dependency {
		if *dependency.Kind == depspb.Dependency_EXPLICIT {
			delete(unusedDeps, depsByJar[*dependency.Path])
		}
	}
	return unusedDeps
}

// parseBuildFile tries to read and parse the contents of buildFileName.
func parseBuildFile(buildFileName string) (buildFile *build.File, err error) {
	data, err := ioutil.ReadFile(buildFileName)
	if err != nil {
		return nil, err
	}
	return build.Parse(buildFileName, data)
}

// getDepsExpr tries to parse the content of buildFileName and return the deps Expr for ruleName.
func getDepsExpr(buildFileName string, ruleName string) build.Expr {
	buildFile, err := parseBuildFile(buildFileName)
	if buildFile == nil {
		log.Printf("%s when parsing %s", err, buildFileName)
		return nil
	}
	rule := edit.FindRuleByName(buildFile, ruleName)
	if rule == nil {
		log.Printf("%s not found in %s", ruleName, buildFileName)
		return nil
	}
	depsExpr := rule.Attr("deps")
	if depsExpr == nil {
		log.Printf("no deps attribute for %s in %s", ruleName, buildFileName)
	}
	return depsExpr
}

// hasRuntimeComment returns true if expr has an EOL comment containing the word "runtime".
// TODO(bazel-team): delete when this comment convention is extinct
func hasRuntimeComment(expr build.Expr) bool {
	for _, comment := range expr.Comment().Suffix {
		if strings.Contains(strings.ToLower(comment.Token), "runtime") {
			return true
		}
	}
	return false
}

// printCommands prints, for each key in the deps map, a buildozer command
// to remove that entry from the deps attribute of the rule identified by label.
// Returns true if at least one command was printed, or false otherwise.
func printCommands(label string, deps map[string]bool) (anyCommandPrinted bool) {
	buildFileName, pkg, ruleName := edit.InterpretLabel(label)
	depsExpr := getDepsExpr(buildFileName, ruleName)
	for _, li := range edit.AllLists(depsExpr) {
		for _, elem := range li.List {
			for dep := range deps {
				str, ok := elem.(*build.StringExpr)
				if ok && labels.Equal(str.Value, dep, pkg) {
					if hasRuntimeComment(str) {
						fmt.Printf("buildozer 'move deps runtime_deps %s' %s\n", str.Value, label)
					} else {
						fmt.Printf("buildozer 'remove deps %s' %s\n", str.Value, label)
					}
					anyCommandPrinted = true
				}
			}
		}
	}
	return anyCommandPrinted
}

// setupAspect creates a workspace in a tmpdir and populates it with an aspect,
// which is used with --override_repository below.
func setupAspect() (string, error) {
	tmp, err := ioutil.TempDir(os.TempDir(), "unused_deps")
	if err != nil {
		return "", err
	}
	for _, f := range []string{"WORKSPACE", "BUILD"} {
		if err := ioutil.WriteFile(path.Join(tmp, f), []byte{}, 0666); err != nil {
			return "", err
		}
	}
	if err := ioutil.WriteFile(path.Join(tmp, "unused_deps.bzl"), []byte(aspect), 0666); err != nil {
		return "", err
	}
	return tmp, nil
}

func usage() {
	fmt.Fprintf(os.Stderr, `usage: unused_deps TARGET...

For Java rules in TARGETs, prints commands to delete deps unused at compile time.
Note these may be used at run time; see documentation for more information.
`)
	os.Exit(2)
}

func main() {
	flag.Usage = usage
	flag.Parse()
	if *version {
		fmt.Printf("unused_deps version: %s \n", buildVersion)
		fmt.Printf("unused_deps scm revision: %s \n", buildScmRevision)
		os.Exit(0)
	}

	if *extraActionFileName != "" {
		jarPath, err := getJarPath(*extraActionFileName)
		if err != nil {
			log.Fatal(err)
		}
		writeUnusedDeps(jarPath, *outputFileName)
		return
	}
	targetPatterns := flag.Args()
	if len(targetPatterns) == 0 {
		targetPatterns = []string{"//..."}
	}
	queryCmd := append([]string{"query"}, blazeFlags...)
	queryCmd = append(
		queryCmd, fmt.Sprintf("kind('(kt|java|android)_*', %s)", strings.Join(targetPatterns, " + ")))

	log.Printf("running: %s %s", *buildTool, strings.Join(queryCmd, " "))
	queryOut, err := cmdWithStderr(*buildTool, queryCmd...).Output()
	if err != nil {
		log.Print(err)
	}
	if len(queryOut) == 0 {
		fmt.Fprintln(os.Stderr, "found no targets of kind (kt|java|android)_*")
		usage()
	}

	aspectDir, err := setupAspect()
	if err != nil {
		log.Print(err)
		os.Exit(1)
	}
	defer func() {
		os.RemoveAll(aspectDir)
	}()

	buildCmd := []string{"build"}
	buildCmd = append(buildCmd, blazeFlags...)
	buildCmd = append(buildCmd, config.DefaultExtraBuildFlags...)
	buildCmd = append(buildCmd, "--output_groups=+unused_deps_outputs")
	buildCmd = append(buildCmd, "--override_repository=unused_deps="+aspectDir)
	buildCmd = append(buildCmd, "--aspects=@unused_deps//:unused_deps.bzl%javac_params")
	buildCmd = append(buildCmd, buildOptions()...)

	blazeArgs := append(buildCmd, targetPatterns...)

	log.Printf("running: %s %s", *buildTool, strings.Join(blazeArgs, " "))
	cmdWithStderr(*buildTool, blazeArgs...).Run()
	blazeBin := blazeInfo(config.DefaultBinDir)
	blazeOutputPath := blazeInfo(config.DefaultOutputPath)
	fmt.Fprintf(os.Stderr, "\n") // vertical space between build output and unused_deps output

	anyCommandPrinted := false
	for _, label := range strings.Fields(string(queryOut)) {
		_, pkg, ruleName := edit.InterpretLabel(label)
		depsByJar := directDepParams(blazeOutputPath, inputFileName(blazeBin, pkg, ruleName, "javac_params"))
		depsToRemove := unusedDeps(inputFileName(blazeBin, pkg, ruleName, "jdeps"), depsByJar)
		// TODO(bazel-team): instead of printing, have buildifier-like modes?
		anyCommandPrinted = printCommands(label, depsToRemove) || anyCommandPrinted
	}
	if !anyCommandPrinted {
		fmt.Fprintln(os.Stderr, "No unused deps found.")
	}
}
<|endoftext|>


<commit_before>package billing

// Definition is an admin-modifiable parameter for bmbilling
// examples include account-opening credit amount and trial length
type Definition struct {
	ID    int    `json:"id,omitempty"`
	Name  string `json:"name"`
	Value string `json:"value"`
	// Which auth group a user must be in to update the definition
	UpdateGroupReq string `json:"update_group_req,omitempty"`
}
<commit_msg>add DefaultFields and PrettyPrint to billing.Definition<commit_after>package billing

import (
	"io"

	"github.com/BytemarkHosting/bytemark-client/lib/output"
	"github.com/BytemarkHosting/bytemark-client/lib/output/prettyprint"
)

// Definition is an admin-modifiable parameter for bmbilling
// examples include account-opening credit amount and trial length
type Definition struct {
	ID    int    `json:"id,omitempty"`
	Name  string `json:"name"`
	Value string `json:"value"`
	// Which auth group a user must be in to update the definition
	UpdateGroupReq string `json:"update_group_req,omitempty"`
}

// DefaultFields returns the default fields used for making tables of Definitions
func (d Definition) DefaultFields(f output.Format) string {
	return "Name, Value, UpdateGroupReq"
}

// PrettyPrint writes the Definition in a human-readable form at the given detail level to wr
func (d Definition) PrettyPrint(wr io.Writer, detail prettyprint.DetailLevel) {
	definitionTpl := `
		{{ define "definition_sgl" }}{{ .Name }}: {{ .Value }}{{ end }}
		{{ define "definition_medium" }}{{ template "definition_sgl" . }}{{ end }}
		{{ define "definition_full" -}}
ID: {{ .ID }}
Name: {{ .Name }}
Value: {{ .Value }}
Update Group Requirement: {{ .UpdateGroupReq }}
		{{- end }}
	`
	prettyprint.Run(wr, definitionTpl, "definition"+detail)
}
<|endoftext|>


<commit_before>package tumblgo

import (
	"fmt"

	"github.com/guregu/null"
)

// PostType .
type PostType string

const (
	// PostTypeUnknown .
	PostTypeUnknown PostType = "unknown"
	// PostTypeText .
	PostTypeText = "text"
	// PostTypeQuote .
	PostTypeQuote = "quote"
	// PostTypeLink .
	PostTypeLink = "link"
	// PostTypeAnswer .
	PostTypeAnswer = "answer"
	// PostTypeVideo .
	PostTypeVideo = "video"
	// PostTypeAudio .
	PostTypeAudio = "audio"
	// PostTypePhoto .
	PostTypePhoto = "photo"
	// PostTypeChat .
	PostTypeChat = "chat"
)

// BlogPostsRequest .
type BlogPostsRequest struct {
	Type       *PostType   `json:"type"`
	ID         null.Int    `json:"id"`
	Tag        null.String `json:""`
	Limit      int         `json:"limit"`
	Offset     int         `json:"offset"`
	ReblogInfo bool        `json:"reblog_info"`
	NotesInfo  bool        `json:"notes_info"`
	Filter     null.String `json:"filter"`
}

// BlogPostsResponse .
type BlogPostsResponse struct {
	Meta     Meta      `json:"meta"`
	Response BlogPosts `json:"response"`
}

// BlogPosts .
type BlogPosts struct {
	Blog  Blog   `json:"blog"`
	Posts []Post `json:"posts"`
}

// Post .
type Post struct {
	Raw interface{}
}

// PostType get post type.
func (p Post) PostType() PostType {
	switch p.Raw.(type) {
	default:
		fmt.Println(p.Raw)
	}

	return PostTypeUnknown
}

// BasePost .
type BasePost struct {
	BlogName    string   `json:"blog_name"`
	ID          int64    `json:"id"`
	PostURL     string   `json:"post_url"`
	Type        PostType `json:"type"`
	Timestump   int      `json:"timestump"`
	Date        string   `json:"date"`
	Format      string   `json:"format"`
	ReblogKey   string   `json:"reblog_key"`
	Tags        []string `json:"tags"`
	Bookmarklet bool     `json:"bookmarklet"`
	Mobile      bool     `json:"mobile"`
	SourceURL   string   `json:"source_url"`
	SourceTitle string   `json:"source_title"`
	Liked       bool     `json:"liked"`
	State       string   `json:"state"`
	TotalPosts  int      `json:"total_posts"`
}

// TextPost text post.
type TextPost struct {
	BasePost
	Title string `json:"title"`
	Body  string `json:"body"`
}

// PhotoSize .
type PhotoSize struct {
	Width  int    `json:"width"`
	Height int    `json:"height"`
	URL    string `json:"url"`
}

// Photo .
type Photo struct {
	Caption      string      `json:"caption"`
	AltSizes     []PhotoSize `json:"alt_size"`
	OriginalSize PhotoSize   `json:"original_size"`
}

// PhotoPost .
type PhotoPost struct {
	BasePost
	Photos []Photo `json:"photos"`
}

// QuotePost .
type QuotePost struct {
	BasePost
	Text   string `json:"text"`
	Source string `json:"source"`
}

// LinkPost .
type LinkPost struct {
	BasePost
	Title       string  `json:"title"`
	URL         string  `json:"url"`
	Author      string  `json:"author"`
	Excerpt     string  `json:"excerpt"`
	Publisher   string  `json:"publisher"`
	Photos      []Photo `json:"photos"`
	Description string  `json:"description"`
}

// Dialogue .
type Dialogue struct {
	Name   string `json:"name"`
	Label  string `json:"label"`
	Phrase string `json:"phrase"`
}

// ChatPost .
type ChatPost struct {
	BasePost
	Title     string     `json:"title"`
	Post      string     `json:"post"`
	Dialogues []Dialogue `json:"dialogue"`
}

// AudioPost .
type AudioPost struct {
	BasePost
	Caption     string `json:"caption"`
	Player      string `json:"player"`
	Plays       int64  `json:"plays"`
	AlbumArt    string `json:"almub_art"`
	Artist      string `json:"artist"`
	Album       string `json:"album"`
	TrackName   string `json:"track_name"`
	TrackNumber int    `json:"track_number"`
	Year        int    `json:"year"`
}

// Player .
type Player struct {
	Width     int    `json:"width"`
	EmbedCode string `json:"embed_code"`
}

// VideoPost .
type VideoPost struct {
	BasePost
	Caption string   `json:"caption"`
	Players []Player `json:"player"`
}

// AnswerPost .
type AnswerPost struct {
	BasePost
	AskingName string `json:"asking_name"`
	AskingURL  string `json:"asking_url"`
	Question   string `json:"question"`
	Answer     string `json:"answer"`
}

// BlogPosts Retrieve Published Posts
func (c *Client) BlogPosts(bi string, param BlogPostsRequest) (*BlogPostsResponse, error) {
	req, err := c.Request("GET", c.BlogEndpoint(bi, "posts"), nil)
	if err != nil {
		return nil, err
	}

	resp := BlogPostsResponse{}
	if err := c.ReadResponse(req, &resp); err != nil {
		return nil, err
	}

	return &resp, nil
}
<commit_msg>post insert interface{} from json.<commit_after>package tumblgo

import (
	"encoding/json"
	"fmt"

	"github.com/guregu/null"
)

// PostType .
type PostType string

const (
	// PostTypeUnknown .
	PostTypeUnknown PostType = "unknown"
	// PostTypeText .
	PostTypeText = "text"
	// PostTypeQuote .
	PostTypeQuote = "quote"
	// PostTypeLink .
	PostTypeLink = "link"
	// PostTypeAnswer .
	PostTypeAnswer = "answer"
	// PostTypeVideo .
	PostTypeVideo = "video"
	// PostTypeAudio .
	PostTypeAudio = "audio"
	// PostTypePhoto .
	PostTypePhoto = "photo"
	// PostTypeChat .
	PostTypeChat = "chat"
)

// BlogPostsRequest .
type BlogPostsRequest struct {
	Type       *PostType   `json:"type"`
	ID         null.Int    `json:"id"`
	Tag        null.String `json:""`
	Limit      int         `json:"limit"`
	Offset     int         `json:"offset"`
	ReblogInfo bool        `json:"reblog_info"`
	NotesInfo  bool        `json:"notes_info"`
	Filter     null.String `json:"filter"`
}

// BlogPostsResponse .
type BlogPostsResponse struct {
	Meta     Meta      `json:"meta"`
	Response BlogPosts `json:"response"`
}

// BlogPosts .
type BlogPosts struct {
	Blog  Blog   `json:"blog"`
	Posts []Post `json:"posts"`
}

// Post .
type Post struct {
	Raw interface{}
}

// UnmarshalJSON get data from json!
func (p *Post) UnmarshalJSON(data []byte) error {
	if err := json.Unmarshal(data, &(p.Raw)); err != nil {
		return err
	}
	return nil
}

// PostType get post type.
func (p Post) PostType() PostType {
	switch p.Raw.(type) {
	default:
		fmt.Println(p.Raw)
	}

	return PostTypeUnknown
}

// BasePost .
type BasePost struct {
	BlogName    string   `json:"blog_name"`
	ID          int64    `json:"id"`
	PostURL     string   `json:"post_url"`
	Type        PostType `json:"type"`
	Timestump   int      `json:"timestump"`
	Date        string   `json:"date"`
	Format      string   `json:"format"`
	ReblogKey   string   `json:"reblog_key"`
	Tags        []string `json:"tags"`
	Bookmarklet bool     `json:"bookmarklet"`
	Mobile      bool     `json:"mobile"`
	SourceURL   string   `json:"source_url"`
	SourceTitle string   `json:"source_title"`
	Liked       bool     `json:"liked"`
	State       string   `json:"state"`
	TotalPosts  int      `json:"total_posts"`
}

// TextPost text post.
type TextPost struct {
	BasePost
	Title string `json:"title"`
	Body  string `json:"body"`
}

// PhotoSize .
type PhotoSize struct {
	Width  int    `json:"width"`
	Height int    `json:"height"`
	URL    string `json:"url"`
}

// Photo .
type Photo struct {
	Caption      string      `json:"caption"`
	AltSizes     []PhotoSize `json:"alt_size"`
	OriginalSize PhotoSize   `json:"original_size"`
}

// PhotoPost .
type PhotoPost struct {
	BasePost
	Photos []Photo `json:"photos"`
}

// QuotePost .
type QuotePost struct {
	BasePost
	Text   string `json:"text"`
	Source string `json:"source"`
}

// LinkPost .
type LinkPost struct {
	BasePost
	Title       string  `json:"title"`
	URL         string  `json:"url"`
	Author      string  `json:"author"`
	Excerpt     string  `json:"excerpt"`
	Publisher   string  `json:"publisher"`
	Photos      []Photo `json:"photos"`
	Description string  `json:"description"`
}

// Dialogue .
type Dialogue struct {
	Name   string `json:"name"`
	Label  string `json:"label"`
	Phrase string `json:"phrase"`
}

// ChatPost .
type ChatPost struct {
	BasePost
	Title     string     `json:"title"`
	Post      string     `json:"post"`
	Dialogues []Dialogue `json:"dialogue"`
}

// AudioPost .
type AudioPost struct {
	BasePost
	Caption     string `json:"caption"`
	Player      string `json:"player"`
	Plays       int64  `json:"plays"`
	AlbumArt    string `json:"almub_art"`
	Artist      string `json:"artist"`
	Album       string `json:"album"`
	TrackName   string `json:"track_name"`
	TrackNumber int    `json:"track_number"`
	Year        int    `json:"year"`
}

// Player .
type Player struct {
	Width     int    `json:"width"`
	EmbedCode string `json:"embed_code"`
}

// VideoPost .
type VideoPost struct {
	BasePost
	Caption string   `json:"caption"`
	Players []Player `json:"player"`
}

// AnswerPost .
type AnswerPost struct {
	BasePost
	AskingName string `json:"asking_name"`
	AskingURL  string `json:"asking_url"`
	Question   string `json:"question"`
	Answer     string `json:"answer"`
}

// BlogPosts Retrieve Published Posts
func (c *Client) BlogPosts(bi string, param BlogPostsRequest) (*BlogPostsResponse, error) {
	req, err := c.Request("GET", c.BlogEndpoint(bi, "posts"), nil)
	if err != nil {
		return nil, err
	}

	resp := BlogPostsResponse{}
	if err := c.ReadResponse(req, &resp); err != nil {
		return nil, err
	}

	return &resp, nil
}
<|endoftext|>


<commit_before>package agent

// You can overridden buildVersion at compile time by using:
//
//  go run -ldflags "-X github.com/buildkite/agent/agent.buildVersion abc" *.go --version
//
// On CI, the binaries are always build with the buildVersion variable set.

var baseVersion string = "3.0-beta.41"
var buildVersion string = ""

func Version() string {
	return baseVersion
}

func BuildVersion() string {
	if buildVersion != "" {
		return buildVersion
	} else {
		return "x"
	}
}
<commit_msg>Bump version to 3.0-beta.42<commit_after>package agent

// You can overridden buildVersion at compile time by using:
//
//  go run -ldflags "-X github.com/buildkite/agent/agent.buildVersion abc" *.go --version
//
// On CI, the binaries are always build with the buildVersion variable set.

var baseVersion string = "3.0-beta.42"
var buildVersion string = ""

func Version() string {
	return baseVersion
}

func BuildVersion() string {
	if buildVersion != "" {
		return buildVersion
	} else {
		return "x"
	}
}
<|endoftext|>


<commit_before>// Copyright 2012 Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.

package layers

import (
	"encoding/binary"
	"github.com/google/gopacket"
	"net"
	"time"
)

type IGMPType uint8

const (
	MembershipQuery    IGMPType = 0x11 // General or group specific query
	MembershipReportV1 IGMPType = 0x12 // Version 1 Membership Report
	MembershipReportV2 IGMPType = 0x16 // Version 2 Membership Report
	LeaveGroup         IGMPType = 0x17 // Leave Group
	MembershipReportV3 IGMPType = 0x22 // Version 3 Membership Report
)

// String conversions for IGMP message types
func (i IGMPType) String() string {
	switch i {
	case MembershipQuery:
		return "IGMP Membership Query"
	case MembershipReportV1:
		return "IGMPv1 Membership Report"
	case MembershipReportV2:
		return "IGMPv2 Membership Report"
	case MembershipReportV3:
		return "IGMPv3 Membership Report"
	case LeaveGroup:
		return "Leave Group"
	default:
		return ""
	}
}

type IGMPQuery interface {
	decodeResponse(data []byte) error
}

// IGMP is the packet structure for IGMP messages.
type IGMP struct {
	BaseLayer
	Type    IGMPType  // IGMP message type
	Message IGMPQuery // Container for message payload
	Version uint8     // IGMP protocol version
}

type GroupRecordType uint8

const (
	IsIn  GroupRecordType = 0x01 // Type MODE_IS_INCLUDE, source addresses x
	IsEx  GroupRecordType = 0x02 // Type MODE_IS_EXCLUDE, source addresses x
	ToIn  GroupRecordType = 0x03 // Type CHANGE_TO_INCLUDE_MODE, source addresses x
	ToEx  GroupRecordType = 0x04 // Type CHANGE_TO_EXCLUDE_MODE, source addresses x
	Allow GroupRecordType = 0x05 // Type ALLOW_NEW_SOURCES, source addresses x
	Block GroupRecordType = 0x06 // Type BLOCK_OLD_SOURCES, source addresses x
)

func (i GroupRecordType) String() string {
	switch i {
	case IsIn:
		return "MODE_IS_INCLUDE"
	case IsEx:
		return "MODE_IS_EXCLUDE"
	case ToIn:
		return "CHANGE_TO_INCLUDE_MODE"
	case ToEx:
		return "CHANGE_TO_EXCLUDE_MODE"
	case Allow:
		return "ALLOW_NEW_SOURCES"
	case Block:
		return "BLOCK_OLD_SOURCES"
	default:
		return ""
	}
}

//  0                   1                   2                   3
//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |      Type     | Max Resp Time |           Checksum            |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                         Group Address                         |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// IGMPv1or2 stores header details for an IGMPv1 or IGMPv2 packet.
type IGMPv1or2 struct {
	MaxRespTime  time.Duration // meaningful only in Membership Query messages
	Checksum     uint16        // 16-bit checksum of entire ip payload
	GroupAddress net.IP        // either 0 or an IP multicast address
}

// decodeResponse dissects IGMPv1 or IGMPv2 packet.
func (i *IGMPv1or2) decodeResponse(data []byte) error {
	i.MaxRespTime = igmpTimeDecode(data[1])
	i.Checksum = binary.BigEndian.Uint16(data[2:4])
	i.GroupAddress = net.IP(data[4:8])

	return nil
}

//  0                   1                   2                   3
//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |  Type = 0x22  |    Reserved   |           Checksum            |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |           Reserved            |  Number of Group Records (M)  |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                                                               |
// .                        Group Record [1]                       .
// |                                                               |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                                                               |
// .                        Group Record [2]                       .
// |                                                               |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                                                               |
// .                        Group Record [M]                       .
// |                                                               |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// IGMPv3MembershipReport stores bytes 2: of the V3 Membership Report packet
type IGMPv3MembershipReport struct {
	Checksum             uint16 // 16-bit checksum of entire ip payload
	NumberofGroupRecords uint16
	GroupRecords         []GroupRecord
}

// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |  Record Type  |  Aux Data Len |     Number of Sources (N)     |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                       Multicast Address                       |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                       Source Address [1]                      |
// +-                                                             -+
// |                       Source Address [2]                      |
// +-                                                             -+
// |                       Source Address [N]                      |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                                                               |
// .                         Auxiliary Data                        .
// |                                                               |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// GroupRecord stores individual group records for a V3 Membership Report message.
type GroupRecord struct {
	Type             GroupRecordType
	AuxDataLen       uint8 // this should always be 0 as per IGMPv3 spec.
	NumberOfSources  uint16
	MulticastAddress net.IP
	SourceAddresses  []net.IP
	AuxData          uint32 // NOT USED
}

// decodeResponse decodes an IGMPv3MembershipReport message.
func (i *IGMPv3MembershipReport) decodeResponse(data []byte) error {
	i.Checksum = binary.BigEndian.Uint16(data[2:4])
	i.NumberofGroupRecords = binary.BigEndian.Uint16(data[6:8])

	for j := 0; j < int(i.NumberofGroupRecords); j++ {
		var gr GroupRecord
		gr.Type = GroupRecordType(data[8])
		gr.AuxDataLen = data[9]
		gr.NumberOfSources = binary.BigEndian.Uint16(data[10:12])
		gr.MulticastAddress = net.IP(data[12:16])

		// append source address records.
		for i := 0; i < int(gr.NumberOfSources); i++ {
			gr.SourceAddresses = append(gr.SourceAddresses, net.IP(data[16+i*4:20+i*4]))
		}

		i.GroupRecords = append(i.GroupRecords, gr)
	}
	return nil
}

//  0                   1                   2                   3
//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |  Type = 0x11  | Max Resp Code |           Checksum            |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                         Group Address                         |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Resv  |S| QRV |     QQIC      |     Number of Sources (N)     |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                       Source Address [1]                      |
// +-                                                             -+
// |                       Source Address [2]                      |
// +-                              .                              -+
// |                       Source Address [N]                      |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type IGMPv3MembershipQuery struct {
	MaxResponseTime time.Duration // IGMP Max response code/time
	Checksum        uint16        // 16-bit checksum of entire ip payload
	GroupAddress    net.IP        // IP multicast address.
	SFlag           bool          // Suppress Router-Side Processing
	QRV             uint8         // Querier's Robustness Variable
	QQIC            time.Duration // Querier's Query Interval Code
	NumberofSources uint16
	SourceAddresses []net.IP
}

func (i *IGMPv3MembershipQuery) decodeResponse(data []byte) error {

	i.Checksum = binary.BigEndian.Uint16(data[2:4])
	i.SFlag = data[8]&0x8 != 0
	i.GroupAddress = net.IP(data[4:8])
	i.QRV = data[8] & 0x7
	i.QQIC = igmpTimeDecode(data[9])
	i.NumberofSources = binary.BigEndian.Uint16(data[10:12])

	for j := 0; j < int(i.NumberofSources); j++ {
		i.SourceAddresses = append(i.SourceAddresses, net.IP(data[12+j*4:16+j*4]))
	}

	return nil
}

// LayerType returns LayerTypeIGMP
func (i *IGMP) LayerType() gopacket.LayerType { return LayerTypeIGMP }

// igmpTimeDecode decodes the duration created by the given byte, using the
// algorithm in http://www.rfc-base.org/txt/rfc-3376.txt section 4.1.1.
func igmpTimeDecode(t uint8) time.Duration {
	if t&0x80 == 0 {
		return time.Millisecond * 100 * time.Duration(t)
	}
	mant := (t & 0x70) >> 4
	exp := t & 0x0F
	return time.Millisecond * 100 * time.Duration((mant|0x10)<<(exp+3))
}

// DecodeFromBytes decodes the given bytes into this layer.
func (i *IGMP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {

	// common IGMP header values between versions 1..3 of IGMP specification..
	i.Type = IGMPType(data[0])

	switch i.Type {

	case MembershipQuery:

		// IGMPv3 Membership Query payload is >= 12
		if len(data) >= 12 {
			i.Version = 3
			i.Message = new(IGMPv3MembershipQuery)
			i.Message.decodeResponse(data)

		} else if len(data) == 8 {

			if data[1] == 0x00 {
				i.Version = 1 // IGMPv1 has a query length of 8 and MaxResp = 0
			} else {
				i.Version = 2 // IGMPv2 has a query length of 8 and MaxResp != 0
			}

			i.Message = new(IGMPv1or2)
			i.Message.decodeResponse(data)
		}

	case MembershipReportV3:
		i.Version = 3
		i.Message = new(IGMPv3MembershipReport)
		i.Message.decodeResponse(data)

	case MembershipReportV1:
		i.Version = 1
		i.Message = new(IGMPv1or2)
		i.Message.decodeResponse(data)

	case LeaveGroup, MembershipReportV2:
		// leave group and Query Report v2 used in IGMPv2 only.
		i.Version = 2
		i.Message = new(IGMPv1or2)
		i.Message.decodeResponse(data)
	}

	return nil
}

// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (i *IGMP) CanDecode() gopacket.LayerClass {
	return LayerTypeIGMP
}

// NextLayerType returns the layer type contained by this DecodingLayer.
func (i *IGMP) NextLayerType() gopacket.LayerType {
	return gopacket.LayerTypeZero
}

func decodeIGMP(data []byte, p gopacket.PacketBuilder) error {
	i := &IGMP{}
	return decodingLayerDecoder(i, data, p)
}
<commit_msg>Pass #2 of the layers-igmp-feature-updates branch.<commit_after>// Copyright 2012 Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.

package layers

import (
	"encoding/binary"
	"fmt"
	"github.com/google/gopacket"
	"net"
	"time"
)

type IGMPType uint8

const (
	IGMPMembershipQuery    IGMPType = 0x11 // General or group specific query
	IGMPMembershipReportV1 IGMPType = 0x12 // Version 1 Membership Report
	IGMPMembershipReportV2 IGMPType = 0x16 // Version 2 Membership Report
	IGMPLeaveGroup         IGMPType = 0x17 // Leave Group
	IGMPMembershipReportV3 IGMPType = 0x22 // Version 3 Membership Report
)

// String conversions for IGMP message types
func (i IGMPType) String() string {
	switch i {
	case IGMPMembershipQuery:
		return "IGMP Membership Query"
	case IGMPMembershipReportV1:
		return "IGMPv1 Membership Report"
	case IGMPMembershipReportV2:
		return "IGMPv2 Membership Report"
	case IGMPMembershipReportV3:
		return "IGMPv3 Membership Report"
	case IGMPLeaveGroup:
		return "Leave Group"
	default:
		return ""
	}
}

type IGMPv3GroupRecordType uint8

const (
	IGMPIsIn  IGMPv3GroupRecordType = 0x01 // Type MODE_IS_INCLUDE, source addresses x
	IGMPIsEx  IGMPv3GroupRecordType = 0x02 // Type MODE_IS_EXCLUDE, source addresses x
	IGMPToIn  IGMPv3GroupRecordType = 0x03 // Type CHANGE_TO_INCLUDE_MODE, source addresses x
	IGMPToEx  IGMPv3GroupRecordType = 0x04 // Type CHANGE_TO_EXCLUDE_MODE, source addresses x
	IGMPAllow IGMPv3GroupRecordType = 0x05 // Type ALLOW_NEW_SOURCES, source addresses x
	IGMPBlock IGMPv3GroupRecordType = 0x06 // Type BLOCK_OLD_SOURCES, source addresses x
)

func (i IGMPv3GroupRecordType) String() string {
	switch i {
	case IGMPIsIn:
		return "MODE_IS_INCLUDE"
	case IGMPIsEx:
		return "MODE_IS_EXCLUDE"
	case IGMPToIn:
		return "CHANGE_TO_INCLUDE_MODE"
	case IGMPToEx:
		return "CHANGE_TO_EXCLUDE_MODE"
	case IGMPAllow:
		return "ALLOW_NEW_SOURCES"
	case IGMPBlock:
		return "BLOCK_OLD_SOURCES"
	default:
		return ""
	}
}

// IGMP represents an IGMPv3 message.
type IGMP struct {
	BaseLayer
	Type                    IGMPType
	MaxResponseTime         time.Duration
	Checksum                uint16
	GroupAddress            net.IP
	SupressRouterProcessing bool
	RobustnessValue         uint8
	IntervalTime            time.Duration
	SourceAddresses         []net.IP
	NumberOfGroupRecords    uint16
	NumberOfSources         uint16
	GroupRecords            []IGMPv3GroupRecord
	Version                 uint8 // IGMP protocol version

}

//  0                   1                   2                   3
//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |      Type     | Max Resp Time |           Checksum            |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                         Group Address                         |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// IGMPv1Orv2 stores header details for an IGMPv1 or IGMPv2 packet.
type IGMPv1Orv2 struct {
	BaseLayer
	Type            IGMPType      // IGMP message type
	MaxResponseTime time.Duration // meaningful only in Membership Query messages
	Checksum        uint16        // 16-bit checksum of entire ip payload
	GroupAddress    net.IP        // either 0 or an IP multicast address
	Version         uint8
}

// decodeResponse dissects IGMPv1 or IGMPv2 packet.
func (i *IGMPv1Orv2) decodeResponse(data []byte) error {
	i.MaxResponseTime = igmpTimeDecode(data[1])
	i.Checksum = binary.BigEndian.Uint16(data[2:4])
	i.GroupAddress = net.IP(data[4:8])

	return nil
}

//  0                   1                   2                   3
//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |  Type = 0x22  |    Reserved   |           Checksum            |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |           Reserved            |  Number of Group Records (M)  |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                                                               |
// .                        Group Record [1]                       .
// |                                                               |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                                                               |
// .                        Group Record [2]                       .
// |                                                               |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                                                               |
// .                        Group Record [M]                       .
// |                                                               |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |  Record Type  |  Aux Data Len |     Number of Sources (N)     |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                       Multicast Address                       |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                       Source Address [1]                      |
// +-                                                             -+
// |                       Source Address [2]                      |
// +-                                                             -+
// |                       Source Address [N]                      |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                                                               |
// .                         Auxiliary Data                        .
// |                                                               |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// IGMPv3GroupRecord stores individual group records for a V3 Membership Report message.
type IGMPv3GroupRecord struct {
	Type             IGMPv3GroupRecordType
	AuxDataLen       uint8 // this should always be 0 as per IGMPv3 spec.
	NumberOfSources  uint16
	MulticastAddress net.IP
	SourceAddresses  []net.IP
	AuxData          uint32 // NOT USED
}

func (i *IGMP) decodeIGMPv3MembershipReport(data []byte) error {
	i.Checksum = binary.BigEndian.Uint16(data[2:4])
	i.NumberOfGroupRecords = binary.BigEndian.Uint16(data[6:8])

	for j := 0; j < int(i.NumberOfGroupRecords); j++ {
		var gr IGMPv3GroupRecord
		gr.Type = IGMPv3GroupRecordType(data[8])
		gr.AuxDataLen = data[9]
		gr.NumberOfSources = binary.BigEndian.Uint16(data[10:12])
		gr.MulticastAddress = net.IP(data[12:16])

		// append source address records.
		for i := 0; i < int(gr.NumberOfSources); i++ {
			gr.SourceAddresses = append(gr.SourceAddresses, net.IP(data[16+i*4:20+i*4]))
		}

		i.GroupRecords = append(i.GroupRecords, gr)
	}
	return nil
}

//  0                   1                   2                   3
//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |  Type = 0x11  | Max Resp Code |           Checksum            |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                         Group Address                         |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Resv  |S| QRV |     QQIC      |     Number of Sources (N)     |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                       Source Address [1]                      |
// +-                                                             -+
// |                       Source Address [2]                      |
// +-                              .                              -+
// |                       Source Address [N]                      |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// decodeIGMPv3MembershipQuery parses the IGMPv3 message of type 0x11
func (i *IGMP) decodeIGMPv3MembershipQuery(data []byte) error {

	i.MaxResponseTime = igmpTimeDecode(data[1])
	i.Checksum = binary.BigEndian.Uint16(data[2:4])
	i.SupressRouterProcessing = data[8]&0x8 != 0
	i.GroupAddress = net.IP(data[4:8])
	i.RobustnessValue = data[8] & 0x7
	i.IntervalTime = igmpTimeDecode(data[9])
	i.NumberOfSources = binary.BigEndian.Uint16(data[10:12])

	for j := 0; j < int(i.NumberOfSources); j++ {
		i.SourceAddresses = append(i.SourceAddresses, net.IP(data[12+j*4:16+j*4]))
	}

	return nil
}

// igmpTimeDecode decodes the duration created by the given byte, using the
// algorithm in http://www.rfc-base.org/txt/rfc-3376.txt section 4.1.1.
func igmpTimeDecode(t uint8) time.Duration {
	if t&0x80 == 0 {
		return time.Millisecond * 100 * time.Duration(t)
	}
	mant := (t & 0x70) >> 4
	exp := t & 0x0F
	return time.Millisecond * 100 * time.Duration((mant|0x10)<<(exp+3))
}

// LayerType returns LayerTypeIGMP for the V1,2,3 message protocol formats.
func (i *IGMP) LayerType() gopacket.LayerType       { return LayerTypeIGMP }
func (i *IGMPv1Orv2) LayerType() gopacket.LayerType { return LayerTypeIGMP }

func (i *IGMPv1Orv2) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
	i.Type = IGMPType(data[0])
	i.MaxResponseTime = igmpTimeDecode(data[1])
	i.Checksum = binary.BigEndian.Uint16(data[2:4])
	i.GroupAddress = net.IP(data[4:8])

	return nil
}

func (i *IGMPv1Orv2) NextLayerType() gopacket.LayerType {
	return gopacket.LayerTypeZero
}

func (i *IGMPv1Orv2) CanDecode() gopacket.LayerClass {
	return LayerTypeIGMP
}

// DecodeFromBytes decodes the given bytes into this layer.
func (i *IGMP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {

	// common IGMP header values between versions 1..3 of IGMP specification..
	i.Type = IGMPType(data[0])

	switch i.Type {

	case IGMPMembershipQuery:
		i.decodeIGMPv3MembershipQuery(data)

	case IGMPMembershipReportV3:
		i.decodeIGMPv3MembershipReport(data)
	}

	return nil
}

// CanDecode returns the set of layer types that this DecodingLayer can decode.
func (i *IGMP) CanDecode() gopacket.LayerClass {
	return LayerTypeIGMP
}

// NextLayerType returns the layer type contained by this DecodingLayer.
func (i *IGMP) NextLayerType() gopacket.LayerType {
	return gopacket.LayerTypeZero
}

// decodeIGMP will parse IGMP v1,2 or 3 protocols. Checks against the IGMP type are performed against byte[0], logic then iniitalizes and passes the appropriate struct (IGMP or IGMPv1Or2) to decodingLayerDecoder.
func decodeIGMP(data []byte, p gopacket.PacketBuilder) error {

	// byte 0 contains IGMP message type.
	switch IGMPType(data[0]) {

	case IGMPMembershipQuery:

		// IGMPv3 Membership Query payload is >= 12
		if len(data) >= 12 {
			i := &IGMP{Version: 3}
			return decodingLayerDecoder(i, data, p)

		} else if len(data) == 8 {
			i := &IGMPv1Orv2{}
			if data[1] == 0x00 {
				i.Version = 1 // IGMPv1 has a query length of 8 and MaxResp = 0
			} else {
				i.Version = 2 // IGMPv2 has a query length of 8 and MaxResp != 0
			}

			return decodingLayerDecoder(i, data, p)
		}

	case IGMPMembershipReportV3:
		i := &IGMP{Version: 3}
		return decodingLayerDecoder(i, data, p)

	case IGMPMembershipReportV1:
		i := &IGMPv1Orv2{Version: 1}
		return decodingLayerDecoder(i, data, p)

	case IGMPLeaveGroup, IGMPMembershipReportV2:
		// leave group and Query Report v2 used in IGMPv2 only.
		i := &IGMPv1Orv2{Version: 2}
		return decodingLayerDecoder(i, data, p)
	default:
	}

	return fmt.Errorf("Unable to determine IGMP type.")
}
<|endoftext|>


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

// flannel tests. tests assume flannel is using the 10.254.0.0/16 network.
// these tests should really assert no units failed during boot (such as flanneld)
// it is also unfortunate that we must retry, but starting
// early-docker -> flanneld -> docker ->docker0 may not be ready by the time we ssh in.
package flannel

import (
	"fmt"
	"net"
	"strings"

	"github.com/coreos/pkg/capnslog"

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

var (
	plog        = capnslog.NewPackageLogger("github.com/coreos/mantle", "kola/tests/flannel")
	flannelConf = `{
  "ignition": { "version": "2.0.0" },
  "systemd": {
    "units": [
      {
        "name": "etcd2.service",
        "enable": true,
        "dropins": [{
          "name": "metadata.conf",
          "contents": "[Unit]\nWants=coreos-metadata.service\nAfter=coreos-metadata.service\n\n[Service]\nEnvironmentFile=-/run/metadata/coreos\nExecStart=\nExecStart=/usr/bin/etcd2 --name=$name --discovery=$discovery --advertise-client-urls=http://$private_ipv4:2379 --initial-advertise-peer-urls=http://$private_ipv4:2380 --listen-client-urls=http://0.0.0.0:2379,http://0.0.0.0:4001 --listen-peer-urls=http://$private_ipv4:2380,http://$private_ipv4:7001"
        }]
      },
      {
        "name": "flanneld.service",
        "enable": true,
        "dropins": [{
          "name": "50-network-config.conf",
          "contents": "[Service]\nExecStartPre=/usr/bin/etcdctl set /coreos.com/network/config '{ \"Network\": \"10.254.0.0/16\", \"Backend\": {\"Type\": \"$type\"} }'"
        }]
      },
      {
        "name": "docker.service",
        "enable": true
      }
    ]
  }
}`
)

func init() {
	register.Register(&register.Test{
		Run:         udp,
		ClusterSize: 3,
		Name:        "coreos.flannel.udp",
		Platforms:   []string{"aws", "gce"},
		UserData:    strings.Replace(flannelConf, "$type", "udp", -1),
	})

	register.Register(&register.Test{
		Run:         vxlan,
		ClusterSize: 3,
		Name:        "coreos.flannel.vxlan",
		Platforms:   []string{"aws", "gce"},
		UserData:    strings.Replace(flannelConf, "$type", "vxlan", -1),
	})
}

// get docker bridge ip from a machine
func mach2bip(m platform.Machine, ifname string) (string, error) {
	// note the escaped % in awk.
	out, err := m.SSH(fmt.Sprintf(`/usr/lib/systemd/systemd-networkd-wait-online --interface=%s --timeout=60 ; ip -4 -o addr show dev %s primary | awk -F " +|/" '{printf "%%s", $4}'`, ifname, ifname))
	if err != nil {
		return "", err
	}

	// XXX(mischief): unfortunately `ip` does not return a nonzero status if the interface doesn't exist.
	if len(out) == 0 {
		return "", fmt.Errorf("interface %q doesn't exist?", ifname)
	}

	return string(out), nil
}

// ping sends icmp packets from machine a to b using the ping tool.
func ping(a, b platform.Machine, ifname string) error {
	srcip, err := mach2bip(a, ifname)
	if err != nil {
		return fmt.Errorf("failed to get docker bridge ip #1: %v", err)
	}

	dstip, err := mach2bip(b, ifname)
	if err != nil {
		return fmt.Errorf("failed to get docker bridge ip #2: %v", err)
	}

	// ensure the docker bridges have the right network
	_, ipnet, _ := net.ParseCIDR("10.254.0.0/16")
	if !ipnet.Contains(net.ParseIP(srcip)) || !ipnet.Contains(net.ParseIP(dstip)) {
		return fmt.Errorf("bridge ips (%s %s) not in flannel network (%s)", srcip, dstip, ipnet)
	}

	plog.Infof("ping from %s(%s) to %s(%s)", a.ID(), srcip, b.ID(), dstip)

	cmd := fmt.Sprintf("ping -c 10 -I %s %s", srcip, dstip)
	out, err := a.SSH(cmd)
	if err != nil {
		return fmt.Errorf("ping from %s to %s failed: %s: %v", a.ID(), b.ID(), out, err)
	}

	return nil
}

// UDP tests that flannel can send packets using the udp backend.
func udp(c cluster.TestCluster) error {
	machs := c.Machines()

	// Wait for all etcd cluster nodes to be ready.
	if err := etcd.GetClusterHealth(machs[0], len(machs)); err != nil {
		return fmt.Errorf("cluster health: %v", err)
	}

	return ping(machs[0], machs[2], "flannel0")
}

// VXLAN tests that flannel can send packets using the vxlan backend.
func vxlan(c cluster.TestCluster) error {
	machs := c.Machines()

	// Wait for all etcd cluster nodes to be ready.
	if err := etcd.GetClusterHealth(machs[0], len(machs)); err != nil {
		return fmt.Errorf("cluster health: %v", err)
	}

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

// flannel tests. tests assume flannel is using the 10.254.0.0/16 network.
// these tests should really assert no units failed during boot (such as flanneld)
// it is also unfortunate that we must retry, but starting
// early-docker -> flanneld -> docker ->docker0 may not be ready by the time we ssh in.
package flannel

import (
	"fmt"
	"net"
	"strings"

	"github.com/coreos/pkg/capnslog"

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

var (
	plog        = capnslog.NewPackageLogger("github.com/coreos/mantle", "kola/tests/flannel")
	flannelConf = `{
  "ignition": { "version": "2.0.0" },
  "systemd": {
    "units": [
      {
        "name": "etcd2.service",
        "enable": true,
        "dropins": [{
          "name": "metadata.conf",
          "contents": "[Unit]\nWants=coreos-metadata.service\nAfter=coreos-metadata.service\n\n[Service]\nEnvironmentFile=-/run/metadata/coreos\nExecStart=\nExecStart=/usr/bin/etcd2 --name=$name --discovery=$discovery --advertise-client-urls=http://$private_ipv4:2379 --initial-advertise-peer-urls=http://$private_ipv4:2380 --listen-client-urls=http://0.0.0.0:2379,http://0.0.0.0:4001 --listen-peer-urls=http://$private_ipv4:2380,http://$private_ipv4:7001"
        }]
      },
      {
        "name": "flanneld.service",
        "enable": true,
        "dropins": [{
          "name": "50-network-config.conf",
          "contents": "[Service]\nExecStartPre=/usr/bin/etcdctl set /coreos.com/network/config '{ \"Network\": \"10.254.0.0/16\", \"Backend\": {\"Type\": \"$type\"} }'"
        }]
      },
      {
        "name": "flannel-docker-opts.service",
        "dropins": [{
          "name": "retry.conf",
          "contents": "[Service]\nTimeoutStartSec=300\nExecStart=\nExecStart=/bin/sh -exc 'for try in 1 2 3 4 5 6 ; do /usr/lib/coreos/flannel-wrapper -d /run/flannel/flannel_docker_opts.env -i && break || sleep 10 ; try=fail ; done ; [ $try != fail ]'"
        }]
      },
      {
        "name": "docker.service",
        "enable": true
      }
    ]
  }
}`
)

func init() {
	register.Register(&register.Test{
		Run:         udp,
		ClusterSize: 3,
		Name:        "coreos.flannel.udp",
		Platforms:   []string{"aws", "gce"},
		UserData:    strings.Replace(flannelConf, "$type", "udp", -1),
	})

	register.Register(&register.Test{
		Run:         vxlan,
		ClusterSize: 3,
		Name:        "coreos.flannel.vxlan",
		Platforms:   []string{"aws", "gce"},
		UserData:    strings.Replace(flannelConf, "$type", "vxlan", -1),
	})
}

// get docker bridge ip from a machine
func mach2bip(m platform.Machine, ifname string) (string, error) {
	// note the escaped % in awk.
	out, err := m.SSH(fmt.Sprintf(`/usr/lib/systemd/systemd-networkd-wait-online --interface=%s --timeout=60 ; ip -4 -o addr show dev %s primary | awk -F " +|/" '{printf "%%s", $4}'`, ifname, ifname))
	if err != nil {
		return "", err
	}

	// XXX(mischief): unfortunately `ip` does not return a nonzero status if the interface doesn't exist.
	if len(out) == 0 {
		return "", fmt.Errorf("interface %q doesn't exist?", ifname)
	}

	return string(out), nil
}

// ping sends icmp packets from machine a to b using the ping tool.
func ping(a, b platform.Machine, ifname string) error {
	srcip, err := mach2bip(a, ifname)
	if err != nil {
		return fmt.Errorf("failed to get docker bridge ip #1: %v", err)
	}

	dstip, err := mach2bip(b, ifname)
	if err != nil {
		return fmt.Errorf("failed to get docker bridge ip #2: %v", err)
	}

	// ensure the docker bridges have the right network
	_, ipnet, _ := net.ParseCIDR("10.254.0.0/16")
	if !ipnet.Contains(net.ParseIP(srcip)) || !ipnet.Contains(net.ParseIP(dstip)) {
		return fmt.Errorf("bridge ips (%s %s) not in flannel network (%s)", srcip, dstip, ipnet)
	}

	plog.Infof("ping from %s(%s) to %s(%s)", a.ID(), srcip, b.ID(), dstip)

	cmd := fmt.Sprintf("ping -c 10 -I %s %s", srcip, dstip)
	out, err := a.SSH(cmd)
	if err != nil {
		return fmt.Errorf("ping from %s to %s failed: %s: %v", a.ID(), b.ID(), out, err)
	}

	return nil
}

// UDP tests that flannel can send packets using the udp backend.
func udp(c cluster.TestCluster) error {
	machs := c.Machines()

	// Wait for all etcd cluster nodes to be ready.
	if err := etcd.GetClusterHealth(machs[0], len(machs)); err != nil {
		return fmt.Errorf("cluster health: %v", err)
	}

	return ping(machs[0], machs[2], "flannel0")
}

// VXLAN tests that flannel can send packets using the vxlan backend.
func vxlan(c cluster.TestCluster) error {
	machs := c.Machines()

	// Wait for all etcd cluster nodes to be ready.
	if err := etcd.GetClusterHealth(machs[0], len(machs)); err != nil {
		return fmt.Errorf("cluster health: %v", err)
	}

	return ping(machs[0], machs[2], "flannel.1")
}
<|endoftext|>