<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The time package provides functionality for measuring and
// displaying time.
package time

import (
	"os";
)

// Seconds reports the number of seconds since the Unix epoch,
// January 1, 1970 00:00:00 UTC.
func Seconds() int64 {
	sec, _, err := os.Time();
	if err != nil {
		panic("time: os.Time: ", err.String());
	}
	return sec
}

// Nanoseconds reports the number of nanoseconds since the Unix epoch,
// January 1, 1970 00:00:00 UTC.
func Nanoseconds() int64 {
	sec, nsec, err := os.Time();
	if err != nil {
		panic("time: os.Time: ", err.String());
	}
	return sec*1e9 + nsec
}

// Days of the week.
const (
	Sunday = iota;
	Monday;
	Tuesday;
	Wednesday;
	Thursday;
	Friday;
	Saturday;
)

// Time is the struct representing a parsed time value.
type Time struct {
	Year int64;	// 2008 is 2008
	Month, Day int;	// Sep-17 is 9, 17
	Hour, Minute, Second int;	// 10:43:12 is 10, 43, 12
	Weekday int;		// Sunday, Monday, ...
	ZoneOffset int;	// seconds west of UTC
	Zone string;
}

var nonleapyear = []int{
	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
}
var leapyear = []int{
	31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
}

func months(year int64) []int {
	if year%4 == 0 && (year%100 != 0 || year%400 == 0) {
		return leapyear
	}
	return nonleapyear
}

const (
	secondsPerDay = 24*60*60;

	daysPer400Years = 365*400+97;
	daysPer100Years = 365*100+24;
	daysPer4Years = 365*4+1;

	days1970To2001 = 31*365+8;
)

// SecondsToUTC converts sec, in number of seconds since the Unix epoch,
// into a parsed Time value in the UTC time zone.
func SecondsToUTC(sec int64) *Time {
	t := new(Time);

	// Split into time and day.
	day := sec/secondsPerDay;
	sec -= day*secondsPerDay;
	if sec < 0 {
		day--;
		sec += secondsPerDay
	}

	// Time
	t.Hour = int(sec/3600);
	t.Minute = int((sec/60)%60);
	t.Second = int(sec%60);

	// Day 0 = January 1, 1970 was a Thursday
	t.Weekday = int((day + Thursday) % 7);
	if t.Weekday < 0 {
		t.Weekday += 7
	}

	// Change day from 0 = 1970 to 0 = 2001,
	// to make leap year calculations easier
	// (2001 begins 4-, 100-, and 400-year cycles ending in a leap year.)
	day -= days1970To2001;

	year := int64(2001);
	if day < 0 {
		// Go back enough 400 year cycles to make day positive.
		n := -day/daysPer400Years + 1;
		year -= 400*n;
		day += daysPer400Years*n;
	} else {
		// Cut off 400 year cycles.
		n := day/daysPer400Years;
		year += 400*n;
		day -= daysPer400Years*n;
	}

	// Cut off 100-year cycles
	n := day/daysPer100Years;
	year += 100*n;
	day -= daysPer100Years*n;

	// Cut off 4-year cycles
	n = day/daysPer4Years;
	year += 4*n;
	day -= daysPer4Years*n;

	// Cut off non-leap years.
	n = day/365;
	year += n;
	day -= 365*n;

	t.Year = year;

	// If someone ever needs yearday,
	// tyearday = day (+1?)

	months := months(year);
	var m int;
	yday := int(day);
	for m = 0; m < 12 && yday >= months[m]; m++ {
		yday -= months[m]
	}
	t.Month = m+1;
	t.Day = yday+1;
	t.Zone = "UTC";

	return t;
}

// UTC returns the current time as a parsed Time value in the UTC time zone.
func UTC() *Time {
	return SecondsToUTC(Seconds())
}

// SecondsToLocalTime converts sec, in number of seconds since the Unix epoch,
// into a parsed Time value in the local time zone.
func SecondsToLocalTime(sec int64) *Time {
	z, offset := lookupTimezone(sec);
	t := SecondsToUTC(sec+int64(offset));
	t.Zone = z;
	t.ZoneOffset = offset;
	return t
}

// LocalTime returns the current time as a parsed Time value in the local time zone.
func LocalTime() *Time {
	return SecondsToLocalTime(Seconds())
}

// Seconds returns the number of seconds since January 1, 1970 represented by the
// parsed Time value.
func (t *Time) Seconds() int64 {
	// First, accumulate days since January 1, 2001.
	// Using 2001 instead of 1970 makes the leap-year
	// handling easier (see SecondsToUTC), because
	// it is at the beginning of the 4-, 100-, and 400-year cycles.
	day := int64(0);

	// Rewrite year to be >= 2001.
	year := t.Year;
	if year < 2001 {
		n := (2001 - year)/400 + 1;
		year += 400*n;
		day -= daysPer400Years*n;
	}

	// Add in days from 400-year cycles.
	n := (year - 2001) / 400;
	year -= 400*n;
	day += daysPer400Years*n;

	// Add in 100-year cycles.
	n = (year - 2001) / 100;
	year -= 100*n;
	day += daysPer100Years*n;

	// Add in 4-year cycles.
	n = (year - 2001) / 4;
	year -= 4*n;
	day += daysPer4Years*n;

	// Add in non-leap years.
	n = year - 2001;
	day += 365*n;

	// Add in days this year.
	months := months(t.Year);
	for m := 0; m < t.Month-1; m++ {
		day += int64(months[m])
	}
	day += int64(t.Day - 1);

	// Convert days to seconds since January 1, 2001.
	sec := day * secondsPerDay;

	// Add in time elapsed today.
	sec += int64(t.Hour) * 3600;
	sec += int64(t.Minute) * 60;
	sec += int64(t.Second);

	// Convert from seconds since 2001 to seconds since 1970.
	sec += days1970To2001 * secondsPerDay;

	// Account for local time zone.
	sec -= int64(t.ZoneOffset);
	return sec
}

var longDayNames = []string{
	"Sunday",
	"Monday",
	"Tuesday",
	"Wednesday",
	"Thursday",
	"Friday",
	"Saturday"
}

var shortDayNames = []string{
	"Sun",
	"Mon",
	"Tue",
	"Wed",
	"Thu",
	"Fri",
	"Sat"
}

var shortMonthNames = []string{
	"---",
	"Jan",
	"Feb",
	"Mar",
	"Apr",
	"May",
	"Jun",
	"Jul",
	"Aug",
	"Sep",
	"Oct",
	"Nov",
	"Dec"
}

func copy(dst []byte, s string) {
	for i := 0; i < len(s); i++ {
		dst[i] = s[i]
	}
}

func decimal(dst []byte, n int) {
	if n < 0 {
		n = 0
	}
	for i := len(dst)-1; i >= 0; i-- {
		dst[i] = byte(n%10 + '0');
		n /= 10
	}
}

func addString(buf []byte, bp int, s string) int {
	n := len(s);
	copy(buf[bp:bp+n], s);
	return bp+n
}

// Just enough of strftime to implement the date formats below.
// Not exported.
func format(t *Time, fmt string) string {
	buf := make([]byte, 128);
	bp := 0;

	for i := 0; i < len(fmt); i++ {
		if fmt[i] == '%' {
			i++;
			switch fmt[i] {
			case 'A':	// %A full weekday name
				bp = addString(buf, bp, longDayNames[t.Weekday]);
			case 'a':	// %a abbreviated weekday name
				bp = addString(buf, bp, shortDayNames[t.Weekday]);
			case 'b':	// %b abbreviated month name
				bp = addString(buf, bp, shortMonthNames[t.Month]);
			case 'd':	// %d day of month (01-31)
				decimal(buf[bp:bp+2], t.Day);
				bp += 2;
			case 'e':	// %e day of month ( 1-31)
				if t.Day >= 10 {
					decimal(buf[bp:bp+2], t.Day)
				} else {
					buf[bp] = ' ';
					buf[bp+1] = byte(t.Day + '0')
				}
				bp += 2;
			case 'H':	// %H hour 00-23
				decimal(buf[bp:bp+2], t.Hour);
				bp += 2;
			case 'M':	// %M minute 00-59
				decimal(buf[bp:bp+2], t.Minute);
				bp += 2;
			case 'S':	// %S second 00-59
				decimal(buf[bp:bp+2], t.Second);
				bp += 2;
			case 'Y':	// %Y year 2008
				decimal(buf[bp:bp+4], int(t.Year));
				bp += 4;
			case 'y':	// %y year 08
				decimal(buf[bp:bp+2], int(t.Year%100));
				bp += 2;
			case 'Z':
				bp = addString(buf, bp, t.Zone);
			default:
				buf[bp] = '%';
				buf[bp+1] = fmt[i];
				bp += 2
			}
		} else {
			buf[bp] = fmt[i];
			bp++;
		}
	}
	return string(buf[0:bp])
}

// Asctime formats the parsed time value in the style of
// ANSI C asctime: Sun Nov  6 08:49:37 1994
func (t *Time) Asctime() string {
	return format(t, "%a %b %e %H:%M:%S %Y")
}

// RFC850 formats the parsed time value in the style of
// RFC 850: Sunday, 06-Nov-94 08:49:37 UTC
func (t *Time) RFC850() string {
	return format(t, "%A, %d-%b-%y %H:%M:%S %Z")
}

// RFC1123 formats the parsed time value in the style of
// RFC 1123: Sun, 06 Nov 1994 08:49:37 UTC
func (t *Time) RFC1123() string {
	return format(t, "%a, %d %b %Y %H:%M:%S %Z")
}

// String formats the parsed time value in the style of
// date(1) - Sun Nov  6 08:49:37 UTC 1994
func (t *Time) String() string {
	return format(t, "%a %b %e %H:%M:%S %Z %Y")
}
<commit_msg>Change description of time.Time.ZoneOffset to specify east is +ve.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The time package provides functionality for measuring and
// displaying time.
package time

import (
	"os";
)

// Seconds reports the number of seconds since the Unix epoch,
// January 1, 1970 00:00:00 UTC.
func Seconds() int64 {
	sec, _, err := os.Time();
	if err != nil {
		panic("time: os.Time: ", err.String());
	}
	return sec
}

// Nanoseconds reports the number of nanoseconds since the Unix epoch,
// January 1, 1970 00:00:00 UTC.
func Nanoseconds() int64 {
	sec, nsec, err := os.Time();
	if err != nil {
		panic("time: os.Time: ", err.String());
	}
	return sec*1e9 + nsec
}

// Days of the week.
const (
	Sunday = iota;
	Monday;
	Tuesday;
	Wednesday;
	Thursday;
	Friday;
	Saturday;
)

// Time is the struct representing a parsed time value.
type Time struct {
	Year int64;	// 2008 is 2008
	Month, Day int;	// Sep-17 is 9, 17
	Hour, Minute, Second int;	// 10:43:12 is 10, 43, 12
	Weekday int;		// Sunday, Monday, ...
	ZoneOffset int;	// seconds east of UTC
	Zone string;
}

var nonleapyear = []int{
	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
}
var leapyear = []int{
	31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
}

func months(year int64) []int {
	if year%4 == 0 && (year%100 != 0 || year%400 == 0) {
		return leapyear
	}
	return nonleapyear
}

const (
	secondsPerDay = 24*60*60;

	daysPer400Years = 365*400+97;
	daysPer100Years = 365*100+24;
	daysPer4Years = 365*4+1;

	days1970To2001 = 31*365+8;
)

// SecondsToUTC converts sec, in number of seconds since the Unix epoch,
// into a parsed Time value in the UTC time zone.
func SecondsToUTC(sec int64) *Time {
	t := new(Time);

	// Split into time and day.
	day := sec/secondsPerDay;
	sec -= day*secondsPerDay;
	if sec < 0 {
		day--;
		sec += secondsPerDay
	}

	// Time
	t.Hour = int(sec/3600);
	t.Minute = int((sec/60)%60);
	t.Second = int(sec%60);

	// Day 0 = January 1, 1970 was a Thursday
	t.Weekday = int((day + Thursday) % 7);
	if t.Weekday < 0 {
		t.Weekday += 7
	}

	// Change day from 0 = 1970 to 0 = 2001,
	// to make leap year calculations easier
	// (2001 begins 4-, 100-, and 400-year cycles ending in a leap year.)
	day -= days1970To2001;

	year := int64(2001);
	if day < 0 {
		// Go back enough 400 year cycles to make day positive.
		n := -day/daysPer400Years + 1;
		year -= 400*n;
		day += daysPer400Years*n;
	} else {
		// Cut off 400 year cycles.
		n := day/daysPer400Years;
		year += 400*n;
		day -= daysPer400Years*n;
	}

	// Cut off 100-year cycles
	n := day/daysPer100Years;
	year += 100*n;
	day -= daysPer100Years*n;

	// Cut off 4-year cycles
	n = day/daysPer4Years;
	year += 4*n;
	day -= daysPer4Years*n;

	// Cut off non-leap years.
	n = day/365;
	year += n;
	day -= 365*n;

	t.Year = year;

	// If someone ever needs yearday,
	// tyearday = day (+1?)

	months := months(year);
	var m int;
	yday := int(day);
	for m = 0; m < 12 && yday >= months[m]; m++ {
		yday -= months[m]
	}
	t.Month = m+1;
	t.Day = yday+1;
	t.Zone = "UTC";

	return t;
}

// UTC returns the current time as a parsed Time value in the UTC time zone.
func UTC() *Time {
	return SecondsToUTC(Seconds())
}

// SecondsToLocalTime converts sec, in number of seconds since the Unix epoch,
// into a parsed Time value in the local time zone.
func SecondsToLocalTime(sec int64) *Time {
	z, offset := lookupTimezone(sec);
	t := SecondsToUTC(sec+int64(offset));
	t.Zone = z;
	t.ZoneOffset = offset;
	return t
}

// LocalTime returns the current time as a parsed Time value in the local time zone.
func LocalTime() *Time {
	return SecondsToLocalTime(Seconds())
}

// Seconds returns the number of seconds since January 1, 1970 represented by the
// parsed Time value.
func (t *Time) Seconds() int64 {
	// First, accumulate days since January 1, 2001.
	// Using 2001 instead of 1970 makes the leap-year
	// handling easier (see SecondsToUTC), because
	// it is at the beginning of the 4-, 100-, and 400-year cycles.
	day := int64(0);

	// Rewrite year to be >= 2001.
	year := t.Year;
	if year < 2001 {
		n := (2001 - year)/400 + 1;
		year += 400*n;
		day -= daysPer400Years*n;
	}

	// Add in days from 400-year cycles.
	n := (year - 2001) / 400;
	year -= 400*n;
	day += daysPer400Years*n;

	// Add in 100-year cycles.
	n = (year - 2001) / 100;
	year -= 100*n;
	day += daysPer100Years*n;

	// Add in 4-year cycles.
	n = (year - 2001) / 4;
	year -= 4*n;
	day += daysPer4Years*n;

	// Add in non-leap years.
	n = year - 2001;
	day += 365*n;

	// Add in days this year.
	months := months(t.Year);
	for m := 0; m < t.Month-1; m++ {
		day += int64(months[m])
	}
	day += int64(t.Day - 1);

	// Convert days to seconds since January 1, 2001.
	sec := day * secondsPerDay;

	// Add in time elapsed today.
	sec += int64(t.Hour) * 3600;
	sec += int64(t.Minute) * 60;
	sec += int64(t.Second);

	// Convert from seconds since 2001 to seconds since 1970.
	sec += days1970To2001 * secondsPerDay;

	// Account for local time zone.
	sec -= int64(t.ZoneOffset);
	return sec
}

var longDayNames = []string{
	"Sunday",
	"Monday",
	"Tuesday",
	"Wednesday",
	"Thursday",
	"Friday",
	"Saturday"
}

var shortDayNames = []string{
	"Sun",
	"Mon",
	"Tue",
	"Wed",
	"Thu",
	"Fri",
	"Sat"
}

var shortMonthNames = []string{
	"---",
	"Jan",
	"Feb",
	"Mar",
	"Apr",
	"May",
	"Jun",
	"Jul",
	"Aug",
	"Sep",
	"Oct",
	"Nov",
	"Dec"
}

func copy(dst []byte, s string) {
	for i := 0; i < len(s); i++ {
		dst[i] = s[i]
	}
}

func decimal(dst []byte, n int) {
	if n < 0 {
		n = 0
	}
	for i := len(dst)-1; i >= 0; i-- {
		dst[i] = byte(n%10 + '0');
		n /= 10
	}
}

func addString(buf []byte, bp int, s string) int {
	n := len(s);
	copy(buf[bp:bp+n], s);
	return bp+n
}

// Just enough of strftime to implement the date formats below.
// Not exported.
func format(t *Time, fmt string) string {
	buf := make([]byte, 128);
	bp := 0;

	for i := 0; i < len(fmt); i++ {
		if fmt[i] == '%' {
			i++;
			switch fmt[i] {
			case 'A':	// %A full weekday name
				bp = addString(buf, bp, longDayNames[t.Weekday]);
			case 'a':	// %a abbreviated weekday name
				bp = addString(buf, bp, shortDayNames[t.Weekday]);
			case 'b':	// %b abbreviated month name
				bp = addString(buf, bp, shortMonthNames[t.Month]);
			case 'd':	// %d day of month (01-31)
				decimal(buf[bp:bp+2], t.Day);
				bp += 2;
			case 'e':	// %e day of month ( 1-31)
				if t.Day >= 10 {
					decimal(buf[bp:bp+2], t.Day)
				} else {
					buf[bp] = ' ';
					buf[bp+1] = byte(t.Day + '0')
				}
				bp += 2;
			case 'H':	// %H hour 00-23
				decimal(buf[bp:bp+2], t.Hour);
				bp += 2;
			case 'M':	// %M minute 00-59
				decimal(buf[bp:bp+2], t.Minute);
				bp += 2;
			case 'S':	// %S second 00-59
				decimal(buf[bp:bp+2], t.Second);
				bp += 2;
			case 'Y':	// %Y year 2008
				decimal(buf[bp:bp+4], int(t.Year));
				bp += 4;
			case 'y':	// %y year 08
				decimal(buf[bp:bp+2], int(t.Year%100));
				bp += 2;
			case 'Z':
				bp = addString(buf, bp, t.Zone);
			default:
				buf[bp] = '%';
				buf[bp+1] = fmt[i];
				bp += 2
			}
		} else {
			buf[bp] = fmt[i];
			bp++;
		}
	}
	return string(buf[0:bp])
}

// Asctime formats the parsed time value in the style of
// ANSI C asctime: Sun Nov  6 08:49:37 1994
func (t *Time) Asctime() string {
	return format(t, "%a %b %e %H:%M:%S %Y")
}

// RFC850 formats the parsed time value in the style of
// RFC 850: Sunday, 06-Nov-94 08:49:37 UTC
func (t *Time) RFC850() string {
	return format(t, "%A, %d-%b-%y %H:%M:%S %Z")
}

// RFC1123 formats the parsed time value in the style of
// RFC 1123: Sun, 06 Nov 1994 08:49:37 UTC
func (t *Time) RFC1123() string {
	return format(t, "%a, %d %b %Y %H:%M:%S %Z")
}

// String formats the parsed time value in the style of
// date(1) - Sun Nov  6 08:49:37 UTC 1994
func (t *Time) String() string {
	return format(t, "%a %b %e %H:%M:%S %Z %Y")
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package utf8 implements functions and constants to support text encoded in
// UTF-8. This package calls a Unicode character a rune for brevity.
package utf8

import "unicode" // only needed for a couple of constants

// Numbers fundamental to the encoding.
const (
	RuneError = unicode.ReplacementChar // the "error" Rune or "replacement character".
	RuneSelf  = 0x80                    // characters below Runeself are represented as themselves in a single byte.
	UTFMax    = 4                       // maximum number of bytes of a UTF-8 encoded Unicode character.
)

const (
	_T1 = 0x00 // 0000 0000
	_Tx = 0x80 // 1000 0000
	_T2 = 0xC0 // 1100 0000
	_T3 = 0xE0 // 1110 0000
	_T4 = 0xF0 // 1111 0000
	_T5 = 0xF8 // 1111 1000

	_Maskx = 0x3F // 0011 1111
	_Mask2 = 0x1F // 0001 1111
	_Mask3 = 0x0F // 0000 1111
	_Mask4 = 0x07 // 0000 0111

	_Rune1Max = 1<<7 - 1
	_Rune2Max = 1<<11 - 1
	_Rune3Max = 1<<16 - 1
	_Rune4Max = 1<<21 - 1
)

func decodeRuneInternal(p []byte) (rune, size int, short bool) {
	n := len(p)
	if n < 1 {
		return RuneError, 0, true
	}
	c0 := p[0]

	// 1-byte, 7-bit sequence?
	if c0 < _Tx {
		return int(c0), 1, false
	}

	// unexpected continuation byte?
	if c0 < _T2 {
		return RuneError, 1, false
	}

	// need first continuation byte
	if n < 2 {
		return RuneError, 1, true
	}
	c1 := p[1]
	if c1 < _Tx || _T2 <= c1 {
		return RuneError, 1, false
	}

	// 2-byte, 11-bit sequence?
	if c0 < _T3 {
		rune = int(c0&_Mask2)<<6 | int(c1&_Maskx)
		if rune <= _Rune1Max {
			return RuneError, 1, false
		}
		return rune, 2, false
	}

	// need second continuation byte
	if n < 3 {
		return RuneError, 1, true
	}
	c2 := p[2]
	if c2 < _Tx || _T2 <= c2 {
		return RuneError, 1, false
	}

	// 3-byte, 16-bit sequence?
	if c0 < _T4 {
		rune = int(c0&_Mask3)<<12 | int(c1&_Maskx)<<6 | int(c2&_Maskx)
		if rune <= _Rune2Max {
			return RuneError, 1, false
		}
		return rune, 3, false
	}

	// need third continuation byte
	if n < 4 {
		return RuneError, 1, true
	}
	c3 := p[3]
	if c3 < _Tx || _T2 <= c3 {
		return RuneError, 1, false
	}

	// 4-byte, 21-bit sequence?
	if c0 < _T5 {
		rune = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)
		if rune <= _Rune3Max {
			return RuneError, 1, false
		}
		return rune, 4, false
	}

	// error
	return RuneError, 1, false
}

func decodeRuneInStringInternal(s string) (rune, size int, short bool) {
	n := len(s)
	if n < 1 {
		return RuneError, 0, true
	}
	c0 := s[0]

	// 1-byte, 7-bit sequence?
	if c0 < _Tx {
		return int(c0), 1, false
	}

	// unexpected continuation byte?
	if c0 < _T2 {
		return RuneError, 1, false
	}

	// need first continuation byte
	if n < 2 {
		return RuneError, 1, true
	}
	c1 := s[1]
	if c1 < _Tx || _T2 <= c1 {
		return RuneError, 1, false
	}

	// 2-byte, 11-bit sequence?
	if c0 < _T3 {
		rune = int(c0&_Mask2)<<6 | int(c1&_Maskx)
		if rune <= _Rune1Max {
			return RuneError, 1, false
		}
		return rune, 2, false
	}

	// need second continuation byte
	if n < 3 {
		return RuneError, 1, true
	}
	c2 := s[2]
	if c2 < _Tx || _T2 <= c2 {
		return RuneError, 1, false
	}

	// 3-byte, 16-bit sequence?
	if c0 < _T4 {
		rune = int(c0&_Mask3)<<12 | int(c1&_Maskx)<<6 | int(c2&_Maskx)
		if rune <= _Rune2Max {
			return RuneError, 1, false
		}
		return rune, 3, false
	}

	// need third continuation byte
	if n < 4 {
		return RuneError, 1, true
	}
	c3 := s[3]
	if c3 < _Tx || _T2 <= c3 {
		return RuneError, 1, false
	}

	// 4-byte, 21-bit sequence?
	if c0 < _T5 {
		rune = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)
		if rune <= _Rune3Max {
			return RuneError, 1, false
		}
		return rune, 4, false
	}

	// error
	return RuneError, 1, false
}

// FullRune reports whether the bytes in p begin with a full UTF-8 encoding of a rune.
// An invalid encoding is considered a full Rune since it will convert as a width-1 error rune.
func FullRune(p []byte) bool {
	_, _, short := decodeRuneInternal(p)
	return !short
}

// FullRuneInString is like FullRune but its input is a string.
func FullRuneInString(s string) bool {
	_, _, short := decodeRuneInStringInternal(s)
	return !short
}

// DecodeRune unpacks the first UTF-8 encoding in p and returns the rune and its width in bytes.
func DecodeRune(p []byte) (rune, size int) {
	rune, size, _ = decodeRuneInternal(p)
	return
}

// DecodeRuneInString is like DecodeRune but its input is a string.
func DecodeRuneInString(s string) (rune, size int) {
	rune, size, _ = decodeRuneInStringInternal(s)
	return
}

// DecodeLastRune unpacks the last UTF-8 encoding in p
// and returns the rune and its width in bytes.
func DecodeLastRune(p []byte) (rune, size int) {
	end := len(p)
	if end == 0 {
		return RuneError, 0
	}
	start := end - 1
	rune = int(p[start])
	if rune < RuneSelf {
		return rune, 1
	}
	// guard against O(n^2) behavior when traversing
	// backwards through strings with long sequences of
	// invalid UTF-8.
	lim := end - UTFMax
	if lim < 0 {
		lim = 0
	}
	for start--; start >= lim; start-- {
		if RuneStart(p[start]) {
			break
		}
	}
	if start < 0 {
		start = 0
	}
	rune, size = DecodeRune(p[start:end])
	if start+size != end {
		return RuneError, 1
	}
	return rune, size
}

// DecodeLastRuneInString is like DecodeLastRune but its input is a string.
func DecodeLastRuneInString(s string) (rune, size int) {
	end := len(s)
	if end == 0 {
		return RuneError, 0
	}
	start := end - 1
	rune = int(s[start])
	if rune < RuneSelf {
		return rune, 1
	}
	// guard against O(n^2) behavior when traversing
	// backwards through strings with long sequences of
	// invalid UTF-8.
	lim := end - UTFMax
	if lim < 0 {
		lim = 0
	}
	for start--; start >= lim; start-- {
		if RuneStart(s[start]) {
			break
		}
	}
	if start < 0 {
		start = 0
	}
	rune, size = DecodeRuneInString(s[start:end])
	if start+size != end {
		return RuneError, 1
	}
	return rune, size
}

// RuneLen returns the number of bytes required to encode the rune.
func RuneLen(rune int) int {
	switch {
	case rune <= _Rune1Max:
		return 1
	case rune <= _Rune2Max:
		return 2
	case rune <= _Rune3Max:
		return 3
	case rune <= _Rune4Max:
		return 4
	}
	return -1
}

// EncodeRune writes into p (which must be large enough) the UTF-8 encoding of the rune.
// It returns the number of bytes written.
func EncodeRune(p []byte, rune int) int {
	// Negative values are erroneous.  Making it unsigned addresses the problem.
	r := uint(rune)

	if r <= _Rune1Max {
		p[0] = byte(r)
		return 1
	}

	if r <= _Rune2Max {
		p[0] = _T2 | byte(r>>6)
		p[1] = _Tx | byte(r)&_Maskx
		return 2
	}

	if r > unicode.MaxRune {
		r = RuneError
	}

	if r <= _Rune3Max {
		p[0] = _T3 | byte(r>>12)
		p[1] = _Tx | byte(r>>6)&_Maskx
		p[2] = _Tx | byte(r)&_Maskx
		return 3
	}

	p[0] = _T4 | byte(r>>18)
	p[1] = _Tx | byte(r>>12)&_Maskx
	p[2] = _Tx | byte(r>>6)&_Maskx
	p[3] = _Tx | byte(r)&_Maskx
	return 4
}

// RuneCount returns the number of runes in p.  Erroneous and short
// encodings are treated as single runes of width 1 byte.
func RuneCount(p []byte) int {
	i := 0
	var n int
	for n = 0; i < len(p); n++ {
		if p[i] < RuneSelf {
			i++
		} else {
			_, size := DecodeRune(p[i:])
			i += size
		}
	}
	return n
}

// RuneCountInString is like RuneCount but its input is a string.
func RuneCountInString(s string) (n int) {
	for _ = range s {
		n++
	}
	return
}

// RuneStart reports whether the byte could be the first byte of
// an encoded rune.  Second and subsequent bytes always have the top
// two bits set to 10.
func RuneStart(b byte) bool { return b&0xC0 != 0x80 }
<commit_msg>utf8: rename some internal constants to remove leading underscores. How quaint.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package utf8 implements functions and constants to support text encoded in
// UTF-8. This package calls a Unicode character a rune for brevity.
package utf8

import "unicode" // only needed for a couple of constants

// Numbers fundamental to the encoding.
const (
	RuneError = unicode.ReplacementChar // the "error" Rune or "replacement character".
	RuneSelf  = 0x80                    // characters below Runeself are represented as themselves in a single byte.
	UTFMax    = 4                       // maximum number of bytes of a UTF-8 encoded Unicode character.
)

const (
	t1 = 0x00 // 0000 0000
	tx = 0x80 // 1000 0000
	t2 = 0xC0 // 1100 0000
	t3 = 0xE0 // 1110 0000
	t4 = 0xF0 // 1111 0000
	t5 = 0xF8 // 1111 1000

	maskx = 0x3F // 0011 1111
	mask2 = 0x1F // 0001 1111
	mask3 = 0x0F // 0000 1111
	mask4 = 0x07 // 0000 0111

	rune1Max = 1<<7 - 1
	rune2Max = 1<<11 - 1
	rune3Max = 1<<16 - 1
	rune4Max = 1<<21 - 1
)

func decodeRuneInternal(p []byte) (rune, size int, short bool) {
	n := len(p)
	if n < 1 {
		return RuneError, 0, true
	}
	c0 := p[0]

	// 1-byte, 7-bit sequence?
	if c0 < tx {
		return int(c0), 1, false
	}

	// unexpected continuation byte?
	if c0 < t2 {
		return RuneError, 1, false
	}

	// need first continuation byte
	if n < 2 {
		return RuneError, 1, true
	}
	c1 := p[1]
	if c1 < tx || t2 <= c1 {
		return RuneError, 1, false
	}

	// 2-byte, 11-bit sequence?
	if c0 < t3 {
		rune = int(c0&mask2)<<6 | int(c1&maskx)
		if rune <= rune1Max {
			return RuneError, 1, false
		}
		return rune, 2, false
	}

	// need second continuation byte
	if n < 3 {
		return RuneError, 1, true
	}
	c2 := p[2]
	if c2 < tx || t2 <= c2 {
		return RuneError, 1, false
	}

	// 3-byte, 16-bit sequence?
	if c0 < t4 {
		rune = int(c0&mask3)<<12 | int(c1&maskx)<<6 | int(c2&maskx)
		if rune <= rune2Max {
			return RuneError, 1, false
		}
		return rune, 3, false
	}

	// need third continuation byte
	if n < 4 {
		return RuneError, 1, true
	}
	c3 := p[3]
	if c3 < tx || t2 <= c3 {
		return RuneError, 1, false
	}

	// 4-byte, 21-bit sequence?
	if c0 < t5 {
		rune = int(c0&mask4)<<18 | int(c1&maskx)<<12 | int(c2&maskx)<<6 | int(c3&maskx)
		if rune <= rune3Max {
			return RuneError, 1, false
		}
		return rune, 4, false
	}

	// error
	return RuneError, 1, false
}

func decodeRuneInStringInternal(s string) (rune, size int, short bool) {
	n := len(s)
	if n < 1 {
		return RuneError, 0, true
	}
	c0 := s[0]

	// 1-byte, 7-bit sequence?
	if c0 < tx {
		return int(c0), 1, false
	}

	// unexpected continuation byte?
	if c0 < t2 {
		return RuneError, 1, false
	}

	// need first continuation byte
	if n < 2 {
		return RuneError, 1, true
	}
	c1 := s[1]
	if c1 < tx || t2 <= c1 {
		return RuneError, 1, false
	}

	// 2-byte, 11-bit sequence?
	if c0 < t3 {
		rune = int(c0&mask2)<<6 | int(c1&maskx)
		if rune <= rune1Max {
			return RuneError, 1, false
		}
		return rune, 2, false
	}

	// need second continuation byte
	if n < 3 {
		return RuneError, 1, true
	}
	c2 := s[2]
	if c2 < tx || t2 <= c2 {
		return RuneError, 1, false
	}

	// 3-byte, 16-bit sequence?
	if c0 < t4 {
		rune = int(c0&mask3)<<12 | int(c1&maskx)<<6 | int(c2&maskx)
		if rune <= rune2Max {
			return RuneError, 1, false
		}
		return rune, 3, false
	}

	// need third continuation byte
	if n < 4 {
		return RuneError, 1, true
	}
	c3 := s[3]
	if c3 < tx || t2 <= c3 {
		return RuneError, 1, false
	}

	// 4-byte, 21-bit sequence?
	if c0 < t5 {
		rune = int(c0&mask4)<<18 | int(c1&maskx)<<12 | int(c2&maskx)<<6 | int(c3&maskx)
		if rune <= rune3Max {
			return RuneError, 1, false
		}
		return rune, 4, false
	}

	// error
	return RuneError, 1, false
}

// FullRune reports whether the bytes in p begin with a full UTF-8 encoding of a rune.
// An invalid encoding is considered a full Rune since it will convert as a width-1 error rune.
func FullRune(p []byte) bool {
	_, _, short := decodeRuneInternal(p)
	return !short
}

// FullRuneInString is like FullRune but its input is a string.
func FullRuneInString(s string) bool {
	_, _, short := decodeRuneInStringInternal(s)
	return !short
}

// DecodeRune unpacks the first UTF-8 encoding in p and returns the rune and its width in bytes.
func DecodeRune(p []byte) (rune, size int) {
	rune, size, _ = decodeRuneInternal(p)
	return
}

// DecodeRuneInString is like DecodeRune but its input is a string.
func DecodeRuneInString(s string) (rune, size int) {
	rune, size, _ = decodeRuneInStringInternal(s)
	return
}

// DecodeLastRune unpacks the last UTF-8 encoding in p
// and returns the rune and its width in bytes.
func DecodeLastRune(p []byte) (rune, size int) {
	end := len(p)
	if end == 0 {
		return RuneError, 0
	}
	start := end - 1
	rune = int(p[start])
	if rune < RuneSelf {
		return rune, 1
	}
	// guard against O(n^2) behavior when traversing
	// backwards through strings with long sequences of
	// invalid UTF-8.
	lim := end - UTFMax
	if lim < 0 {
		lim = 0
	}
	for start--; start >= lim; start-- {
		if RuneStart(p[start]) {
			break
		}
	}
	if start < 0 {
		start = 0
	}
	rune, size = DecodeRune(p[start:end])
	if start+size != end {
		return RuneError, 1
	}
	return rune, size
}

// DecodeLastRuneInString is like DecodeLastRune but its input is a string.
func DecodeLastRuneInString(s string) (rune, size int) {
	end := len(s)
	if end == 0 {
		return RuneError, 0
	}
	start := end - 1
	rune = int(s[start])
	if rune < RuneSelf {
		return rune, 1
	}
	// guard against O(n^2) behavior when traversing
	// backwards through strings with long sequences of
	// invalid UTF-8.
	lim := end - UTFMax
	if lim < 0 {
		lim = 0
	}
	for start--; start >= lim; start-- {
		if RuneStart(s[start]) {
			break
		}
	}
	if start < 0 {
		start = 0
	}
	rune, size = DecodeRuneInString(s[start:end])
	if start+size != end {
		return RuneError, 1
	}
	return rune, size
}

// RuneLen returns the number of bytes required to encode the rune.
func RuneLen(rune int) int {
	switch {
	case rune <= rune1Max:
		return 1
	case rune <= rune2Max:
		return 2
	case rune <= rune3Max:
		return 3
	case rune <= rune4Max:
		return 4
	}
	return -1
}

// EncodeRune writes into p (which must be large enough) the UTF-8 encoding of the rune.
// It returns the number of bytes written.
func EncodeRune(p []byte, rune int) int {
	// Negative values are erroneous.  Making it unsigned addresses the problem.
	r := uint(rune)

	if r <= rune1Max {
		p[0] = byte(r)
		return 1
	}

	if r <= rune2Max {
		p[0] = t2 | byte(r>>6)
		p[1] = tx | byte(r)&maskx
		return 2
	}

	if r > unicode.MaxRune {
		r = RuneError
	}

	if r <= rune3Max {
		p[0] = t3 | byte(r>>12)
		p[1] = tx | byte(r>>6)&maskx
		p[2] = tx | byte(r)&maskx
		return 3
	}

	p[0] = t4 | byte(r>>18)
	p[1] = tx | byte(r>>12)&maskx
	p[2] = tx | byte(r>>6)&maskx
	p[3] = tx | byte(r)&maskx
	return 4
}

// RuneCount returns the number of runes in p.  Erroneous and short
// encodings are treated as single runes of width 1 byte.
func RuneCount(p []byte) int {
	i := 0
	var n int
	for n = 0; i < len(p); n++ {
		if p[i] < RuneSelf {
			i++
		} else {
			_, size := DecodeRune(p[i:])
			i += size
		}
	}
	return n
}

// RuneCountInString is like RuneCount but its input is a string.
func RuneCountInString(s string) (n int) {
	for _ = range s {
		n++
	}
	return
}

// RuneStart reports whether the byte could be the first byte of
// an encoded rune.  Second and subsequent bytes always have the top
// two bits set to 10.
func RuneStart(b byte) bool { return b&0xC0 != 0x80 }
<|endoftext|>


<commit_before>// +build integration

/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package integration

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
	"time"

	"k8s.io/apimachinery/pkg/labels"
	pkgutil "k8s.io/minikube/pkg/util"
	"k8s.io/minikube/test/integration/util"
)

func testMounting(t *testing.T) {
	t.Parallel()
	if runtime.GOOS == "darwin" {
		t.Skip("mount tests disabled in darwin due to timeout (issue#3200)")
	}
	if strings.Contains(*args, "--vm-driver=none") {
		t.Skip("skipping test for none driver as it does not need mount")
	}
	minikubeRunner := NewMinikubeRunner(t)

	tempDir, err := ioutil.TempDir("", "mounttest")
	if err != nil {
		t.Fatalf("Unexpected error while creating tempDir: %v", err)
	}
	defer os.RemoveAll(tempDir)

	var mountCmd string
	if len(minikubeRunner.MountArgs) > 0 {
		mountCmd = fmt.Sprintf("mount %s %s:/mount-9p", minikubeRunner.MountArgs, tempDir)
	} else {
		mountCmd = fmt.Sprintf("mount %s:/mount-9p", tempDir)
	}
	if testing.Verbose() {
		fmt.Fprintf(os.Stderr, "runing mount cmd: %s\n", mountCmd)
	}
	cmd, out, serr := minikubeRunner.RunDaemon2(mountCmd)
	defer func() {
		err := cmd.Process.Kill()
		if err != nil {
			t.Logf("Failed to kill mount command: %v", err)
		}
	}()

	if testing.Verbose() {
		go io.Copy(os.Stderr, out)
		go io.Copy(os.Stderr, serr)
	}

	kubectlRunner := util.NewKubectlRunner(t)
	podName := "busybox-mount"
	podPath, _ := filepath.Abs("testdata/busybox-mount-test.yaml")

	// Write file in mounted dir from host
	expected := "test\n"
	files := []string{"fromhost", "fromhostremove"}
	for _, file := range files {
		path := filepath.Join(tempDir, file)
		err = ioutil.WriteFile(path, []byte(expected), 0644)
		if err != nil {
			t.Fatalf("Unexpected error while writing file %s: %v", path, err)
		}
	}

	// Create the pods we need outside the main test loop.
	setupTest := func() error {
		if _, err := kubectlRunner.RunCommand([]string{"create", "-f", podPath}); err != nil {
			return err
		}
		return nil
	}
	defer func() {
		if out, err := kubectlRunner.RunCommand([]string{"delete", "-f", podPath}); err != nil {
			t.Logf("delete -f %s failed: %v\noutput: %s\n", podPath, err, out)
		}
	}()

	if err := util.Retry(t, setupTest, 5*time.Second, 40); err != nil {
		t.Fatal("mountTest failed with error:", err)
	}

	client, err := pkgutil.GetClient()
	if err != nil {
		t.Fatalf("getting kubernetes client: %v", err)
	}
	selector := labels.SelectorFromSet(labels.Set(map[string]string{"integration-test": "busybox-mount"}))
	if err := pkgutil.WaitForPodsWithLabelRunning(client, "default", selector); err != nil {
		t.Fatalf("Error waiting for busybox mount pod to be up: %v", err)
	}

	mountTest := func() error {
		path := filepath.Join(tempDir, "frompod")
		out, err := ioutil.ReadFile(path)
		if err != nil {
			return err
		}
		// test that file written from pod can be read from host echo test > /mount-9p/frompod; in pod
		if string(out) != expected {
			t.Fatalf("Expected file %s to contain text %s, was %s.", path, expected, out)
		}

		// test that file written from host was read in by the pod via cat /mount-9p/fromhost;
		if out, err = kubectlRunner.RunCommand([]string{"logs", podName}); err != nil {
			return err
		}
		if string(out) != expected {
			t.Fatalf("Expected file %s to contain text %s, was %s.", path, expected, out)
		}

		// test file timestamps are correct
		files := []string{"fromhost", "frompod"}
		for _, file := range files {
			statCmd := fmt.Sprintf("stat /mount-9p/%s", file)
			statOutput, err := minikubeRunner.SSH(statCmd)
			if err != nil {
				t.Fatalf("%v", err)
			}

			if runtime.GOOS == "windows" {
				if strings.Contains(statOutput, "Access: 1970-01-01") {
					t.Fatalf("Invalid access time\n%s", statOutput)
				}
			}

			if strings.Contains(statOutput, "Modify: 1970-01-01") {
				t.Fatalf("Invalid modify time\n%s", statOutput)
			}
		}

		// test that fromhostremove was deleted by the pod from the mount via rm /mount-9p/fromhostremove
		path = filepath.Join(tempDir, "fromhostremove")
		if _, err := os.Stat(path); err == nil {
			t.Fatalf("Expected file %s to be removed", path)
		}

		// test that frompodremove can be deleted on the host
		path = filepath.Join(tempDir, "frompodremove")
		if err := os.Remove(path); err != nil {
			t.Fatalf("Unexpected error removing file %s: %v", path, err)
		}

		return nil
	}
	if err := util.Retry(t, mountTest, 5*time.Second, 40); err != nil {
		t.Fatalf("mountTest failed with error: %v", err)
	}

}
<commit_msg>Remove extra debug logging for mount command.<commit_after>// +build integration

/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package integration

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
	"time"

	"k8s.io/apimachinery/pkg/labels"
	pkgutil "k8s.io/minikube/pkg/util"
	"k8s.io/minikube/test/integration/util"
)

func testMounting(t *testing.T) {
	t.Parallel()
	if runtime.GOOS == "darwin" {
		t.Skip("mount tests disabled in darwin due to timeout (issue#3200)")
	}
	if strings.Contains(*args, "--vm-driver=none") {
		t.Skip("skipping test for none driver as it does not need mount")
	}
	minikubeRunner := NewMinikubeRunner(t)

	tempDir, err := ioutil.TempDir("", "mounttest")
	if err != nil {
		t.Fatalf("Unexpected error while creating tempDir: %v", err)
	}
	defer os.RemoveAll(tempDir)

	var mountCmd string
	if len(minikubeRunner.MountArgs) > 0 {
		mountCmd = fmt.Sprintf("mount %s %s:/mount-9p", minikubeRunner.MountArgs, tempDir)
	} else {
		mountCmd = fmt.Sprintf("mount %s:/mount-9p", tempDir)
	}
	cmd, _, _ := minikubeRunner.RunDaemon2(mountCmd)
	defer func() {
		err := cmd.Process.Kill()
		if err != nil {
			t.Logf("Failed to kill mount command: %v", err)
		}
	}()

	kubectlRunner := util.NewKubectlRunner(t)
	podName := "busybox-mount"
	podPath, _ := filepath.Abs("testdata/busybox-mount-test.yaml")

	// Write file in mounted dir from host
	expected := "test\n"
	files := []string{"fromhost", "fromhostremove"}
	for _, file := range files {
		path := filepath.Join(tempDir, file)
		err = ioutil.WriteFile(path, []byte(expected), 0644)
		if err != nil {
			t.Fatalf("Unexpected error while writing file %s: %v", path, err)
		}
	}

	// Create the pods we need outside the main test loop.
	setupTest := func() error {
		if _, err := kubectlRunner.RunCommand([]string{"create", "-f", podPath}); err != nil {
			return err
		}
		return nil
	}
	defer func() {
		if out, err := kubectlRunner.RunCommand([]string{"delete", "-f", podPath}); err != nil {
			t.Logf("delete -f %s failed: %v\noutput: %s\n", podPath, err, out)
		}
	}()

	if err := util.Retry(t, setupTest, 5*time.Second, 40); err != nil {
		t.Fatal("mountTest failed with error:", err)
	}

	client, err := pkgutil.GetClient()
	if err != nil {
		t.Fatalf("getting kubernetes client: %v", err)
	}
	selector := labels.SelectorFromSet(labels.Set(map[string]string{"integration-test": "busybox-mount"}))
	if err := pkgutil.WaitForPodsWithLabelRunning(client, "default", selector); err != nil {
		t.Fatalf("Error waiting for busybox mount pod to be up: %v", err)
	}

	mountTest := func() error {
		path := filepath.Join(tempDir, "frompod")
		out, err := ioutil.ReadFile(path)
		if err != nil {
			return err
		}
		// test that file written from pod can be read from host echo test > /mount-9p/frompod; in pod
		if string(out) != expected {
			t.Fatalf("Expected file %s to contain text %s, was %s.", path, expected, out)
		}

		// test that file written from host was read in by the pod via cat /mount-9p/fromhost;
		if out, err = kubectlRunner.RunCommand([]string{"logs", podName}); err != nil {
			return err
		}
		if string(out) != expected {
			t.Fatalf("Expected file %s to contain text %s, was %s.", path, expected, out)
		}

		// test file timestamps are correct
		files := []string{"fromhost", "frompod"}
		for _, file := range files {
			statCmd := fmt.Sprintf("stat /mount-9p/%s", file)
			statOutput, err := minikubeRunner.SSH(statCmd)
			if err != nil {
				t.Fatalf("Unable to stat %s via SSH. error %v, %s", file, err, statOutput)
			}

			if runtime.GOOS == "windows" {
				if strings.Contains(statOutput, "Access: 1970-01-01") {
					t.Fatalf("Invalid access time\n%s", statOutput)
				}
			}

			if strings.Contains(statOutput, "Modify: 1970-01-01") {
				t.Fatalf("Invalid modify time\n%s", statOutput)
			}
		}

		// test that fromhostremove was deleted by the pod from the mount via rm /mount-9p/fromhostremove
		path = filepath.Join(tempDir, "fromhostremove")
		if _, err := os.Stat(path); err == nil {
			t.Fatalf("Expected file %s to be removed", path)
		}

		// test that frompodremove can be deleted on the host
		path = filepath.Join(tempDir, "frompodremove")
		if err := os.Remove(path); err != nil {
			t.Fatalf("Unexpected error removing file %s: %v", path, err)
		}

		return nil
	}
	if err := util.Retry(t, mountTest, 5*time.Second, 40); err != nil {
		t.Fatalf("mountTest failed with error: %v", err)
	}

}
<|endoftext|>


<commit_before><commit_msg>Another TODO<commit_after><|endoftext|>


<commit_before>package executor

import (
	"fmt"
	"os"
	"os/user"
	"strconv"
	"syscall"

	multierror "github.com/hashicorp/go-multierror"
	"github.com/hashicorp/nomad/helper"
	"github.com/opencontainers/runc/libcontainer/cgroups"
	cgroupFs "github.com/opencontainers/runc/libcontainer/cgroups/fs"
	lconfigs "github.com/opencontainers/runc/libcontainer/configs"
)

// runAs takes a user id as a string and looks up the user, and sets the command
// to execute as that user.
func (e *UniversalExecutor) runAs(userid string) error {
	u, err := user.Lookup(userid)
	if err != nil {
		return fmt.Errorf("Failed to identify user %v: %v", userid, err)
	}

	// Get the groups the user is a part of
	gidStrings, err := u.GroupIds()
	if err != nil {
		return fmt.Errorf("Unable to lookup user's group membership: %v", err)
	}

	gids := make([]uint32, len(gidStrings))
	for _, gidString := range gidStrings {
		u, err := strconv.Atoi(gidString)
		if err != nil {
			return fmt.Errorf("Unable to convert user's group to int %s: %v", gidString, err)
		}

		gids = append(gids, uint32(u))
	}

	// Convert the uid and gid
	uid, err := strconv.ParseUint(u.Uid, 10, 32)
	if err != nil {
		return fmt.Errorf("Unable to convert userid to uint32: %s", err)
	}
	gid, err := strconv.ParseUint(u.Gid, 10, 32)
	if err != nil {
		return fmt.Errorf("Unable to convert groupid to uint32: %s", err)
	}

	// Set the command to run as that user and group.
	if e.childCmd.SysProcAttr == nil {
		e.childCmd.SysProcAttr = &syscall.SysProcAttr{}
	}
	if e.childCmd.SysProcAttr.Credential == nil {
		e.childCmd.SysProcAttr.Credential = &syscall.Credential{}
	}
	e.childCmd.SysProcAttr.Credential.Uid = uint32(uid)
	e.childCmd.SysProcAttr.Credential.Gid = uint32(gid)
	e.childCmd.SysProcAttr.Credential.Groups = gids

	e.logger.Debug("setting process user", "user", uid, "group", gid, "additional_groups", gids)

	return nil
}

// configureResourceContainer configured the cgroups to be used to track pids
// created by the executor
func (e *UniversalExecutor) configureResourceContainer(pid int) error {
	cfg := &lconfigs.Config{
		Cgroups: &lconfigs.Cgroup{
			Resources: &lconfigs.Resources{
				AllowAllDevices: helper.BoolToPtr(true),
			},
		},
	}

	err := configureBasicCgroups(cfg)
	if err != nil {
		// Debug this error to help diagnose cases where nomad is run with too few
		// permissions, but don't return an error. There is no separate check for
		// cgroup creation permissions, so this may be the happy path.
		e.logger.Debug("failed to create cgroup", "error", err)
		return nil
	}
	e.resConCtx.groups = cfg.Cgroups
	return cgroups.EnterPid(cfg.Cgroups.Paths, pid)
}

func (e *UniversalExecutor) getAllPids() (map[int]*nomadPid, error) {
	if e.resConCtx.isEmpty() {
		return getAllPidsByScanning()
	} else {
		return e.resConCtx.getAllPidsByCgroup()
	}
}

// DestroyCgroup kills all processes in the cgroup and removes the cgroup
// configuration from the host. This function is idempotent.
func DestroyCgroup(groups *lconfigs.Cgroup, executorPid int) error {
	mErrs := new(multierror.Error)
	if groups == nil {
		return fmt.Errorf("Can't destroy: cgroup configuration empty")
	}

	// Move the executor into the global cgroup so that the task specific
	// cgroup can be destroyed.
	path, err := cgroups.GetInitCgroupPath("freezer")
	if err != nil {
		return err
	}

	if err := cgroups.EnterPid(map[string]string{"freezer": path}, executorPid); err != nil {
		return err
	}

	// Freeze the Cgroup so that it can not continue to fork/exec.
	groups.Resources.Freezer = lconfigs.Frozen
	freezer := cgroupFs.FreezerGroup{}
	if err := freezer.Set(groups.Paths[freezer.Name()], groups); err != nil {
		return err
	}

	var procs []*os.Process
	pids, err := cgroups.GetAllPids(groups.Paths[freezer.Name()])
	if err != nil {
		multierror.Append(mErrs, fmt.Errorf("error getting pids: %v", err))

		// Unfreeze the cgroup.
		groups.Resources.Freezer = lconfigs.Thawed
		freezer := cgroupFs.FreezerGroup{}
		if err := freezer.Set(groups.Paths[freezer.Name()], groups); err != nil {
			multierror.Append(mErrs, fmt.Errorf("failed to unfreeze cgroup: %v", err))
			return mErrs.ErrorOrNil()
		}
	}

	// Kill the processes in the cgroup
	for _, pid := range pids {
		proc, err := os.FindProcess(pid)
		if err != nil {
			multierror.Append(mErrs, fmt.Errorf("error finding process %v: %v", pid, err))
			continue
		}

		procs = append(procs, proc)
		if e := proc.Kill(); e != nil {
			multierror.Append(mErrs, fmt.Errorf("error killing process %v: %v", pid, e))
		}
	}

	// Unfreeze the cgroug so we can wait.
	groups.Resources.Freezer = lconfigs.Thawed
	if err := freezer.Set(groups.Paths[freezer.Name()], groups); err != nil {
		multierror.Append(mErrs, fmt.Errorf("failed to unfreeze cgroup: %v", err))
		return mErrs.ErrorOrNil()
	}

	// Wait on the killed processes to ensure they are cleaned up.
	for _, proc := range procs {
		// Don't capture the error because we expect this to fail for
		// processes we didn't fork.
		proc.Wait()
	}

	// Remove the cgroup.
	if err := cgroups.RemovePaths(groups.Paths); err != nil {
		multierror.Append(mErrs, fmt.Errorf("failed to delete the cgroup directories: %v", err))
	}
	return mErrs.ErrorOrNil()
}
<commit_msg>executor_universal_linux log a link to the docs on cgroup error<commit_after>package executor

import (
	"fmt"
	"os"
	"os/user"
	"strconv"
	"syscall"

	multierror "github.com/hashicorp/go-multierror"
	"github.com/hashicorp/nomad/helper"
	"github.com/opencontainers/runc/libcontainer/cgroups"
	cgroupFs "github.com/opencontainers/runc/libcontainer/cgroups/fs"
	lconfigs "github.com/opencontainers/runc/libcontainer/configs"
)

// runAs takes a user id as a string and looks up the user, and sets the command
// to execute as that user.
func (e *UniversalExecutor) runAs(userid string) error {
	u, err := user.Lookup(userid)
	if err != nil {
		return fmt.Errorf("Failed to identify user %v: %v", userid, err)
	}

	// Get the groups the user is a part of
	gidStrings, err := u.GroupIds()
	if err != nil {
		return fmt.Errorf("Unable to lookup user's group membership: %v", err)
	}

	gids := make([]uint32, len(gidStrings))
	for _, gidString := range gidStrings {
		u, err := strconv.Atoi(gidString)
		if err != nil {
			return fmt.Errorf("Unable to convert user's group to int %s: %v", gidString, err)
		}

		gids = append(gids, uint32(u))
	}

	// Convert the uid and gid
	uid, err := strconv.ParseUint(u.Uid, 10, 32)
	if err != nil {
		return fmt.Errorf("Unable to convert userid to uint32: %s", err)
	}
	gid, err := strconv.ParseUint(u.Gid, 10, 32)
	if err != nil {
		return fmt.Errorf("Unable to convert groupid to uint32: %s", err)
	}

	// Set the command to run as that user and group.
	if e.childCmd.SysProcAttr == nil {
		e.childCmd.SysProcAttr = &syscall.SysProcAttr{}
	}
	if e.childCmd.SysProcAttr.Credential == nil {
		e.childCmd.SysProcAttr.Credential = &syscall.Credential{}
	}
	e.childCmd.SysProcAttr.Credential.Uid = uint32(uid)
	e.childCmd.SysProcAttr.Credential.Gid = uint32(gid)
	e.childCmd.SysProcAttr.Credential.Groups = gids

	e.logger.Debug("setting process user", "user", uid, "group", gid, "additional_groups", gids)

	return nil
}

// configureResourceContainer configured the cgroups to be used to track pids
// created by the executor
func (e *UniversalExecutor) configureResourceContainer(pid int) error {
	cfg := &lconfigs.Config{
		Cgroups: &lconfigs.Cgroup{
			Resources: &lconfigs.Resources{
				AllowAllDevices: helper.BoolToPtr(true),
			},
		},
	}

	err := configureBasicCgroups(cfg)
	if err != nil {
		// Log this error to help diagnose cases where nomad is run with too few
		// permissions, but don't return an error. There is no separate check for
		// cgroup creation permissions, so this may be the happy path.
		e.logger.Warn("failed to create cgroup",
			"docs", "https://www.nomadproject.io/docs/drivers/raw_exec.html#no_cgroups",
			"error", err)
		return nil
	}
	e.resConCtx.groups = cfg.Cgroups
	return cgroups.EnterPid(cfg.Cgroups.Paths, pid)
}

func (e *UniversalExecutor) getAllPids() (map[int]*nomadPid, error) {
	if e.resConCtx.isEmpty() {
		return getAllPidsByScanning()
	} else {
		return e.resConCtx.getAllPidsByCgroup()
	}
}

// DestroyCgroup kills all processes in the cgroup and removes the cgroup
// configuration from the host. This function is idempotent.
func DestroyCgroup(groups *lconfigs.Cgroup, executorPid int) error {
	mErrs := new(multierror.Error)
	if groups == nil {
		return fmt.Errorf("Can't destroy: cgroup configuration empty")
	}

	// Move the executor into the global cgroup so that the task specific
	// cgroup can be destroyed.
	path, err := cgroups.GetInitCgroupPath("freezer")
	if err != nil {
		return err
	}

	if err := cgroups.EnterPid(map[string]string{"freezer": path}, executorPid); err != nil {
		return err
	}

	// Freeze the Cgroup so that it can not continue to fork/exec.
	groups.Resources.Freezer = lconfigs.Frozen
	freezer := cgroupFs.FreezerGroup{}
	if err := freezer.Set(groups.Paths[freezer.Name()], groups); err != nil {
		return err
	}

	var procs []*os.Process
	pids, err := cgroups.GetAllPids(groups.Paths[freezer.Name()])
	if err != nil {
		multierror.Append(mErrs, fmt.Errorf("error getting pids: %v", err))

		// Unfreeze the cgroup.
		groups.Resources.Freezer = lconfigs.Thawed
		freezer := cgroupFs.FreezerGroup{}
		if err := freezer.Set(groups.Paths[freezer.Name()], groups); err != nil {
			multierror.Append(mErrs, fmt.Errorf("failed to unfreeze cgroup: %v", err))
			return mErrs.ErrorOrNil()
		}
	}

	// Kill the processes in the cgroup
	for _, pid := range pids {
		proc, err := os.FindProcess(pid)
		if err != nil {
			multierror.Append(mErrs, fmt.Errorf("error finding process %v: %v", pid, err))
			continue
		}

		procs = append(procs, proc)
		if e := proc.Kill(); e != nil {
			multierror.Append(mErrs, fmt.Errorf("error killing process %v: %v", pid, e))
		}
	}

	// Unfreeze the cgroug so we can wait.
	groups.Resources.Freezer = lconfigs.Thawed
	if err := freezer.Set(groups.Paths[freezer.Name()], groups); err != nil {
		multierror.Append(mErrs, fmt.Errorf("failed to unfreeze cgroup: %v", err))
		return mErrs.ErrorOrNil()
	}

	// Wait on the killed processes to ensure they are cleaned up.
	for _, proc := range procs {
		// Don't capture the error because we expect this to fail for
		// processes we didn't fork.
		proc.Wait()
	}

	// Remove the cgroup.
	if err := cgroups.RemovePaths(groups.Paths); err != nil {
		multierror.Append(mErrs, fmt.Errorf("failed to delete the cgroup directories: %v", err))
	}
	return mErrs.ErrorOrNil()
}
<|endoftext|>


<commit_before>package digest

import (
	"fmt"
	"hash"
	"io"
	"regexp"
	"strings"
)

// Digest allows simple protection of hex formatted digest strings, prefixed
// by their algorithm. Strings of type Digest have some guarantee of being in
// the correct format and it provides quick access to the components of a
// digest string.
//
// The following is an example of the contents of Digest types:
//
// 	sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc
//
// This allows to abstract the digest behind this type and work only in those
// terms.
type Digest string

// NewDigest returns a Digest from alg and a hash.Hash object.
func NewDigest(alg Algorithm, h hash.Hash) Digest {
	return NewDigestFromBytes(alg, h.Sum(nil))
}

// NewDigestFromBytes returns a new digest from the byte contents of p.
// Typically, this can come from hash.Hash.Sum(...) or xxx.SumXXX(...)
// functions. This is also useful for rebuilding digests from binary
// serializations.
func NewDigestFromBytes(alg Algorithm, p []byte) Digest {
	return Digest(fmt.Sprintf("%s:%x", alg, p))
}

// NewDigestFromHex returns a Digest from alg and a the hex encoded digest.
func NewDigestFromHex(alg, hex string) Digest {
	return Digest(fmt.Sprintf("%s:%s", alg, hex))
}

// DigestRegexp matches valid digest types.
var DigestRegexp = regexp.MustCompile(`[a-zA-Z0-9-_+.]+:[a-fA-F0-9]+`)

// DigestRegexpAnchored matches valid digest types, anchored to the start and end of the match.
var DigestRegexpAnchored = regexp.MustCompile(`^` + DigestRegexp.String() + `$`)

var (
	// ErrDigestInvalidFormat returned when digest format invalid.
	ErrDigestInvalidFormat = fmt.Errorf("invalid checksum digest format")

	// ErrDigestInvalidLength returned when digest has invalid length.
	ErrDigestInvalidLength = fmt.Errorf("invalid checksum digest length")

	// ErrDigestUnsupported returned when the digest algorithm is unsupported.
	ErrDigestUnsupported = fmt.Errorf("unsupported digest algorithm")
)

// Parse parses s and returns the validated digest object. An error will
// be returned if the format is invalid.
func Parse(s string) (Digest, error) {
	d := Digest(s)
	return d, d.Validate()
}

// FromReader returns the most valid digest for the underlying content using
// the canonical digest algorithm.
func FromReader(rd io.Reader) (Digest, error) {
	return Canonical.FromReader(rd)
}

// FromBytes digests the input and returns a Digest.
func FromBytes(p []byte) Digest {
	return Canonical.FromBytes(p)
}

// FromString digests the input and returns a Digest.
func FromString(s string) Digest {
	return Canonical.FromString(s)
}

// Validate checks that the contents of d is a valid digest, returning an
// error if not.
func (d Digest) Validate() error {
	s := string(d)

	i := strings.Index(s, ":")

	// validate i then run through regexp
	if i < 0 || i+1 == len(s) || !DigestRegexpAnchored.MatchString(s) {
		return ErrDigestInvalidFormat
	}

	algorithm := Algorithm(s[:i])
	if !algorithm.Available() {
		return ErrDigestUnsupported
	}

	// Digests much always be hex-encoded, ensuring that their hex portion will
	// always be size*2
	if algorithm.Size()*2 != len(s[i+1:]) {
		return ErrDigestInvalidLength
	}

	return nil
}

// Algorithm returns the algorithm portion of the digest. This will panic if
// the underlying digest is not in a valid format.
func (d Digest) Algorithm() Algorithm {
	return Algorithm(d[:d.sepIndex()])
}

// Verifier returns a writer object that can be used to verify a stream of
// content against the digest. If the digest is invalid, the method will panic.
func (d Digest) Verifier() Verifier {
	return hashVerifier{
		hash:   d.Algorithm().Hash(),
		digest: d,
	}
}

// Hex returns the hex digest portion of the digest. This will panic if the
// underlying digest is not in a valid format.
func (d Digest) Hex() string {
	return string(d[d.sepIndex()+1:])
}

func (d Digest) String() string {
	return string(d)
}

func (d Digest) sepIndex() int {
	i := strings.Index(string(d), ":")

	if i < 0 {
		panic(fmt.Sprintf("no ':' separator in digest %q", d))
	}

	return i
}
<commit_msg>digest: remove out of date godoc comment<commit_after>package digest

import (
	"fmt"
	"hash"
	"io"
	"regexp"
	"strings"
)

// Digest allows simple protection of hex formatted digest strings, prefixed
// by their algorithm. Strings of type Digest have some guarantee of being in
// the correct format and it provides quick access to the components of a
// digest string.
//
// The following is an example of the contents of Digest types:
//
// 	sha256:7173b809ca12ec5dee4506cd86be934c4596dd234ee82c0662eac04a8c2c71dc
//
// This allows to abstract the digest behind this type and work only in those
// terms.
type Digest string

// NewDigest returns a Digest from alg and a hash.Hash object.
func NewDigest(alg Algorithm, h hash.Hash) Digest {
	return NewDigestFromBytes(alg, h.Sum(nil))
}

// NewDigestFromBytes returns a new digest from the byte contents of p.
// Typically, this can come from hash.Hash.Sum(...) or xxx.SumXXX(...)
// functions. This is also useful for rebuilding digests from binary
// serializations.
func NewDigestFromBytes(alg Algorithm, p []byte) Digest {
	return Digest(fmt.Sprintf("%s:%x", alg, p))
}

// NewDigestFromHex returns a Digest from alg and a the hex encoded digest.
func NewDigestFromHex(alg, hex string) Digest {
	return Digest(fmt.Sprintf("%s:%s", alg, hex))
}

// DigestRegexp matches valid digest types.
var DigestRegexp = regexp.MustCompile(`[a-zA-Z0-9-_+.]+:[a-fA-F0-9]+`)

// DigestRegexpAnchored matches valid digest types, anchored to the start and end of the match.
var DigestRegexpAnchored = regexp.MustCompile(`^` + DigestRegexp.String() + `$`)

var (
	// ErrDigestInvalidFormat returned when digest format invalid.
	ErrDigestInvalidFormat = fmt.Errorf("invalid checksum digest format")

	// ErrDigestInvalidLength returned when digest has invalid length.
	ErrDigestInvalidLength = fmt.Errorf("invalid checksum digest length")

	// ErrDigestUnsupported returned when the digest algorithm is unsupported.
	ErrDigestUnsupported = fmt.Errorf("unsupported digest algorithm")
)

// Parse parses s and returns the validated digest object. An error will
// be returned if the format is invalid.
func Parse(s string) (Digest, error) {
	d := Digest(s)
	return d, d.Validate()
}

// FromReader consumes the content of rd until io.EOF, returning canonical digest.
func FromReader(rd io.Reader) (Digest, error) {
	return Canonical.FromReader(rd)
}

// FromBytes digests the input and returns a Digest.
func FromBytes(p []byte) Digest {
	return Canonical.FromBytes(p)
}

// FromString digests the input and returns a Digest.
func FromString(s string) Digest {
	return Canonical.FromString(s)
}

// Validate checks that the contents of d is a valid digest, returning an
// error if not.
func (d Digest) Validate() error {
	s := string(d)

	i := strings.Index(s, ":")

	// validate i then run through regexp
	if i < 0 || i+1 == len(s) || !DigestRegexpAnchored.MatchString(s) {
		return ErrDigestInvalidFormat
	}

	algorithm := Algorithm(s[:i])
	if !algorithm.Available() {
		return ErrDigestUnsupported
	}

	// Digests much always be hex-encoded, ensuring that their hex portion will
	// always be size*2
	if algorithm.Size()*2 != len(s[i+1:]) {
		return ErrDigestInvalidLength
	}

	return nil
}

// Algorithm returns the algorithm portion of the digest. This will panic if
// the underlying digest is not in a valid format.
func (d Digest) Algorithm() Algorithm {
	return Algorithm(d[:d.sepIndex()])
}

// Verifier returns a writer object that can be used to verify a stream of
// content against the digest. If the digest is invalid, the method will panic.
func (d Digest) Verifier() Verifier {
	return hashVerifier{
		hash:   d.Algorithm().Hash(),
		digest: d,
	}
}

// Hex returns the hex digest portion of the digest. This will panic if the
// underlying digest is not in a valid format.
func (d Digest) Hex() string {
	return string(d[d.sepIndex()+1:])
}

func (d Digest) String() string {
	return string(d)
}

func (d Digest) sepIndex() int {
	i := strings.Index(string(d), ":")

	if i < 0 {
		panic(fmt.Sprintf("no ':' separator in digest %q", d))
	}

	return i
}
<|endoftext|>


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

package analyzer

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"strconv"
	"sync"
	"sync/atomic"
	"time"

	"github.com/pmylund/go-cache"
	"github.com/skydive-project/skydive/common"
	"github.com/skydive-project/skydive/config"
	"github.com/skydive-project/skydive/flow"
	"github.com/skydive-project/skydive/flow/enhancers"
	"github.com/skydive-project/skydive/flow/storage"
	"github.com/skydive-project/skydive/logging"
	"github.com/skydive-project/skydive/probe"
	"github.com/skydive-project/skydive/topology/graph"
)

// ErrFlowUDPAcceptNotSupported error the connection can't accept as it's UDP based
var ErrFlowUDPAcceptNotSupported = errors.New("UDP connection is datagram based (not connected), accept() not supported")

// FlowConnectionType describes an UDP or TLS connection
type FlowConnectionType int

const (
	// UDP connection
	UDP FlowConnectionType = 1 + iota
	// TLS connection
	TLS
)

// FlowServerConn describes a flow server connection
type FlowServerConn struct {
	mode      FlowConnectionType
	udpConn   *net.UDPConn
	tlsConn   net.Conn
	tlsListen net.Listener
}

// FlowServer describes a flow server with pipeline enhancers mechanism
type FlowServer struct {
	Addr             string
	Port             int
	Storage          storage.Storage
	EnhancerPipeline *flow.EnhancerPipeline
	conn             *FlowServerConn
	state            int64
	wgServer         sync.WaitGroup
	wgFlowsHandlers  sync.WaitGroup
	bulkInsert       int
	bulkDeadline     int
}

// Mode returns the connection mode UDP or TLS
func (a *FlowServerConn) Mode() FlowConnectionType {
	return a.mode
}

// Accept connection step
func (a *FlowServerConn) Accept() (*FlowServerConn, error) {
	switch a.mode {
	case TLS:
		acceptedTLSConn, err := a.tlsListen.Accept()
		if err != nil {
			return nil, err
		}

		tlsConn, ok := acceptedTLSConn.(*tls.Conn)
		if !ok {
			logging.GetLogger().Fatalf("This is not a TLS connection %v", a.tlsConn)
		}
		if err = tlsConn.Handshake(); err != nil {
			return nil, err
		}
		if state := tlsConn.ConnectionState(); state.HandshakeComplete == false {
			return nil, errors.New("TLS Handshake is not complete")
		}
		return &FlowServerConn{
			mode:    TLS,
			tlsConn: acceptedTLSConn,
		}, nil
	case UDP:
		return a, ErrFlowUDPAcceptNotSupported
	}
	return nil, errors.New("Connection mode is not set properly")
}

// Cleanup stop listening on the connection
func (a *FlowServerConn) Cleanup() {
	if a.mode == TLS {
		if err := a.tlsListen.Close(); err != nil {
			logging.GetLogger().Errorf("Close error %v", err)
		}
	}
}

// Close the connection
func (a *FlowServerConn) Close() {
	switch a.mode {
	case TLS:
		if err := a.tlsConn.Close(); err != nil {
			logging.GetLogger().Errorf("Close error %v", err)
		}
	case UDP:
		if err := a.udpConn.Close(); err != nil {
			logging.GetLogger().Errorf("Close error %v", err)
		}
	}
}

// SetDeadline for the connection IO
func (a *FlowServerConn) SetDeadline(t time.Time) {
	switch a.mode {
	case TLS:
		if err := a.tlsConn.SetReadDeadline(t); err != nil {
			logging.GetLogger().Errorf("SetReadDeadline %v", err)
		}
	case UDP:
		if err := a.udpConn.SetDeadline(t); err != nil {
			logging.GetLogger().Errorf("SetDeadline %v", err)
		}
	}
}

// Read data from the connection
func (a *FlowServerConn) Read(data []byte) (int, error) {
	switch a.mode {
	case TLS:
		n, err := a.tlsConn.Read(data)
		return n, err
	case UDP:
		n, _, err := a.udpConn.ReadFromUDP(data)
		return n, err
	}
	return 0, errors.New("Mode didn't exist")
}

// Timeout returns true if the connection error timeouted
func (a *FlowServerConn) Timeout(err error) bool {
	switch a.mode {
	case TLS:
		if netErr, ok := err.(net.Error); ok {
			return netErr.Timeout()
		}
	case UDP:
		if netErr, ok := err.(*net.OpError); ok {
			return netErr.Timeout()
		}
	}
	return false
}

// NewFlowServerConn creates a new server listening at address
func NewFlowServerConn(addr *net.UDPAddr) (a *FlowServerConn, err error) {
	a = &FlowServerConn{mode: UDP}
	certPEM := config.GetConfig().GetString("analyzer.X509_cert")
	keyPEM := config.GetConfig().GetString("analyzer.X509_key")
	clientCertPEM := config.GetConfig().GetString("agent.X509_cert")

	if len(certPEM) > 0 && len(keyPEM) > 0 {
		cert, err := tls.LoadX509KeyPair(certPEM, keyPEM)
		if err != nil {
			logging.GetLogger().Fatalf("Can't read X509 key pair set in config : cert '%s' key '%s'", certPEM, keyPEM)
		}
		rootPEM, err := ioutil.ReadFile(clientCertPEM)
		if err != nil {
			logging.GetLogger().Fatalf("Failed to open root certificate '%s' : %s", clientCertPEM, err.Error())
		}
		roots := x509.NewCertPool()
		if ok := roots.AppendCertsFromPEM([]byte(rootPEM)); !ok {
			logging.GetLogger().Fatalf("Failed to parse root certificate '%s'", clientCertPEM)
		}
		cfgTLS := &tls.Config{
			ClientCAs:                roots,
			ClientAuth:               tls.RequireAndVerifyClientCert,
			Certificates:             []tls.Certificate{cert},
			MinVersion:               tls.VersionTLS12,
			PreferServerCipherSuites: true,
			CipherSuites: []uint16{
				tls.TLS_RSA_WITH_AES_128_CBC_SHA,
				tls.TLS_RSA_WITH_AES_256_CBC_SHA,
				tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
				tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
				tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
				tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
				tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
				tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
				tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
				tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
				tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
				tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
			},
		}
		cfgTLS.BuildNameToCertificate()
		if a.tlsListen, err = tls.Listen("tcp", fmt.Sprintf("%s:%d", common.IPToString(addr.IP), addr.Port+1), cfgTLS); err != nil {
			return nil, err
		}
		a.mode = TLS
		logging.GetLogger().Info("Analyzer listen agents on TLS socket")
		return a, nil
	}
	a.udpConn, err = net.ListenUDP("udp", addr)
	logging.GetLogger().Info("Analyzer listen agents on UDP socket")
	return a, err
}

func (s *FlowServer) storeFlows(flows []*flow.Flow) {
	if s.Storage != nil && len(flows) > 0 {
		s.EnhancerPipeline.Enhance(flows)
		s.Storage.StoreFlows(flows)

		logging.GetLogger().Debugf("%d flows stored", len(flows))
	}
}

// handleFlowPacket can handle connection based on TCP or UDP
func (s *FlowServer) handleFlowPacket(conn *FlowServerConn) {
	defer s.wgFlowsHandlers.Done()
	defer conn.Close()

	conn.SetDeadline(time.Now().Add(200 * time.Millisecond))
	// each flow can be HeaderSize * RawPackets + flow size (~500)
	data := make([]byte, flow.MaxCaptureLength*flow.MaxRawPacketLimit+flow.DefaultProtobufFlowSize)

	var flowBuffer []*flow.Flow
	defer s.storeFlows(flowBuffer)

	dlTimer := time.NewTicker(time.Duration(s.bulkDeadline) * time.Second)
	defer dlTimer.Stop()

	for atomic.LoadInt64(&s.state) == common.RunningState {
		select {
		case <-dlTimer.C:
			s.storeFlows(flowBuffer)
			flowBuffer = flowBuffer[:0]
		default:
			n, err := conn.Read(data)
			if err != nil {
				if conn.Timeout(err) {
					conn.SetDeadline(time.Now().Add(200 * time.Millisecond))
					continue
				}
				if atomic.LoadInt64(&s.state) != common.RunningState {
					return
				}
				logging.GetLogger().Errorf("Error while reading: %s", err.Error())
				return
			}

			f, err := flow.FromData(data[0:n])
			if err != nil {
				logging.GetLogger().Errorf("Error while parsing flow: %s", err.Error())
				continue
			}

			flowBuffer = append(flowBuffer, f)
			if len(flowBuffer) >= s.bulkInsert {
				s.storeFlows(flowBuffer)
				flowBuffer = flowBuffer[:0]
			}
		}
	}
}

// Start the flow server
func (s *FlowServer) Start() {
	host := s.Addr + ":" + strconv.FormatInt(int64(s.Port), 10)
	addr, err := net.ResolveUDPAddr("udp", host)
	if err != nil {
		logging.GetLogger().Errorf("Unable to start flow server: %s", err.Error())
		return
	}

	if s.conn, err = NewFlowServerConn(addr); err != nil {
		logging.GetLogger().Errorf("Unable to start flow server: %s", err.Error())
		return
	}
	atomic.StoreInt64(&s.state, common.RunningState)

	s.wgServer.Add(1)
	go func() {
		defer s.wgServer.Done()

		for atomic.LoadInt64(&s.state) == common.RunningState {
			switch s.conn.Mode() {
			case TLS:
				conn, err := s.conn.Accept()
				if atomic.LoadInt64(&s.state) != common.RunningState {
					break
				}
				if err != nil {
					logging.GetLogger().Errorf("Accept error : %s", err.Error())
					time.Sleep(200 * time.Millisecond)
					continue
				}

				s.wgFlowsHandlers.Add(1)
				go s.handleFlowPacket(conn)
			case UDP:
				s.wgFlowsHandlers.Add(1)
				s.handleFlowPacket(s.conn)
			}
		}
		s.wgFlowsHandlers.Wait()
	}()
}

// Stop the server
func (s *FlowServer) Stop() {
	if atomic.CompareAndSwapInt64(&s.state, common.RunningState, common.StoppingState) {
		s.conn.Cleanup()
		s.wgServer.Wait()
	}
}

// NewFlowServer creates a new flow server listening at address/port, based on configuration
func NewFlowServer(addr string, port int, g *graph.Graph, store storage.Storage, probe *probe.ProbeBundle) (*FlowServer, error) {
	cache := cache.New(time.Duration(600)*time.Second, time.Duration(600)*time.Second)
	pipeline := flow.NewEnhancerPipeline(enhancers.NewGraphFlowEnhancer(g, cache))

	// check that the neutron probe is loaded if so add the neutron flow enhancer
	if probe.GetProbe("neutron") != nil {
		pipeline.AddEnhancer(enhancers.NewNeutronFlowEnhancer(g, cache))
	}

	bulk := config.GetConfig().GetInt("analyzer.storage.bulk_insert")
	deadline := config.GetConfig().GetInt("analyzer.storage.bulk_insert_deadline")

	return &FlowServer{
		Addr:             addr,
		Port:             port,
		Storage:          store,
		EnhancerPipeline: pipeline,
		bulkInsert:       bulk,
		bulkDeadline:     deadline,
	}, nil
}
<commit_msg>flow: refactor UDP and TCP flow servers<commit_after>/*
 * Copyright (C) 2016 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */

package analyzer

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/pmylund/go-cache"
	"github.com/skydive-project/skydive/common"
	"github.com/skydive-project/skydive/config"
	"github.com/skydive-project/skydive/flow"
	"github.com/skydive-project/skydive/flow/enhancers"
	"github.com/skydive-project/skydive/flow/storage"
	"github.com/skydive-project/skydive/logging"
	"github.com/skydive-project/skydive/probe"
	"github.com/skydive-project/skydive/topology/graph"
)

// FlowServerConn describes a flow server connection
type FlowServerConn interface {
	Accept() (net.Conn, error)
	Cleanup() error
}

// FlowServerConn describes a UDP flow server connection
type FlowServerUDPConn struct {
	udpConn *net.UDPConn
}

// FlowServerConn describes a TCP flow server connection
type FlowServerTCPConn struct {
	tlsConn   net.Conn
	tlsListen net.Listener
}

// FlowServer describes a flow server with pipeline enhancers mechanism
type FlowServer struct {
	Addr             string
	Port             int
	Storage          storage.Storage
	EnhancerPipeline *flow.EnhancerPipeline
	conn             FlowServerConn
	state            int64
	wgServer         sync.WaitGroup
	wgFlowsHandlers  sync.WaitGroup
	bulkInsert       int
	bulkDeadline     int
}

// Accept connection step
func (c *FlowServerTCPConn) Accept() (net.Conn, error) {
	acceptedTLSConn, err := c.tlsListen.Accept()
	if err != nil {
		return nil, err
	}

	tlsConn, ok := acceptedTLSConn.(*tls.Conn)
	if !ok {
		logging.GetLogger().Fatalf("This is not a TLS connection %v", c.tlsConn)
	}

	if err = tlsConn.Handshake(); err != nil {
		return nil, err
	}

	if state := tlsConn.ConnectionState(); state.HandshakeComplete == false {
		return nil, errors.New("TLS Handshake is not complete")
	}

	return tlsConn, nil
}

// Cleanup stop listening on the connection
func (c *FlowServerTCPConn) Cleanup() error {
	return c.tlsListen.Close()
}

// Accept connection step
func (c *FlowServerUDPConn) Accept() (net.Conn, error) {
	return c.udpConn, nil
}

// Cleanup stop listening on the connection
func (c *FlowServerUDPConn) Cleanup() error {
	return nil
}

func NewFlowServerTCPConn(addr string, port int) (*FlowServerTCPConn, error) {
	tcpAddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", addr, port))
	if err != nil {
		return nil, err
	}

	certPEM := config.GetConfig().GetString("analyzer.X509_cert")
	keyPEM := config.GetConfig().GetString("analyzer.X509_key")
	clientCertPEM := config.GetConfig().GetString("agent.X509_cert")

	if len(certPEM) == 0 || len(keyPEM) == 0 {
		return nil, errors.New("Certificates are required to use TCP for flows")
	}

	cert, err := tls.LoadX509KeyPair(certPEM, keyPEM)
	if err != nil {
		logging.GetLogger().Fatalf("Can't read X509 key pair set in config : cert '%s' key '%s'", certPEM, keyPEM)
	}

	rootPEM, err := ioutil.ReadFile(clientCertPEM)
	if err != nil {
		logging.GetLogger().Fatalf("Failed to open root certificate '%s' : %s", clientCertPEM, err.Error())
	}

	roots := x509.NewCertPool()
	if ok := roots.AppendCertsFromPEM([]byte(rootPEM)); !ok {
		logging.GetLogger().Fatalf("Failed to parse root certificate '%s'", clientCertPEM)
	}

	cfgTLS := &tls.Config{
		ClientCAs:                roots,
		ClientAuth:               tls.RequireAndVerifyClientCert,
		Certificates:             []tls.Certificate{cert},
		MinVersion:               tls.VersionTLS12,
		PreferServerCipherSuites: true,
		CipherSuites: []uint16{
			tls.TLS_RSA_WITH_AES_128_CBC_SHA,
			tls.TLS_RSA_WITH_AES_256_CBC_SHA,
			tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
			tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
			tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
			tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
			tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
			tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
			tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
			tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
		},
	}

	cfgTLS.BuildNameToCertificate()
	tlsListen, err := tls.Listen("tcp", fmt.Sprintf("%s:%d", common.IPToString(tcpAddr.IP), port+1), cfgTLS)
	if err != nil {
		return nil, err
	}

	logging.GetLogger().Info("Analyzer listen agents on TLS socket")
	return &FlowServerTCPConn{
		tlsListen: tlsListen,
	}, nil
}

func NewFlowServerUDPConn(addr string, port int) (*FlowServerUDPConn, error) {
	host := addr + ":" + strconv.FormatInt(int64(port), 10)
	udpAddr, err := net.ResolveUDPAddr("udp", host)
	if err != nil {
		return nil, err
	}

	udpConn, err := net.ListenUDP("udp", udpAddr)
	if err != nil {
		return nil, err
	}

	logging.GetLogger().Info("Analyzer listen agents on UDP socket")
	return &FlowServerUDPConn{udpConn: udpConn}, err
}

func (s *FlowServer) storeFlows(flows []*flow.Flow) {
	if s.Storage != nil && len(flows) > 0 {
		s.EnhancerPipeline.Enhance(flows)
		s.Storage.StoreFlows(flows)

		logging.GetLogger().Debugf("%d flows stored", len(flows))
	}
}

// handleFlowPacket can handle connection based on TCP or UDP
func (s *FlowServer) handleFlowPacket(conn net.Conn) {
	defer conn.Close()

	conn.SetDeadline(time.Now().Add(200 * time.Millisecond))
	// each flow can be HeaderSize * RawPackets + flow size (~500)
	data := make([]byte, flow.MaxCaptureLength*flow.MaxRawPacketLimit+flow.DefaultProtobufFlowSize)

	var flowBuffer []*flow.Flow
	defer s.storeFlows(flowBuffer)

	dlTimer := time.NewTicker(time.Duration(s.bulkDeadline) * time.Second)
	defer dlTimer.Stop()

	for atomic.LoadInt64(&s.state) == common.RunningState {
		select {
		case <-dlTimer.C:
			s.storeFlows(flowBuffer)
			flowBuffer = flowBuffer[:0]
		default:
			n, err := conn.Read(data)
			if err != nil {
				timeout := false
				switch netErr := err.(type) {
				case net.Error:
					timeout = netErr.Timeout()
				case *net.OpError:
					timeout = netErr.Timeout()
				}

				if timeout {
					conn.SetDeadline(time.Now().Add(200 * time.Millisecond))
					continue
				}

				if atomic.LoadInt64(&s.state) != common.RunningState {
					return
				}

				logging.GetLogger().Errorf("Error while reading: %s", err.Error())
				return
			}

			f, err := flow.FromData(data[0:n])
			if err != nil {
				logging.GetLogger().Errorf("Error while parsing flow: %s", err.Error())
				continue
			}

			flowBuffer = append(flowBuffer, f)
			if len(flowBuffer) >= s.bulkInsert {
				s.storeFlows(flowBuffer)
				flowBuffer = flowBuffer[:0]
			}
		}
	}
}

// Start the flow server
func (s *FlowServer) Start() {
	var err error
	protocol := strings.ToLower(config.GetConfig().GetString("flow.protocol"))
	switch protocol {
	case "udp":
		s.conn, err = NewFlowServerUDPConn(s.Addr, s.Port)
	case "tcp":
		s.conn, err = NewFlowServerTCPConn(s.Addr, s.Port)
	default:
		err = fmt.Errorf("Invalid protocol %s", protocol)
	}

	if err != nil {
		logging.GetLogger().Errorf("Unable to start flow server: %s", err.Error())
		return
	}
	atomic.StoreInt64(&s.state, common.RunningState)

	s.wgServer.Add(1)
	go func() {
		defer s.wgServer.Done()

		for atomic.LoadInt64(&s.state) == common.RunningState {
			conn, err := s.conn.Accept()
			if atomic.LoadInt64(&s.state) != common.RunningState {
				break
			}
			if err != nil {
				logging.GetLogger().Errorf("Accept error : %s", err.Error())
				time.Sleep(200 * time.Millisecond)
				continue
			}

			s.handleFlowPacket(conn)
		}

		s.wgFlowsHandlers.Wait()
	}()
}

// Stop the server
func (s *FlowServer) Stop() {
	if atomic.CompareAndSwapInt64(&s.state, common.RunningState, common.StoppingState) {
		s.conn.Cleanup()
		s.wgServer.Wait()
	}
}

// NewFlowServer creates a new flow server listening at address/port, based on configuration
func NewFlowServer(addr string, port int, g *graph.Graph, store storage.Storage, probe *probe.ProbeBundle) (*FlowServer, error) {
	cache := cache.New(time.Duration(600)*time.Second, time.Duration(600)*time.Second)
	pipeline := flow.NewEnhancerPipeline(enhancers.NewGraphFlowEnhancer(g, cache))

	// check that the neutron probe is loaded if so add the neutron flow enhancer
	if probe.GetProbe("neutron") != nil {
		pipeline.AddEnhancer(enhancers.NewNeutronFlowEnhancer(g, cache))
	}

	bulk := config.GetConfig().GetInt("analyzer.storage.bulk_insert")
	deadline := config.GetConfig().GetInt("analyzer.storage.bulk_insert_deadline")

	return &FlowServer{
		Addr:             addr,
		Port:             port,
		Storage:          store,
		EnhancerPipeline: pipeline,
		bulkInsert:       bulk,
		bulkDeadline:     deadline,
	}, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2014 Rohith All rights reserved.

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

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

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

package marathon

import "errors"

type Container struct {
	Type    string    `json:"type,omitempty"`
	Docker  *Docker   `json:"docker,omitempty"`
	Volumes []*Volume `json:"volumes,omitempty"`
}

type PortMapping struct {
	ContainerPort int    `json:"containerPort,omitempty"`
	HostPort      int    `json:"hostPort"`
	ServicePort   int    `json:"servicePort,omitempty"`
	Protocol      string `json:"protocol"`
}

type Volume struct {
	ContainerPath string `json:"containerPath,omitempty"`
	HostPath      string `json:"hostPath,omitempty"`
	Mode          string `json:"mode,omitempty"`
}

type Docker struct {
	Image        string         `json:"image,omitempty"`
	Network      string         `json:"network,omitempty"`
	PortMappings []*PortMapping `json:"portMappings,omitempty"`
}

func (container *Container) Volume(host_path, container_path, mode string) *Container {
	if container.Volumes == nil {
		container.Volumes = make([]*Volume, 0)
	}
	container.Volumes = append(container.Volumes, &Volume{
		ContainerPath: container_path,
		HostPath:      host_path,
		Mode:          mode,
	})
	return container
}

func NewDockerContainer() *Container {
	container := new(Container)
	container.Type = "DOCKER"
	container.Docker = &Docker{
		Image:        "",
		Network:      "BRIDGE",
		PortMappings: make([]*PortMapping, 0),
	}
	container.Volumes = make([]*Volume, 0)
	return container
}

func (docker *Docker) Container(image string) *Docker {
	docker.Image = image
	return docker
}

func (docker *Docker) Bridged() *Docker {
	docker.Network = "BRIDGE"
	return docker
}

func (docker *Docker) Expose(port int) *Docker {
	docker.ExposePort(port, 0, 0, "tcp")
	return docker
}

func (docker *Docker) ExposeUDP(port int) *Docker {
	docker.ExposePort(port, 0, 0, "udp")
	return docker
}

func (docker *Docker) ExposePort(container_port, host_port, service_port int, protocol string) *Docker {
	if docker.PortMappings == nil {
		docker.PortMappings = make([]*PortMapping, 0)
	}
	docker.PortMappings = append(docker.PortMappings, &PortMapping{
		ContainerPort: container_port,
		HostPort:      host_port,
		ServicePort:   service_port,
		Protocol:      protocol})
	return docker
}

func (docker *Docker) ServicePortIndex(port int) (int, error) {
	if docker.PortMappings == nil || len(docker.PortMappings) <= 0 {
		return 0, errors.New("The docker does not contain any port mappings to search")
	}
	/* step: iterate and find the port */
	for index, container_port := range docker.PortMappings {
		if container_port.ContainerPort == port {
			return index, nil
		}
	}
	/* step: we didn't find the port in the mappings */
	return 0, errors.New("The container port required was not found in the container port mappings")
}
<commit_msg>pass parameters<commit_after>/*
Copyright 2014 Rohith All rights reserved.

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

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

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

package marathon

import "errors"

type Container struct {
	Type    string    `json:"type,omitempty"`
	Docker  *Docker   `json:"docker,omitempty"`
	Volumes []*Volume `json:"volumes,omitempty"`
}
type PortMapping struct {
	ContainerPort int    `json:"containerPort,omitempty"`
	HostPort      int    `json:"hostPort"`
	ServicePort   int    `json:"servicePort,omitempty"`
	Protocol      string `json:"protocol"`
}

type Parameters struct {
	Key   string `json:"key,omitempty"`
	Value string `json:"value,omitempty"`
}

type Volume struct {
	ContainerPath string `json:"containerPath,omitempty"`
	HostPath      string `json:"hostPath,omitempty"`
	Mode          string `json:"mode,omitempty"`
}

type Docker struct {
	Image        string         `json:"image,omitempty"`
	Network      string         `json:"network,omitempty"`
	PortMappings []*PortMapping `json:"portMappings,omitempty"`
	Parameters   []*Parameters  `json:"parameters,omitempty"`
}

func (container *Container) Volume(host_path, container_path, mode string) *Container {
	if container.Volumes == nil {
		container.Volumes = make([]*Volume, 0)
	}
	container.Volumes = append(container.Volumes, &Volume{
		ContainerPath: container_path,
		HostPath:      host_path,
		Mode:          mode,
	})
	return container
}

func NewDockerContainer() *Container {
	container := new(Container)
	container.Type = "DOCKER"
	container.Docker = &Docker{
		Image:        "",
		Network:      "BRIDGE",
		PortMappings: make([]*PortMapping, 0),
		Parameters:   make([]*Parameters, 0),
	}
	container.Volumes = make([]*Volume, 0)
	return container
}

func (docker *Docker) Container(image string) *Docker {
	docker.Image = image
	return docker
}

func (docker *Docker) Bridged() *Docker {
	docker.Network = "BRIDGE"
	return docker
}

func (docker *Docker) Expose(port int) *Docker {
	docker.ExposePort(port, 0, 0, "tcp")
	return docker
}

func (docker *Docker) ExposeUDP(port int) *Docker {
	docker.ExposePort(port, 0, 0, "udp")
	return docker
}

func (docker *Docker) ExposePort(container_port, host_port, service_port int, protocol string) *Docker {
	if docker.PortMappings == nil {
		docker.PortMappings = make([]*PortMapping, 0)
	}
	docker.PortMappings = append(docker.PortMappings, &PortMapping{
		ContainerPort: container_port,
		HostPort:      host_port,
		ServicePort:   service_port,
		Protocol:      protocol})
	return docker
}

func (docker *Docker) AddParameter(key string, value string) *Docker {
	if docker.Parameters == nil {
		docker.Parameters = make([]*Parameters, 0)
	}
	docker.Parameters = append(docker.Parameters, &Parameters{
		Key:   key,
		Value: value})

	return docker
}

func (docker *Docker) ServicePortIndex(port int) (int, error) {
	if docker.PortMappings == nil || len(docker.PortMappings) <= 0 {
		return 0, errors.New("The docker does not contain any port mappings to search")
	}
	/* step: iterate and find the port */
	for index, container_port := range docker.PortMappings {
		if container_port.ContainerPort == port {
			return index, nil
		}
	}
	/* step: we didn't find the port in the mappings */
	return 0, errors.New("The container port required was not found in the container port mappings")
}
<|endoftext|>


<commit_before><commit_msg>handlers: only look for sha1 product if os is "win"<commit_after><|endoftext|>