<commit_before>package utils

import (
	"fmt"
	"image"
	"image/color"
	"math"
	"strconv"
)

/*********	Start 	DrawCircle ********/

func DrawCircle(centerX, centerY, radius, thick int, c color.RGBA, rgba *image.RGBA) {
	minX, maxX := centerX-radius-thick, centerX+radius+thick
	minY, maxY := centerY-radius-thick, centerY+radius+thick
	for x := minX; x < maxX; x++ {
		for y := minY; y < maxY; y++ {
			if possibleCirclePoint(centerX, centerY, x, y, radius, thick) {
				rgba.Set(x, y, c)
			}
		}
	}
}

func possibleCirclePoint(cx, cy, x, y, r, thick int) bool {
	dx, dy := cx-x, cy-y
	if (dx*dx+dy*dy > (r+thick)*(r+thick)) || (dx*dx+dy*dy < (r-thick)*(r-thick)) {
		return false
	}
	return true
}

/*********  Start   DrawLine   ********/
func DrawLine(x0, y0, x1, y1, thick int, c color.RGBA, rgba *image.RGBA) {
	dx := math.Abs(float64(x1 - x0))
	dy := math.Abs(float64(y1 - y0))
	sx, sy := 1, 1
	if x0 >= x1 {
		sx = -1
	}
	if y0 >= y1 {
		sy = -1
	}
	err := dx - dy
	for {
		rgba.Set(x0, y0, c)
		for i := 1; i <= thick; i++ {
			rgba.Set(x0+i, y0, c)
			rgba.Set(x0, y0+i, c)
		}
		if x0 == x1 && y0 == y1 {
			return
		}
		e2 := err * 2
		if e2 > -dy {
			err -= dy
			x0 += sx
		}
		if e2 < dx {
			err += dx
			y0 += sy
		}
	}
}

/*
	*********  Start   DrawDataLineByData   ********
	The first parameter is a map
	In this map, string is the subject's title on each vertex
*/
func DrawDataLineByData(data map[string]int, thick int, rgba *image.RGBA, lineColor, fontColor color.RGBA) {
	/*
		1st layer -- 1000
		2nd layer -- 500
		3rd layer -- 100
	*/
	centerX, centerY := rgba.Bounds().Max.X/2, rgba.Bounds().Max.Y/2
	radius, radians := GetRadiusRadians(rgba, len(data))

	cc, n := 0, len(data)
	x0, x1, fx, y0, y1, fy := 0, 0, 0, 0, 0, 0

	for key, v := range data {
		tmpRadians := radians * float64(cc)
		x0, y0 = x1, y1
		var tmp float64
		if v <= 100 {
			tmp = float64(v) / float64(100) / 3
		} else if v > 100 && v <= 500 {
			tmp = float64(1.0/3.0) + float64(v-100)/float64(400)/3
		} else if v > 500 && v <= 1000 {
			tmp = float64(2.0/3.0) + float64(v-500)/float64(500)/3
		} else {
			tmp = 1.0
		}

		x1 = ToInt(math.Sin(tmpRadians)*tmp*float64(radius)) + centerX
		y1 = ToInt(math.Cos(tmpRadians)*tmp*float64(radius)) + centerY

		if cc == 0 {
			fx, fy = x1, y1
		} else if cc < n-1 {
			DrawLine(x0, y0, x1, y1, thick, lineColor, rgba)
		} else if cc == n-1 {
			DrawLine(x0, y0, x1, y1, thick, lineColor, rgba)
			DrawLine(fx, fy, x1, y1, thick, lineColor, rgba)
		}
		//DrawString
		tx, ty := calFontPosition(x1, y1, centerX, centerY)
		DrawString(tx, ty, key, rgba, fontColor)
		cc++
	}
}

/*
	*********  Start   DrawDataLineByPercentage   ********
	The first parameter is a map
	In this map, string is the subject's title on each vertex
*/
func DrawDataLineByPercentage(data map[string]int, thick int, rgba *image.RGBA, lineColor, fontColor color.RGBA) {
	var sum float64
	for _, v := range data {
		sum += float64(v)
	}
	/*
		1st layer -- 100%
		2nd layer -- 40%
		3rd layer -- 5%
	*/
	centerX, centerY := rgba.Bounds().Max.X/2, rgba.Bounds().Max.Y/2
	radius, radians := GetRadiusRadians(rgba, len(data))

	cc, n := 0, len(data)
	x0, x1, fx, y0, y1, fy := 0, 0, 0, 0, 0, 0

	for key, v := range data {
		fmt.Println(v, float64(v)/sum, getVertexPerByPer(v, sum))

		tmpRadians := radians * float64(cc)
		x0, y0 = x1, y1
		per := getVertexPerByPer(v, sum)
		// per := float64(v) / sum

		// if per <= 0.05 {
		// 	per = per / 0.05 / 3
		// } else if per > 0.05 && per <= 0.4 {
		// 	per = float64(1.0/3.0) + float64((per-0.05)/0.35/3)
		// } else if per > 0.4 && per <= 1 {
		// 	per = float64(2.0/3.0) + float64((per-0.4)/0.6/3)
		//}

		x1 = ToInt(math.Sin(tmpRadians)*per*float64(radius)) + centerX
		y1 = ToInt(math.Cos(tmpRadians)*per*float64(radius)) + centerY

		if cc == 0 {
			fx, fy = x1, y1
		} else if cc < n-1 {
			DrawLine(x0, y0, x1, y1, thick, lineColor, rgba)
		} else if cc == n-1 {
			DrawLine(x0, y0, x1, y1, thick, lineColor, rgba)
			DrawLine(fx, fy, x1, y1, thick, lineColor, rgba)
		}
		//DrawString
		tx, ty := calFontPosition(x1, y1, centerX, centerY)
		DrawString(tx, ty, key, rgba, fontColor)
		cc++
	}
	fmt.Println(subFunc(0))
	fmt.Println(subFunc(1) / subFunc(3))
	fmt.Println(subFunc(2) / subFunc(3))
	fmt.Println(subFunc(3) / subFunc(3))
}

/*
	This function only used for generate point position.

	Get Radius according to the img's X & Y axis.

	Get Radians according to N and radius.
*/
func GetRadiusRadians(img *image.RGBA, n int) (radius int, radians float64) {
	tmpMin := getMinimum(img.Bounds().Max.X, img.Bounds().Max.Y)
	if tmpMin/2 <= 50 {
		radius = tmpMin / 2
	} else {
		radius = tmpMin / 2 * 4 / 5
	}
	radians = math.Pi * 2.0 / float64(n)
	return
}

/**************		Private Function	*******************/
// func getVertexPerByVal() {
// 	key, ok := Config.GetSetting("equal_division")
// 	layers, ok2 := Config.GetSetting("layers")
// 	if !ok {
// 		fmt.Println("equal_division not set in config.conf")
// 		//return 0.0
// 	}
// 	if !ok2 {
// 		fmt.Println("layers not set in config.conf")
// 		//return 0.0
// 	}

// 	if key == "0" {

// 	} else {

// 	}
// }

func getVertexPerByPer(v int, sum float64) float64 {
	// per := float64(v) / sum

	// if per <= 0.05 {
	// 	per = per / 0.05 / 3
	// } else if per > 0.05 && per <= 0.4 {
	// 	per = float64(1.0/3.0) + float64((per-0.05)/0.35/3)
	// } else if per > 0.4 && per <= 1 {
	// 	per = float64(2.0/3.0) + float64((per-0.4)/0.6/3)
	//}
	equal, ok := Config.GetSetting("equal_division")
	l, ok2 := Config.GetSetting("layers")
	if !ok {
		fmt.Println("equal_division not set in config.conf")
		return 0.0
	}
	if !ok2 {
		fmt.Println("layers not set in config.conf")
		return 0.0
	}

	layers, _ := strconv.Atoi(l)

	if equal == "0" {
		per := float64(v) / sum
		ans := 0.0
		dd := subFunc(layers)
		for i := 0; i < layers; i++ {
			tt := subFunc(i) / dd
			if per > tt {
				per -= tt
				ans += subFunc(i) / dd
			} else {
				ans += per / (subFunc(i+1) - subFunc(i))
				break
			}
		}
		return ans
	} else {
		return float64(v) / sum
	}
}

func subFunc(layers int) float64 {
	return math.Sqrt(float64(layers)) + float64(layers)*1.5
}

func getMinimum(tmp ...int) int {
	if len(tmp) == 0 {
		return 0
	}

	if len(tmp) == 1 {
		return tmp[0]
	}

	min := tmp[0]
	for i := range tmp {
		if min > tmp[i] {
			min = tmp[i]
		}
	}
	return min
}

func calFontPosition(x0, y0, centerX, centerY int) (x, y int) {
	offset := 50
	x, y = x0, y0
	if x0 < centerX {
		x = x0 - offset
	} else if x0 > centerX {
		x = x0 + offset
	}

	if y0 < centerY {
		y = y0 - offset
	} else if y0 > centerY {
		y = y + offset

	}
	return
}
<commit_msg>2016-03-29 13:53:54<commit_after>package utils

import (
	"fmt"
	"image"
	"image/color"
	"math"
	"strconv"
)

/*********	Start 	DrawCircle ********/

func DrawCircle(centerX, centerY, radius, thick int, c color.RGBA, rgba *image.RGBA) {
	minX, maxX := centerX-radius-thick, centerX+radius+thick
	minY, maxY := centerY-radius-thick, centerY+radius+thick
	for x := minX; x < maxX; x++ {
		for y := minY; y < maxY; y++ {
			if possibleCirclePoint(centerX, centerY, x, y, radius, thick) {
				rgba.Set(x, y, c)
			}
		}
	}
}

func possibleCirclePoint(cx, cy, x, y, r, thick int) bool {
	dx, dy := cx-x, cy-y
	if (dx*dx+dy*dy > (r+thick)*(r+thick)) || (dx*dx+dy*dy < (r-thick)*(r-thick)) {
		return false
	}
	return true
}

/*********  Start   DrawLine   ********/
func DrawLine(x0, y0, x1, y1, thick int, c color.RGBA, rgba *image.RGBA) {
	dx := math.Abs(float64(x1 - x0))
	dy := math.Abs(float64(y1 - y0))
	sx, sy := 1, 1
	if x0 >= x1 {
		sx = -1
	}
	if y0 >= y1 {
		sy = -1
	}
	err := dx - dy
	for {
		rgba.Set(x0, y0, c)
		for i := 1; i <= thick; i++ {
			rgba.Set(x0+i, y0, c)
			rgba.Set(x0, y0+i, c)
		}
		if x0 == x1 && y0 == y1 {
			return
		}
		e2 := err * 2
		if e2 > -dy {
			err -= dy
			x0 += sx
		}
		if e2 < dx {
			err += dx
			y0 += sy
		}
	}
}

/*
	*********  Start   DrawDataLineByData   ********
	The first parameter is a map
	In this map, string is the subject's title on each vertex
*/
func DrawDataLineByData(data map[string]int, thick int, rgba *image.RGBA, lineColor, fontColor color.RGBA) {
	/*
		1st layer -- 1000
		2nd layer -- 500
		3rd layer -- 100
	*/
	centerX, centerY := rgba.Bounds().Max.X/2, rgba.Bounds().Max.Y/2
	radius, radians := GetRadiusRadians(rgba, len(data))

	cc, n := 0, len(data)
	x0, x1, fx, y0, y1, fy := 0, 0, 0, 0, 0, 0

	for key, v := range data {
		tmpRadians := radians * float64(cc)
		x0, y0 = x1, y1
		var tmp float64
		if v <= 100 {
			tmp = float64(v) / float64(100) / 3
		} else if v > 100 && v <= 500 {
			tmp = float64(1.0/3.0) + float64(v-100)/float64(400)/3
		} else if v > 500 && v <= 1000 {
			tmp = float64(2.0/3.0) + float64(v-500)/float64(500)/3
		} else {
			tmp = 1.0
		}

		x1 = ToInt(math.Sin(tmpRadians)*tmp*float64(radius)) + centerX
		y1 = ToInt(math.Cos(tmpRadians)*tmp*float64(radius)) + centerY

		if cc == 0 {
			fx, fy = x1, y1
		} else if cc < n-1 {
			DrawLine(x0, y0, x1, y1, thick, lineColor, rgba)
		} else if cc == n-1 {
			DrawLine(x0, y0, x1, y1, thick, lineColor, rgba)
			DrawLine(fx, fy, x1, y1, thick, lineColor, rgba)
		}
		//DrawString
		tx, ty := calFontPosition(x1, y1, centerX, centerY)
		DrawString(tx, ty, key, rgba, fontColor)
		cc++
	}
}

/*
	*********  Start   DrawDataLineByPercentage   ********
	The first parameter is a map
	In this map, string is the subject's title on each vertex
*/
func DrawDataLineByPercentage(data map[string]int, thick int, rgba *image.RGBA, lineColor, fontColor color.RGBA) {
	var sum float64
	for _, v := range data {
		sum += float64(v)
	}
	/*
		1st layer -- 100%
		2nd layer -- 40%
		3rd layer -- 5%
	*/
	centerX, centerY := rgba.Bounds().Max.X/2, rgba.Bounds().Max.Y/2
	radius, radians := GetRadiusRadians(rgba, len(data))

	cc, n := 0, len(data)
	x0, x1, fx, y0, y1, fy := 0, 0, 0, 0, 0, 0

	for key, v := range data {
		fmt.Println(v, float64(v)/sum, getVertexPerByPer(v, sum))

		tmpRadians := radians * float64(cc)
		x0, y0 = x1, y1
		//per := getVertexPerByPer(v, sum)
		per := float64(v) / sum

		if per <= 0.05 {
			per = per / 0.05 / 3
		} else if per > 0.05 && per <= 0.4 {
			per = float64(1.0/3.0) + float64((per-0.05)/0.35/3)
		} else if per > 0.4 && per <= 1 {
			per = float64(2.0/3.0) + float64((per-0.4)/0.6/3)
		}

		x1 = ToInt(math.Sin(tmpRadians)*per*float64(radius)) + centerX
		y1 = ToInt(math.Cos(tmpRadians)*per*float64(radius)) + centerY

		if cc == 0 {
			fx, fy = x1, y1
		} else if cc < n-1 {
			DrawLine(x0, y0, x1, y1, thick, lineColor, rgba)
		} else if cc == n-1 {
			DrawLine(x0, y0, x1, y1, thick, lineColor, rgba)
			DrawLine(fx, fy, x1, y1, thick, lineColor, rgba)
		}
		//DrawString
		tx, ty := calFontPosition(x1, y1, centerX, centerY)
		DrawString(tx, ty, key, rgba, fontColor)
		cc++
	}
	fmt.Println(subFunc(0))
	fmt.Println(subFunc(1) / subFunc(3))
	fmt.Println(subFunc(2) / subFunc(3))
	fmt.Println(subFunc(3) / subFunc(3))
}

/*
	This function only used for generate point position.

	Get Radius according to the img's X & Y axis.

	Get Radians according to N and radius.
*/
func GetRadiusRadians(img *image.RGBA, n int) (radius int, radians float64) {
	tmpMin := getMinimum(img.Bounds().Max.X, img.Bounds().Max.Y)
	if tmpMin/2 <= 50 {
		radius = tmpMin / 2
	} else {
		radius = tmpMin / 2 * 4 / 5
	}
	radians = math.Pi * 2.0 / float64(n)
	return
}

/**************		Private Function	*******************/
// func getVertexPerByVal() {
// 	key, ok := Config.GetSetting("equal_division")
// 	layers, ok2 := Config.GetSetting("layers")
// 	if !ok {
// 		fmt.Println("equal_division not set in config.conf")
// 		//return 0.0
// 	}
// 	if !ok2 {
// 		fmt.Println("layers not set in config.conf")
// 		//return 0.0
// 	}

// 	if key == "0" {

// 	} else {

// 	}
// }

func getVertexPerByPer(v int, sum float64) float64 {
	// per := float64(v) / sum

	// if per <= 0.05 {
	// 	per = per / 0.05 / 3
	// } else if per > 0.05 && per <= 0.4 {
	// 	per = float64(1.0/3.0) + float64((per-0.05)/0.35/3)
	// } else if per > 0.4 && per <= 1 {
	// 	per = float64(2.0/3.0) + float64((per-0.4)/0.6/3)
	//}
	equal, ok := Config.GetSetting("equal_division")
	l, ok2 := Config.GetSetting("layers")
	if !ok {
		fmt.Println("equal_division not set in config.conf")
		return 0.0
	}
	if !ok2 {
		fmt.Println("layers not set in config.conf")
		return 0.0
	}

	layers, _ := strconv.Atoi(l)

	if equal == "0" {
		per := float64(v) / sum
		ans := 0.0
		dd := subFunc(layers)
		for i := 0; i < layers; i++ {
			tt := subFunc(i) / dd
			if per > tt {
				per -= tt
				ans += subFunc(i) / dd
			} else {
				ans += per / (subFunc(i+1) - subFunc(i))
				break
			}
		}
		return ans
	} else {
		return float64(v) / sum
	}
}

func subFunc(layers int) float64 {
	return math.Sqrt(float64(layers)) + float64(layers)*1.5
}

func getMinimum(tmp ...int) int {
	if len(tmp) == 0 {
		return 0
	}

	if len(tmp) == 1 {
		return tmp[0]
	}

	min := tmp[0]
	for i := range tmp {
		if min > tmp[i] {
			min = tmp[i]
		}
	}
	return min
}

func calFontPosition(x0, y0, centerX, centerY int) (x, y int) {
	offset := 50
	x, y = x0, y0
	if x0 < centerX {
		x = x0 - offset
	} else if x0 > centerX {
		x = x0 + offset
	}

	if y0 < centerY {
		y = y0 - offset
	} else if y0 > centerY {
		y = y + offset

	}
	return
}
<|endoftext|>


<commit_before>package github

import (
	"errors"
	"net/http"

	"github.com/dghubble/gologin"
	oauth2Login "github.com/dghubble/gologin/oauth2"
	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
)

// Github login errors
var (
	ErrUnableToGetGithubUser = errors.New("github: unable to get Github User")
)

// StateHandler checks for a state cookie. If found, the state value is read
// and added to the ctx. Otherwise, a non-guessable value is added to the ctx
// and to a (short-lived) state cookie issued to the requester.
//
// Implements OAuth 2 RFC 6749 10.12 CSRF Protection. If you wish to issue
// state params differently, write a http.Handler which sets the ctx state,
// using oauth2 WithState(ctx, state) since it is required by LoginHandler
// and CallbackHandler.
func StateHandler(config gologin.CookieConfig, success http.Handler) http.Handler {
	return oauth2Login.StateHandler(config, success)
}

// LoginHandler handles Github login requests by reading the state value from
// the ctx and redirecting requests to the AuthURL with that state value.
func LoginHandler(config *oauth2.Config, failure http.Handler) http.Handler {
	return oauth2Login.LoginHandler(config, failure)
}

// CallbackHandler handles Github redirection URI requests and adds the Github
// access token and User to the ctx. If authentication succeeds, handling
// delegates to the success handler, otherwise to the failure handler.
func CallbackHandler(config *oauth2.Config, success, failure http.Handler) http.Handler {
	success = githubHandler(config, success, failure)
	return oauth2Login.CallbackHandler(config, success, failure)
}

// githubHandler is a http.Handler that gets the OAuth2 Token from the ctx to
// get the corresponding Github User. If successful, the User is added to the
// ctx and the success handler is called. Otherwise, the failure handler is
// called.
func githubHandler(config *oauth2.Config, success, failure http.Handler) http.Handler {
	if failure == nil {
		failure = gologin.DefaultFailureHandler
	}
	fn := func(w http.ResponseWriter, req *http.Request) {
		ctx := req.Context()
		token, err := oauth2Login.TokenFromContext(ctx)
		if err != nil {
			ctx = gologin.WithError(ctx, err)
			failure.ServeHTTP(w, req.WithContext(ctx))
			return
		}
		httpClient := config.Client(ctx, token)
		githubClient := github.NewClient(httpClient)
		user, resp, err := githubClient.Users.Get("")
		err = validateResponse(user, resp, err)
		if err != nil {
			ctx = gologin.WithError(ctx, err)
			failure.ServeHTTP(w, req.WithContext(ctx))
			return
		}
		ctx = WithUser(ctx, user)
		success.ServeHTTP(w, req.WithContext(ctx))
	}
	return http.HandlerFunc(fn)
}

// validateResponse returns an error if the given Github user, raw
// http.Response, or error are unexpected. Returns nil if they are valid.
func validateResponse(user *github.User, resp *github.Response, err error) error {
	if err != nil || resp.StatusCode != http.StatusOK {
		return ErrUnableToGetGithubUser
	}
	if user == nil || user.ID == nil {
		return ErrUnableToGetGithubUser
	}
	return nil
}
<commit_msg>Add context to Github GetUsers call<commit_after>package github

import (
	"errors"
	"net/http"

	"github.com/dghubble/gologin"
	oauth2Login "github.com/dghubble/gologin/oauth2"
	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
)

// Github login errors
var (
	ErrUnableToGetGithubUser = errors.New("github: unable to get Github User")
)

// StateHandler checks for a state cookie. If found, the state value is read
// and added to the ctx. Otherwise, a non-guessable value is added to the ctx
// and to a (short-lived) state cookie issued to the requester.
//
// Implements OAuth 2 RFC 6749 10.12 CSRF Protection. If you wish to issue
// state params differently, write a http.Handler which sets the ctx state,
// using oauth2 WithState(ctx, state) since it is required by LoginHandler
// and CallbackHandler.
func StateHandler(config gologin.CookieConfig, success http.Handler) http.Handler {
	return oauth2Login.StateHandler(config, success)
}

// LoginHandler handles Github login requests by reading the state value from
// the ctx and redirecting requests to the AuthURL with that state value.
func LoginHandler(config *oauth2.Config, failure http.Handler) http.Handler {
	return oauth2Login.LoginHandler(config, failure)
}

// CallbackHandler handles Github redirection URI requests and adds the Github
// access token and User to the ctx. If authentication succeeds, handling
// delegates to the success handler, otherwise to the failure handler.
func CallbackHandler(config *oauth2.Config, success, failure http.Handler) http.Handler {
	success = githubHandler(config, success, failure)
	return oauth2Login.CallbackHandler(config, success, failure)
}

// githubHandler is a http.Handler that gets the OAuth2 Token from the ctx to
// get the corresponding Github User. If successful, the User is added to the
// ctx and the success handler is called. Otherwise, the failure handler is
// called.
func githubHandler(config *oauth2.Config, success, failure http.Handler) http.Handler {
	if failure == nil {
		failure = gologin.DefaultFailureHandler
	}
	fn := func(w http.ResponseWriter, req *http.Request) {
		ctx := req.Context()
		token, err := oauth2Login.TokenFromContext(ctx)
		if err != nil {
			ctx = gologin.WithError(ctx, err)
			failure.ServeHTTP(w, req.WithContext(ctx))
			return
		}
		httpClient := config.Client(ctx, token)
		githubClient := github.NewClient(httpClient)
		user, resp, err := githubClient.Users.Get(ctx, "")
		err = validateResponse(user, resp, err)
		if err != nil {
			ctx = gologin.WithError(ctx, err)
			failure.ServeHTTP(w, req.WithContext(ctx))
			return
		}
		ctx = WithUser(ctx, user)
		success.ServeHTTP(w, req.WithContext(ctx))
	}
	return http.HandlerFunc(fn)
}

// validateResponse returns an error if the given Github user, raw
// http.Response, or error are unexpected. Returns nil if they are valid.
func validateResponse(user *github.User, resp *github.Response, err error) error {
	if err != nil || resp.StatusCode != http.StatusOK {
		return ErrUnableToGetGithubUser
	}
	if user == nil || user.ID == nil {
		return ErrUnableToGetGithubUser
	}
	return nil
}
<|endoftext|>


<commit_before>package utils

import (
	"log"
	text "text/template"

	"html/template"

	"github.com/patrickalin/bloomsky-client-go/assembly"
)

/*
GetTemplate retrieve a template
*/
func GetTemplate(templateName string, templateLocation string, funcs map[string]interface{}, dev bool) *text.Template {
	if dev {
		t, err := text.New(templateName).Funcs(funcs).ParseFiles(templateLocation)

		if err != nil {
			log.Fatalf("Load template console : %v", err)
		}
		return t
	}

	assetBloomsky, err := assembly.Asset(templateLocation)
	t, err := text.New(templateName).Funcs(funcs).Parse(string(assetBloomsky[:]))
	if err != nil {
		log.Fatalf("Load template console : %v", err)
	}
	return t
}

// "bloomsky_header.html","tmpl/bloomsky_header.html",map[string]interface{}{"T": config.translateFunc,}
func GetHtmlTemplate(templateName string, templatesLocation []string, funcs map[string]interface{}, dev bool) *template.Template {
	if dev {
		t := template.New(templateName)
		t.Funcs(funcs)
		t, err := t.ParseFiles(templatesLocation...)

		if err != nil {
			log.Fatalf("Template part 1 : %v", err)
		}

		return t
	}

	asset, err := assembly.Asset(templatesLocation[0])

	if err != nil {
		log.Fatalf("Template part 1 assembly: %v", err)
	}

	t, err := template.New(templateName).Funcs(funcs).Parse(string(asset[:]))

	if err != nil {
		log.Fatalf("Template part 1 : %v", err)
	}
	return t

}
<commit_msg>using asset<commit_after>package utils

import (
	"log"
	text "text/template"

	"html/template"

	"github.com/patrickalin/bloomsky-client-go/assembly"
)

/*
GetTemplate retrieve a template
*/
func GetTemplate(templateName string, templateLocation string, funcs map[string]interface{}, dev bool) *text.Template {
	if dev {
		t, err := text.New(templateName).Funcs(funcs).ParseFiles(templateLocation)

		if err != nil {
			log.Fatalf("Load template console : %v", err)
		}
		return t
	}

	assetBloomsky, err := assembly.Asset(templateLocation)
	t, err := text.New(templateName).Funcs(funcs).Parse(string(assetBloomsky[:]))
	if err != nil {
		log.Fatalf("Load template console : %v", err)
	}
	return t
}

// "bloomsky_header.html","tmpl/bloomsky_header.html",map[string]interface{}{"T": config.translateFunc,}
func GetHtmlTemplate(templateName string, templatesLocation []string, funcs map[string]interface{}, dev bool) *template.Template {
	t := template.New(templateName)
	t.Funcs(funcs)
	if dev {

		t, err := t.ParseFiles(templatesLocation...)

		if err != nil {
			log.Fatalf("Template part 1 : %v", err)
		}

		return t
	}

	for _, l := range templatesLocation {
		asset, err := assembly.Asset(l)

		if err != nil {
			log.Fatalf("Template part 1 assembly: %v", err)
		}
		t, err = t.Parse(string(asset[:]))
		if err != nil {
			log.Fatalf("Template part 1 : %v", err)
		}
	}

	return t

}
<|endoftext|>


<commit_before>package forecast

import (
	"crypto/tls"
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
)

// URL example:  "https://api.forecast.io/forecast/APIKEY/LATITUDE,LONGITUDE,TIME?units=ca"
const (
	BASEURL = "https://api.forecast.io/forecast"
)

type Flags struct {
	DarkSkyUnavailable string
	DarkSkyStations    []string
	DataPointStations  []string
	ISDStations        []string
	LAMPStations       []string
	METARStations      []string
	METNOLicense       string
	Sources            []string
	Units              string
}

type DataPoint struct {
	Time                   float64
	Summary                string
	Icon                   string
	SunriseTime            float64
	SunsetTime             float64
	PrecipIntensity        float64
	PrecipIntensityMax     float64
	PrecipIntensityMaxTime float64
	PrecipProbability      float64
	PrecipType             string
	PrecipAccumulation     float64
	Temperature            float64
	TemperatureMin         float64
	TemperatureMinTime     float64
	TemperatureMax         float64
	TemperatureMaxTime     float64
	DewPoint               float64
	WindSpeed              float64
	WindBearing            float64
	CloudCover             float64
	Humidity               float64
	Pressure               float64
	Visibility             float64
	Ozone                  float64
}

type DataBlock struct {
	Summary string
	Icon    string
	Data    []DataPoint
}

type alert struct {
	Title   string
	Expires float64
	URI     string
}

type Forecast struct {
	Latitude  float64
	Longitude float64
	Timezone  string
	Offset    float64
	Currently DataPoint
	Minutely  DataBlock
	Hourly    DataBlock
	Daily     DataBlock
	Alerts    []alert
	Flags     Flags
	APICalls  int
}

type Units string

const (
	CA Units = "ca"
	SI Units = "si"
)

func Get(key string, lat string, long string, time string, units Units) (*Forecast, error) {
	coord := lat + "," + long

	var url string
	if time == "now" {
		url = BASEURL + "/" + key + "/" + coord + "?units=" + string(units)
	} else {
		url = BASEURL + "/" + key + "/" + coord + "," + time + "?units=" + string(units)
	}

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}
	res, err := client.Get(url)
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Fatal(err)
	}

	var f Forecast
	err = json.Unmarshal(body, &f)
	if err != nil {
		return nil, err
	}

	calls, _ := strconv.Atoi(res.Header.Get("X-Forecast-API-Calls"))
	f.APICalls = calls

	return &f, nil
}
<commit_msg>finally working, was probably always working were it not for my key setup<commit_after>package forecast

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
)

// URL example:  "https://api.forecast.io/forecast/APIKEY/LATITUDE,LONGITUDE,TIME?units=ca"
const (
	BASEURL = "https://api.forecast.io/forecast"
)

type Flags struct {
	DarkSkyUnavailable string
	DarkSkyStations    []string
	DataPointStations  []string
	ISDStations        []string
	LAMPStations       []string
	METARStations      []string
	METNOLicense       string
	Sources            []string
	Units              string
}

type DataPoint struct {
	Time                   float64
	Summary                string
	Icon                   string
	SunriseTime            float64
	SunsetTime             float64
	PrecipIntensity        float64
	PrecipIntensityMax     float64
	PrecipIntensityMaxTime float64
	PrecipProbability      float64
	PrecipType             string
	PrecipAccumulation     float64
	Temperature            float64
	TemperatureMin         float64
	TemperatureMinTime     float64
	TemperatureMax         float64
	TemperatureMaxTime     float64
	DewPoint               float64
	WindSpeed              float64
	WindBearing            float64
	CloudCover             float64
	Humidity               float64
	Pressure               float64
	Visibility             float64
	Ozone                  float64
}

type DataBlock struct {
	Summary string
	Icon    string
	Data    []DataPoint
}

type alert struct {
	Title   string
	Expires float64
	URI     string
}

type Forecast struct {
	Latitude  float64
	Longitude float64
	Timezone  string
	Offset    float64
	Currently DataPoint
	Minutely  DataBlock
	Hourly    DataBlock
	Daily     DataBlock
	Alerts    []alert
	Flags     Flags
	APICalls  int
}

type Units string

const (
	CA Units = "ca"
	SI Units = "si"
)

func Get(key string, lat string, long string, time string, units Units) (*Forecast, error) {
	coord := lat + "," + long

	var url string
	if time == "now" {
		url = BASEURL + "/" + key + "/" + coord + "?units=" + string(units)
	} else {
		url = BASEURL + "/" + key + "/" + coord + "," + time + "?units=" + string(units)
	}

	res, err := http.Get(url)
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Fatal(err)
	}

	var f Forecast
	err = json.Unmarshal(body, &f)
	if err != nil {
		return nil, err
	}

	calls, _ := strconv.Atoi(res.Header.Get("X-Forecast-API-Calls"))
	f.APICalls = calls

	return &f, nil
}
<|endoftext|>


<commit_before>package vault

import (
	"bytes"
	"crypto/rand"
	"errors"
	"io"
	"io/ioutil"
	"os"
	"path"

	"encoding/gob"
	"golang.org/x/crypto/nacl/secretbox"
	"golang.org/x/crypto/scrypt"
)

const (
	scryptN = 16384
	scryptR = 8
	scryptP = 1
	keyLen  = 32
)

var (
	ErrNoSuchCredential = errors.New("credential at specified location does not exist in vault")
	ErrCouldNotDecrypt  = errors.New("provided decryption key is incorrect or the provided vault is corrupt")
)

// Vault is an atomic, consistent, and durable password database, using NACL
// secretbox.
type Vault struct {
	data   []byte
	nonce  [24]byte
	secret [32]byte
}

type Credential struct {
	Username string
	Password string
}

func New(passphrase string) (*Vault, error) {
	var nonce [24]byte
	if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
		return nil, err
	}

	var secret [32]byte
	key, err := scrypt.Key([]byte(passphrase), nonce[:], scryptN, scryptR, scryptP, keyLen)
	if err != nil {
		return nil, err
	}
	copy(secret[:], key)

	v := &Vault{
		nonce:  nonce,
		secret: secret,
	}

	err = v.encrypt(make(map[string]*Credential))
	if err != nil {
		return nil, err
	}

	return v, nil
}

func (v *Vault) decrypt() (map[string]*Credential, error) {
	decryptedData, success := secretbox.Open([]byte{}, v.data[len(v.nonce):], &v.nonce, &v.secret)
	if !success {
		return nil, ErrCouldNotDecrypt
	}

	credentials := make(map[string]*Credential)
	err := gob.NewDecoder(bytes.NewBuffer(decryptedData)).Decode(&credentials)
	if err != nil {
		return nil, err
	}

	return credentials, nil
}

func (v *Vault) encrypt(creds map[string]*Credential) error {
	var buf bytes.Buffer
	err := gob.NewEncoder(&buf).Encode(creds)
	if err != nil {
		return err
	}

	v.data = secretbox.Seal(v.nonce[:], buf.Bytes(), &v.nonce, &v.secret)

	return nil
}

func (v *Vault) Add(location string, credential Credential) error {
	creds, err := v.decrypt()
	if err != nil {
		return err
	}

	creds[location] = &credential

	err = v.encrypt(creds)
	if err != nil {
		return err
	}

	return nil
}

func (v *Vault) Get(location string) (*Credential, error) {
	creds, err := v.decrypt()
	if err != nil {
		return nil, err
	}

	cred, ok := creds[location]
	if !ok {
		return nil, ErrNoSuchCredential
	}
	return cred, nil
}

func (v *Vault) Save(filename string) error {
	tempfile, err := ioutil.TempFile(path.Dir(filename), "passio-temp")
	if err != nil {
		return err
	}

	_, err = io.Copy(tempfile, bytes.NewBuffer(v.data))
	if err != nil {
		return err
	}

	err = os.Rename(tempfile.Name(), filename)
	if err != nil {
		return err
	}

	return nil
}

func Open(filename string, passphrase string) (*Vault, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}

	var encryptedData bytes.Buffer
	_, err = io.Copy(&encryptedData, f)
	if err != nil {
		return nil, err
	}

	var nonce [24]byte
	copy(nonce[:], encryptedData.Bytes()[:24])

	key, err := scrypt.Key([]byte(passphrase), nonce[:], scryptN, scryptR, scryptP, keyLen)
	if err != nil {
		return nil, err
	}

	var secret [32]byte
	copy(secret[:], key)

	vault := &Vault{
		data:   encryptedData.Bytes(),
		nonce:  nonce,
		secret: secret,
	}

	creds, err := vault.decrypt()
	if err != nil {
		return nil, err
	}

	if _, err = io.ReadFull(rand.Reader, nonce[:]); err != nil {
		return nil, err
	}

	key, err = scrypt.Key([]byte(passphrase), nonce[:], scryptN, scryptR, scryptP, keyLen)
	if err != nil {
		return nil, err
	}
	copy(secret[:], key)

	vault.secret = secret
	vault.nonce = nonce
	if err = vault.encrypt(creds); err != nil {
		return nil, err
	}

	return vault, nil
}
<commit_msg>add Locations()<commit_after>package vault

import (
	"bytes"
	"crypto/rand"
	"errors"
	"io"
	"io/ioutil"
	"os"
	"path"

	"encoding/gob"
	"golang.org/x/crypto/nacl/secretbox"
	"golang.org/x/crypto/scrypt"
)

const (
	scryptN = 16384
	scryptR = 8
	scryptP = 1
	keyLen  = 32
)

var (
	ErrNoSuchCredential = errors.New("credential at specified location does not exist in vault")
	ErrCouldNotDecrypt  = errors.New("provided decryption key is incorrect or the provided vault is corrupt")
)

// Vault is an atomic, consistent, and durable password database, using NACL
// secretbox.
type Vault struct {
	data   []byte
	nonce  [24]byte
	secret [32]byte
}

type Credential struct {
	Username string
	Password string
}

func New(passphrase string) (*Vault, error) {
	var nonce [24]byte
	if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
		return nil, err
	}

	var secret [32]byte
	key, err := scrypt.Key([]byte(passphrase), nonce[:], scryptN, scryptR, scryptP, keyLen)
	if err != nil {
		return nil, err
	}
	copy(secret[:], key)

	v := &Vault{
		nonce:  nonce,
		secret: secret,
	}

	err = v.encrypt(make(map[string]*Credential))
	if err != nil {
		return nil, err
	}

	return v, nil
}

func (v *Vault) decrypt() (map[string]*Credential, error) {
	decryptedData, success := secretbox.Open([]byte{}, v.data[len(v.nonce):], &v.nonce, &v.secret)
	if !success {
		return nil, ErrCouldNotDecrypt
	}

	credentials := make(map[string]*Credential)
	err := gob.NewDecoder(bytes.NewBuffer(decryptedData)).Decode(&credentials)
	if err != nil {
		return nil, err
	}

	return credentials, nil
}

func (v *Vault) encrypt(creds map[string]*Credential) error {
	var buf bytes.Buffer
	err := gob.NewEncoder(&buf).Encode(creds)
	if err != nil {
		return err
	}

	v.data = secretbox.Seal(v.nonce[:], buf.Bytes(), &v.nonce, &v.secret)

	return nil
}

func (v *Vault) Add(location string, credential Credential) error {
	creds, err := v.decrypt()
	if err != nil {
		return err
	}

	creds[location] = &credential

	err = v.encrypt(creds)
	if err != nil {
		return err
	}

	return nil
}

func (v *Vault) Get(location string) (*Credential, error) {
	creds, err := v.decrypt()
	if err != nil {
		return nil, err
	}

	cred, ok := creds[location]
	if !ok {
		return nil, ErrNoSuchCredential
	}
	return cred, nil
}

func (v *Vault) Save(filename string) error {
	tempfile, err := ioutil.TempFile(path.Dir(filename), "passio-temp")
	if err != nil {
		return err
	}

	_, err = io.Copy(tempfile, bytes.NewBuffer(v.data))
	if err != nil {
		return err
	}

	err = os.Rename(tempfile.Name(), filename)
	if err != nil {
		return err
	}

	return nil
}

func (v *Vault) Locations() ([]string, error) {
	var locations []string
	creds, err := v.decrypt()
	if err != nil {
		return locations, err
	}

	for location, _ := range creds {
		locations = append(locations, location)
	}
	return locations, nil
}

func Open(filename string, passphrase string) (*Vault, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, err
	}

	var encryptedData bytes.Buffer
	_, err = io.Copy(&encryptedData, f)
	if err != nil {
		return nil, err
	}

	var nonce [24]byte
	copy(nonce[:], encryptedData.Bytes()[:24])

	key, err := scrypt.Key([]byte(passphrase), nonce[:], scryptN, scryptR, scryptP, keyLen)
	if err != nil {
		return nil, err
	}

	var secret [32]byte
	copy(secret[:], key)

	vault := &Vault{
		data:   encryptedData.Bytes(),
		nonce:  nonce,
		secret: secret,
	}

	creds, err := vault.decrypt()
	if err != nil {
		return nil, err
	}

	if _, err = io.ReadFull(rand.Reader, nonce[:]); err != nil {
		return nil, err
	}

	key, err = scrypt.Key([]byte(passphrase), nonce[:], scryptN, scryptR, scryptP, keyLen)
	if err != nil {
		return nil, err
	}
	copy(secret[:], key)

	vault.secret = secret
	vault.nonce = nonce
	if err = vault.encrypt(creds); err != nil {
		return nil, err
	}

	return vault, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Kubernetes Authors.

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

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

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

package common

import (
	"errors"
	"fmt"
	"sync"
	"time"

	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/klog"
	"k8s.io/perf-tests/clusterloader2/pkg/measurement"
	measurementutil "k8s.io/perf-tests/clusterloader2/pkg/measurement/util"
	"k8s.io/perf-tests/clusterloader2/pkg/util"
)

const (
	cpuProfileName    = "CPUProfile"
	memoryProfileName = "MemoryProfile"
	mutexProfileName  = "MutexProfile"
)

func init() {
	if err := measurement.Register(cpuProfileName, createProfileMeasurementFactory(cpuProfileName, "profile")); err != nil {
		klog.Fatalf("Cannot register %s: %v", cpuProfileName, err)
	}
	if err := measurement.Register(memoryProfileName, createProfileMeasurementFactory(memoryProfileName, "heap")); err != nil {
		klog.Fatalf("Cannot register %s: %v", memoryProfileName, err)
	}
	if err := measurement.Register(mutexProfileName, createProfileMeasurementFactory(mutexProfileName, "mutex")); err != nil {
		klog.Fatalf("Cannot register %s: %v", mutexProfileName, err)
	}
}

type profileConfig struct {
	componentName string
	provider      string
	hosts         []string
	kind          string
}

func (p *profileMeasurement) populateProfileConfig(config *measurement.MeasurementConfig) error {
	var err error
	if p.config.componentName, err = util.GetString(config.Params, "componentName"); err != nil {
		return err
	}
	if p.config.provider, err = util.GetStringOrDefault(config.Params, "provider", config.ClusterFramework.GetClusterConfig().Provider); err != nil {
		return err
	}
	return nil
}

type profileMeasurement struct {
	name      string
	config    *profileConfig
	summaries []measurement.Summary
	isRunning bool
	stopCh    chan struct{}
	wg        sync.WaitGroup
}

func createProfileMeasurementFactory(name, kind string) func() measurement.Measurement {
	return func() measurement.Measurement {
		return &profileMeasurement{
			name:   name,
			config: &profileConfig{kind: kind},
		}
	}
}

func (p *profileMeasurement) start(config *measurement.MeasurementConfig) error {
	p.config.hosts = config.ClusterFramework.GetClusterConfig().MasterIPs
	if len(p.config.hosts) < 1 {
		return errors.New("Profile measurements will be disabled due to no MasterIps")
	}

	if err := p.populateProfileConfig(config); err != nil {
		return err
	}
	p.summaries = make([]measurement.Summary, 0)
	p.isRunning = true
	p.stopCh = make(chan struct{})
	p.wg.Add(1)

	// Currently length of the test is proportional to the cluster size.
	// So for now we make the profiling frequency proportional to the cluster size.
	// We may want to revisit ot adjust it in the future.
	numNodes := config.ClusterFramework.GetClusterConfig().Nodes
	profileFrequency := time.Duration(5+numNodes/250) * time.Minute

	go func() {
		defer p.wg.Done()
		for {
			select {
			case <-p.stopCh:
				return
			case <-time.After(profileFrequency):
				profileSummaries, err := p.gatherProfile(config.ClusterFramework.GetClientSets().GetClient())
				if err != nil {
					klog.Errorf("failed to gather profile for %#v: %v", *p.config, err)
					continue
				}
				if profileSummaries != nil {
					p.summaries = append(p.summaries, profileSummaries...)
				}
			}
		}
	}()
	return nil
}

func (p *profileMeasurement) stop() {
	if !p.isRunning {
		return
	}
	close(p.stopCh)
	p.wg.Wait()
}

// Execute gathers memory profile of a given component.
func (p *profileMeasurement) Execute(config *measurement.MeasurementConfig) ([]measurement.Summary, error) {
	action, err := util.GetString(config.Params, "action")
	if err != nil {
		return nil, err
	}

	switch action {
	case "start":
		if p.isRunning {
			klog.Infof("%s: measurement already running", p)
			return nil, nil
		}
		return nil, p.start(config)
	case "gather":
		p.stop()
		return p.summaries, nil
	default:
		return nil, fmt.Errorf("unknown action %v", action)
	}
}

// Dispose cleans up after the measurement.
func (*profileMeasurement) Dispose() {}

// String returns string representation of this measurement.
func (p *profileMeasurement) String() string {
	return p.name
}

func (p *profileMeasurement) gatherProfile(c clientset.Interface) ([]measurement.Summary, error) {
	profilePort, err := getPortForComponent(p.config.componentName)
	if err != nil {
		return nil, fmt.Errorf("profile gathering failed finding component port: %v", err)
	}
	getCommand := fmt.Sprintf("curl -s localhost:%v/debug/pprof/%s", profilePort, p.config.kind)

	var summaries []measurement.Summary
	for _, host := range p.config.hosts {
		profilePrefix := fmt.Sprintf("%s_%s_%s", host, p.config.componentName, p.name)

		if p.config.componentName == "kube-apiserver" {
			body, err := c.CoreV1().RESTClient().Get().AbsPath("/debug/pprof/" + p.config.kind).DoRaw()
			if err != nil {
				return nil, err
			}
			summary := measurement.CreateSummary(profilePrefix, "pprof", string(body))
			summaries = append(summaries, summary)
			break
		}

		// Get the profile data over SSH.
		// Start by checking that the provider allows us to do so.
		if p.config.provider == "gke" {
			// Only logging error for gke. SSHing to gke master is not supported.
			klog.Warningf("%s: failed to execute curl command on master through SSH", p.name)
			return nil, nil
		}

		sshResult, err := measurementutil.SSH(getCommand, host+":22", p.config.provider)
		if err != nil {
			return nil, fmt.Errorf("failed to execute curl command on master node %s through SSH: %v", host, err)
		}
		summaries = append(summaries, measurement.CreateSummary(profilePrefix, "pprof", sshResult.Stdout))
	}

	return summaries, nil
}

func getPortForComponent(componentName string) (int, error) {
	switch componentName {
	case "etcd":
		return 2379, nil
	case "kube-scheduler":
		return 10251, nil
	case "kube-controller-manager":
		return 10252, nil
	}
	return -1, fmt.Errorf("port for component %v unknown", componentName)
}
<commit_msg>Profile measurements should warn instead of fail on lack of master IPs<commit_after>/*
Copyright 2018 The Kubernetes Authors.

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

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

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

package common

import (
	"fmt"
	"sync"
	"time"

	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/klog"
	"k8s.io/perf-tests/clusterloader2/pkg/measurement"
	measurementutil "k8s.io/perf-tests/clusterloader2/pkg/measurement/util"
	"k8s.io/perf-tests/clusterloader2/pkg/util"
)

const (
	cpuProfileName    = "CPUProfile"
	memoryProfileName = "MemoryProfile"
	mutexProfileName  = "MutexProfile"
)

func init() {
	if err := measurement.Register(cpuProfileName, createProfileMeasurementFactory(cpuProfileName, "profile")); err != nil {
		klog.Fatalf("Cannot register %s: %v", cpuProfileName, err)
	}
	if err := measurement.Register(memoryProfileName, createProfileMeasurementFactory(memoryProfileName, "heap")); err != nil {
		klog.Fatalf("Cannot register %s: %v", memoryProfileName, err)
	}
	if err := measurement.Register(mutexProfileName, createProfileMeasurementFactory(mutexProfileName, "mutex")); err != nil {
		klog.Fatalf("Cannot register %s: %v", mutexProfileName, err)
	}
}

type profileConfig struct {
	componentName string
	provider      string
	hosts         []string
	kind          string
}

func (p *profileMeasurement) populateProfileConfig(config *measurement.MeasurementConfig) error {
	var err error
	if p.config.componentName, err = util.GetString(config.Params, "componentName"); err != nil {
		return err
	}
	if p.config.provider, err = util.GetStringOrDefault(config.Params, "provider", config.ClusterFramework.GetClusterConfig().Provider); err != nil {
		return err
	}
	p.config.hosts = config.ClusterFramework.GetClusterConfig().MasterIPs
	return nil
}

type profileMeasurement struct {
	name      string
	config    *profileConfig
	summaries []measurement.Summary
	isRunning bool
	stopCh    chan struct{}
	wg        sync.WaitGroup
}

func createProfileMeasurementFactory(name, kind string) func() measurement.Measurement {
	return func() measurement.Measurement {
		return &profileMeasurement{
			name:   name,
			config: &profileConfig{kind: kind},
		}
	}
}

func (p *profileMeasurement) start(config *measurement.MeasurementConfig) error {
	if err := p.populateProfileConfig(config); err != nil {
		return err
	}
	if len(p.config.hosts) < 1 {
		klog.Warning("Profile measurements will be disabled due to no MasterIps")
		return nil
	}

	p.summaries = make([]measurement.Summary, 0)
	p.isRunning = true
	p.stopCh = make(chan struct{})
	p.wg.Add(1)

	// Currently length of the test is proportional to the cluster size.
	// So for now we make the profiling frequency proportional to the cluster size.
	// We may want to revisit ot adjust it in the future.
	numNodes := config.ClusterFramework.GetClusterConfig().Nodes
	profileFrequency := time.Duration(5+numNodes/250) * time.Minute

	go func() {
		defer p.wg.Done()
		for {
			select {
			case <-p.stopCh:
				return
			case <-time.After(profileFrequency):
				profileSummaries, err := p.gatherProfile(config.ClusterFramework.GetClientSets().GetClient())
				if err != nil {
					klog.Errorf("failed to gather profile for %#v: %v", *p.config, err)
					continue
				}
				if profileSummaries != nil {
					p.summaries = append(p.summaries, profileSummaries...)
				}
			}
		}
	}()
	return nil
}

func (p *profileMeasurement) stop() {
	if !p.isRunning {
		return
	}
	close(p.stopCh)
	p.wg.Wait()
}

// Execute gathers memory profile of a given component.
func (p *profileMeasurement) Execute(config *measurement.MeasurementConfig) ([]measurement.Summary, error) {
	action, err := util.GetString(config.Params, "action")
	if err != nil {
		return nil, err
	}

	switch action {
	case "start":
		if p.isRunning {
			klog.Infof("%s: measurement already running", p)
			return nil, nil
		}
		return nil, p.start(config)
	case "gather":
		p.stop()
		return p.summaries, nil
	default:
		return nil, fmt.Errorf("unknown action %v", action)
	}
}

// Dispose cleans up after the measurement.
func (*profileMeasurement) Dispose() {}

// String returns string representation of this measurement.
func (p *profileMeasurement) String() string {
	return p.name
}

func (p *profileMeasurement) gatherProfile(c clientset.Interface) ([]measurement.Summary, error) {
	profilePort, err := getPortForComponent(p.config.componentName)
	if err != nil {
		return nil, fmt.Errorf("profile gathering failed finding component port: %v", err)
	}
	getCommand := fmt.Sprintf("curl -s localhost:%v/debug/pprof/%s", profilePort, p.config.kind)

	var summaries []measurement.Summary
	for _, host := range p.config.hosts {
		profilePrefix := fmt.Sprintf("%s_%s_%s", host, p.config.componentName, p.name)

		if p.config.componentName == "kube-apiserver" {
			body, err := c.CoreV1().RESTClient().Get().AbsPath("/debug/pprof/" + p.config.kind).DoRaw()
			if err != nil {
				return nil, err
			}
			summary := measurement.CreateSummary(profilePrefix, "pprof", string(body))
			summaries = append(summaries, summary)
			break
		}

		// Get the profile data over SSH.
		// Start by checking that the provider allows us to do so.
		if p.config.provider == "gke" {
			// Only logging error for gke. SSHing to gke master is not supported.
			klog.Warningf("%s: failed to execute curl command on master through SSH", p.name)
			return nil, nil
		}

		sshResult, err := measurementutil.SSH(getCommand, host+":22", p.config.provider)
		if err != nil {
			return nil, fmt.Errorf("failed to execute curl command on master node %s through SSH: %v", host, err)
		}
		summaries = append(summaries, measurement.CreateSummary(profilePrefix, "pprof", sshResult.Stdout))
	}

	return summaries, nil
}

func getPortForComponent(componentName string) (int, error) {
	switch componentName {
	case "etcd":
		return 2379, nil
	case "kube-scheduler":
		return 10251, nil
	case "kube-controller-manager":
		return 10252, nil
	}
	return -1, fmt.Errorf("port for component %v unknown", componentName)
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package config

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net"
	"strconv"

	"github.com/pkg/errors"
	"k8s.io/klog"

	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	netutil "k8s.io/apimachinery/pkg/util/net"
	bootstraputil "k8s.io/cluster-bootstrap/token/util"
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
	kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
	kubeadmapiv1beta2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2"
	"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
	"k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
	kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
	kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
	"k8s.io/kubernetes/cmd/kubeadm/app/util/config/strict"
	kubeadmruntime "k8s.io/kubernetes/cmd/kubeadm/app/util/runtime"
)

// SetInitDynamicDefaults checks and sets configuration values for the InitConfiguration object
func SetInitDynamicDefaults(cfg *kubeadmapi.InitConfiguration) error {
	if err := SetBootstrapTokensDynamicDefaults(&cfg.BootstrapTokens); err != nil {
		return err
	}
	if err := SetNodeRegistrationDynamicDefaults(&cfg.NodeRegistration, true); err != nil {
		return err
	}
	if err := SetAPIEndpointDynamicDefaults(&cfg.LocalAPIEndpoint); err != nil {
		return err
	}
	return SetClusterDynamicDefaults(&cfg.ClusterConfiguration, &cfg.LocalAPIEndpoint)
}

// SetBootstrapTokensDynamicDefaults checks and sets configuration values for the BootstrapTokens object
func SetBootstrapTokensDynamicDefaults(cfg *[]kubeadmapi.BootstrapToken) error {
	// Populate the .Token field with a random value if unset
	// We do this at this layer, and not the API defaulting layer
	// because of possible security concerns, and more practically
	// because we can't return errors in the API object defaulting
	// process but here we can.
	for i, bt := range *cfg {
		if bt.Token != nil && len(bt.Token.String()) > 0 {
			continue
		}

		tokenStr, err := bootstraputil.GenerateBootstrapToken()
		if err != nil {
			return errors.Wrap(err, "couldn't generate random token")
		}
		token, err := kubeadmapi.NewBootstrapTokenString(tokenStr)
		if err != nil {
			return err
		}
		(*cfg)[i].Token = token
	}

	return nil
}

// SetNodeRegistrationDynamicDefaults checks and sets configuration values for the NodeRegistration object
func SetNodeRegistrationDynamicDefaults(cfg *kubeadmapi.NodeRegistrationOptions, ControlPlaneTaint bool) error {
	var err error
	cfg.Name, err = kubeadmutil.GetHostname(cfg.Name)
	if err != nil {
		return err
	}

	// Only if the slice is nil, we should append the control-plane taint. This allows the user to specify an empty slice for no default control-plane taint
	if ControlPlaneTaint && cfg.Taints == nil {
		cfg.Taints = []v1.Taint{kubeadmconstants.ControlPlaneTaint}
	}

	if cfg.CRISocket == "" {
		cfg.CRISocket, err = kubeadmruntime.DetectCRISocket()
		if err != nil {
			return err
		}
		klog.V(1).Infof("detected and using CRI socket: %s", cfg.CRISocket)
	}

	return nil
}

// SetAPIEndpointDynamicDefaults checks and sets configuration values for the APIEndpoint object
func SetAPIEndpointDynamicDefaults(cfg *kubeadmapi.APIEndpoint) error {
	// validate cfg.API.AdvertiseAddress.
	addressIP := net.ParseIP(cfg.AdvertiseAddress)
	if addressIP == nil && cfg.AdvertiseAddress != "" {
		return errors.Errorf("couldn't use \"%s\" as \"apiserver-advertise-address\", must be ipv4 or ipv6 address", cfg.AdvertiseAddress)
	}

	// kubeadm allows users to specify address=Loopback as a selector for global unicast IP address that can be found on loopback interface.
	// e.g. This is required for network setups where default routes are present, but network interfaces use only link-local addresses (e.g. as described in RFC5549).
	if addressIP.IsLoopback() {
		loopbackIP, err := netutil.ChooseBindAddressForInterface(netutil.LoopbackInterfaceName)
		if err != nil {
			return err
		}
		if loopbackIP != nil {
			klog.V(4).Infof("Found active IP %v on loopback interface", loopbackIP.String())
			cfg.AdvertiseAddress = loopbackIP.String()
			return nil
		}
		return errors.New("unable to resolve link-local addresses")
	}

	// This is the same logic as the API Server uses, except that if no interface is found the address is set to 0.0.0.0, which is invalid and cannot be used
	// for bootstrapping a cluster.
	ip, err := ChooseAPIServerBindAddress(addressIP)
	if err != nil {
		return err
	}
	cfg.AdvertiseAddress = ip.String()

	return nil
}

// SetClusterDynamicDefaults checks and sets values for the ClusterConfiguration object
func SetClusterDynamicDefaults(cfg *kubeadmapi.ClusterConfiguration, LocalAPIEndpoint *kubeadmapi.APIEndpoint) error {
	// Default all the embedded ComponentConfig structs
	componentconfigs.Default(cfg, LocalAPIEndpoint)

	// Resolve possible version labels and validate version string
	if err := NormalizeKubernetesVersion(cfg); err != nil {
		return err
	}

	// If ControlPlaneEndpoint is specified without a port number defaults it to
	// the bindPort number of the APIEndpoint.
	// This will allow join of additional control plane instances with different bindPort number
	if cfg.ControlPlaneEndpoint != "" {
		host, port, err := kubeadmutil.ParseHostPort(cfg.ControlPlaneEndpoint)
		if err != nil {
			return err
		}
		if port == "" {
			cfg.ControlPlaneEndpoint = net.JoinHostPort(host, strconv.FormatInt(int64(LocalAPIEndpoint.BindPort), 10))
		}
	}

	// Downcase SANs. Some domain names (like ELBs) have capitals in them.
	LowercaseSANs(cfg.APIServer.CertSANs)
	return nil
}

// DefaultedInitConfiguration takes a versioned init config (often populated by flags), defaults it and converts it into internal InitConfiguration
func DefaultedInitConfiguration(versionedInitCfg *kubeadmapiv1beta2.InitConfiguration, versionedClusterCfg *kubeadmapiv1beta2.ClusterConfiguration) (*kubeadmapi.InitConfiguration, error) {
	internalcfg := &kubeadmapi.InitConfiguration{}

	// Takes passed flags into account; the defaulting is executed once again enforcing assignment of
	// static default values to cfg only for values not provided with flags
	kubeadmscheme.Scheme.Default(versionedInitCfg)
	if err := kubeadmscheme.Scheme.Convert(versionedInitCfg, internalcfg, nil); err != nil {
		return nil, err
	}

	kubeadmscheme.Scheme.Default(versionedClusterCfg)
	if err := kubeadmscheme.Scheme.Convert(versionedClusterCfg, &internalcfg.ClusterConfiguration, nil); err != nil {
		return nil, err
	}

	// Applies dynamic defaults to settings not provided with flags
	if err := SetInitDynamicDefaults(internalcfg); err != nil {
		return nil, err
	}
	// Validates cfg (flags/configs + defaults + dynamic defaults)
	if err := validation.ValidateInitConfiguration(internalcfg).ToAggregate(); err != nil {
		return nil, err
	}
	return internalcfg, nil
}

// LoadInitConfigurationFromFile loads a supported versioned InitConfiguration from a file, converts it into internal config, defaults it and verifies it.
func LoadInitConfigurationFromFile(cfgPath string) (*kubeadmapi.InitConfiguration, error) {
	klog.V(1).Infof("loading configuration from %q", cfgPath)

	b, err := ioutil.ReadFile(cfgPath)
	if err != nil {
		return nil, errors.Wrapf(err, "unable to read config from %q ", cfgPath)
	}

	return BytesToInitConfiguration(b)
}

// LoadOrDefaultInitConfiguration takes a path to a config file and a versioned configuration that can serve as the default config
// If cfgPath is specified, the versioned configs will always get overridden with the one in the file (specified by cfgPath).
// The external, versioned configuration is defaulted and converted to the internal type.
// Right thereafter, the configuration is defaulted again with dynamic values (like IP addresses of a machine, etc)
// Lastly, the internal config is validated and returned.
func LoadOrDefaultInitConfiguration(cfgPath string, versionedInitCfg *kubeadmapiv1beta2.InitConfiguration, versionedClusterCfg *kubeadmapiv1beta2.ClusterConfiguration) (*kubeadmapi.InitConfiguration, error) {
	if cfgPath != "" {
		// Loads configuration from config file, if provided
		// Nb. --config overrides command line flags
		return LoadInitConfigurationFromFile(cfgPath)
	}

	return DefaultedInitConfiguration(versionedInitCfg, versionedClusterCfg)
}

// BytesToInitConfiguration converts a byte slice to an internal, defaulted and validated InitConfiguration object.
// The map may contain many different YAML documents. These YAML documents are parsed one-by-one
// and well-known ComponentConfig GroupVersionKinds are stored inside of the internal InitConfiguration struct.
// The resulting InitConfiguration is then dynamically defaulted and validated prior to return.
func BytesToInitConfiguration(b []byte) (*kubeadmapi.InitConfiguration, error) {
	gvkmap, err := kubeadmutil.SplitYAMLDocuments(b)
	if err != nil {
		return nil, err
	}

	return documentMapToInitConfiguration(gvkmap, false)
}

// documentMapToInitConfiguration converts a map of GVKs and YAML documents to defaulted and validated configuration object.
func documentMapToInitConfiguration(gvkmap kubeadmapi.DocumentMap, allowDeprecated bool) (*kubeadmapi.InitConfiguration, error) {
	var initcfg *kubeadmapi.InitConfiguration
	var clustercfg *kubeadmapi.ClusterConfiguration

	for gvk, fileContent := range gvkmap {
		// first, check if this GVK is supported and possibly not deprecated
		if err := validateSupportedVersion(gvk.GroupVersion(), allowDeprecated); err != nil {
			return nil, err
		}

		// verify the validity of the YAML
		strict.VerifyUnmarshalStrict(fileContent, gvk)

		if kubeadmutil.GroupVersionKindsHasInitConfiguration(gvk) {
			// Set initcfg to an empty struct value the deserializer will populate
			initcfg = &kubeadmapi.InitConfiguration{}
			// Decode the bytes into the internal struct. Under the hood, the bytes will be unmarshalled into the
			// right external version, defaulted, and converted into the internal version.
			if err := runtime.DecodeInto(kubeadmscheme.Codecs.UniversalDecoder(), fileContent, initcfg); err != nil {
				return nil, err
			}
			continue
		}
		if kubeadmutil.GroupVersionKindsHasClusterConfiguration(gvk) {
			// Set clustercfg to an empty struct value the deserializer will populate
			clustercfg = &kubeadmapi.ClusterConfiguration{}
			// Decode the bytes into the internal struct. Under the hood, the bytes will be unmarshalled into the
			// right external version, defaulted, and converted into the internal version.
			if err := runtime.DecodeInto(kubeadmscheme.Codecs.UniversalDecoder(), fileContent, clustercfg); err != nil {
				return nil, err
			}
			continue
		}

		fmt.Printf("[config] WARNING: Ignored YAML document with GroupVersionKind %v\n", gvk)
	}

	// Enforce that InitConfiguration and/or ClusterConfiguration has to exist among the YAML documents
	if initcfg == nil && clustercfg == nil {
		return nil, errors.New("no InitConfiguration or ClusterConfiguration kind was found in the YAML file")
	}

	// If InitConfiguration wasn't given, default it by creating an external struct instance, default it and convert into the internal type
	if initcfg == nil {
		extinitcfg := &kubeadmapiv1beta2.InitConfiguration{}
		kubeadmscheme.Scheme.Default(extinitcfg)
		// Set initcfg to an empty struct value the deserializer will populate
		initcfg = &kubeadmapi.InitConfiguration{}
		if err := kubeadmscheme.Scheme.Convert(extinitcfg, initcfg, nil); err != nil {
			return nil, err
		}
	}
	// If ClusterConfiguration was given, populate it in the InitConfiguration struct
	if clustercfg != nil {
		initcfg.ClusterConfiguration = *clustercfg
	}

	// Load any component configs
	if err := componentconfigs.FetchFromDocumentMap(&initcfg.ClusterConfiguration, gvkmap); err != nil {
		return nil, err
	}

	// Applies dynamic defaults to settings not provided with flags
	if err := SetInitDynamicDefaults(initcfg); err != nil {
		return nil, err
	}

	// Validates cfg (flags/configs + defaults + dynamic defaults)
	if err := validation.ValidateInitConfiguration(initcfg).ToAggregate(); err != nil {
		return nil, err
	}

	return initcfg, nil
}

// MarshalInitConfigurationToBytes marshals the internal InitConfiguration object to bytes. It writes the embedded
// ClusterConfiguration object with ComponentConfigs out as separate YAML documents
func MarshalInitConfigurationToBytes(cfg *kubeadmapi.InitConfiguration, gv schema.GroupVersion) ([]byte, error) {
	initbytes, err := kubeadmutil.MarshalToYamlForCodecs(cfg, gv, kubeadmscheme.Codecs)
	if err != nil {
		return []byte{}, err
	}
	allFiles := [][]byte{initbytes}

	// Exception: If the specified groupversion is targeting the internal type, don't print embedded ClusterConfiguration contents
	// This is mostly used for unit testing. In a real scenario the internal version of the API is never marshalled as-is.
	if gv.Version != runtime.APIVersionInternal {
		clusterbytes, err := kubeadmutil.MarshalToYamlForCodecs(&cfg.ClusterConfiguration, gv, kubeadmscheme.Codecs)
		if err != nil {
			return []byte{}, err
		}
		allFiles = append(allFiles, clusterbytes)
	}
	return bytes.Join(allFiles, []byte(kubeadmconstants.YAMLDocumentSeparator)), nil
}
<commit_msg>kubeadm: Fix a false positive in a warning<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package config

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net"
	"strconv"

	"github.com/pkg/errors"
	"k8s.io/klog"

	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	netutil "k8s.io/apimachinery/pkg/util/net"
	bootstraputil "k8s.io/cluster-bootstrap/token/util"
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
	kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
	kubeadmapiv1beta2 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2"
	"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/validation"
	"k8s.io/kubernetes/cmd/kubeadm/app/componentconfigs"
	kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
	kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
	"k8s.io/kubernetes/cmd/kubeadm/app/util/config/strict"
	kubeadmruntime "k8s.io/kubernetes/cmd/kubeadm/app/util/runtime"
)

// SetInitDynamicDefaults checks and sets configuration values for the InitConfiguration object
func SetInitDynamicDefaults(cfg *kubeadmapi.InitConfiguration) error {
	if err := SetBootstrapTokensDynamicDefaults(&cfg.BootstrapTokens); err != nil {
		return err
	}
	if err := SetNodeRegistrationDynamicDefaults(&cfg.NodeRegistration, true); err != nil {
		return err
	}
	if err := SetAPIEndpointDynamicDefaults(&cfg.LocalAPIEndpoint); err != nil {
		return err
	}
	return SetClusterDynamicDefaults(&cfg.ClusterConfiguration, &cfg.LocalAPIEndpoint)
}

// SetBootstrapTokensDynamicDefaults checks and sets configuration values for the BootstrapTokens object
func SetBootstrapTokensDynamicDefaults(cfg *[]kubeadmapi.BootstrapToken) error {
	// Populate the .Token field with a random value if unset
	// We do this at this layer, and not the API defaulting layer
	// because of possible security concerns, and more practically
	// because we can't return errors in the API object defaulting
	// process but here we can.
	for i, bt := range *cfg {
		if bt.Token != nil && len(bt.Token.String()) > 0 {
			continue
		}

		tokenStr, err := bootstraputil.GenerateBootstrapToken()
		if err != nil {
			return errors.Wrap(err, "couldn't generate random token")
		}
		token, err := kubeadmapi.NewBootstrapTokenString(tokenStr)
		if err != nil {
			return err
		}
		(*cfg)[i].Token = token
	}

	return nil
}

// SetNodeRegistrationDynamicDefaults checks and sets configuration values for the NodeRegistration object
func SetNodeRegistrationDynamicDefaults(cfg *kubeadmapi.NodeRegistrationOptions, ControlPlaneTaint bool) error {
	var err error
	cfg.Name, err = kubeadmutil.GetHostname(cfg.Name)
	if err != nil {
		return err
	}

	// Only if the slice is nil, we should append the control-plane taint. This allows the user to specify an empty slice for no default control-plane taint
	if ControlPlaneTaint && cfg.Taints == nil {
		cfg.Taints = []v1.Taint{kubeadmconstants.ControlPlaneTaint}
	}

	if cfg.CRISocket == "" {
		cfg.CRISocket, err = kubeadmruntime.DetectCRISocket()
		if err != nil {
			return err
		}
		klog.V(1).Infof("detected and using CRI socket: %s", cfg.CRISocket)
	}

	return nil
}

// SetAPIEndpointDynamicDefaults checks and sets configuration values for the APIEndpoint object
func SetAPIEndpointDynamicDefaults(cfg *kubeadmapi.APIEndpoint) error {
	// validate cfg.API.AdvertiseAddress.
	addressIP := net.ParseIP(cfg.AdvertiseAddress)
	if addressIP == nil && cfg.AdvertiseAddress != "" {
		return errors.Errorf("couldn't use \"%s\" as \"apiserver-advertise-address\", must be ipv4 or ipv6 address", cfg.AdvertiseAddress)
	}

	// kubeadm allows users to specify address=Loopback as a selector for global unicast IP address that can be found on loopback interface.
	// e.g. This is required for network setups where default routes are present, but network interfaces use only link-local addresses (e.g. as described in RFC5549).
	if addressIP.IsLoopback() {
		loopbackIP, err := netutil.ChooseBindAddressForInterface(netutil.LoopbackInterfaceName)
		if err != nil {
			return err
		}
		if loopbackIP != nil {
			klog.V(4).Infof("Found active IP %v on loopback interface", loopbackIP.String())
			cfg.AdvertiseAddress = loopbackIP.String()
			return nil
		}
		return errors.New("unable to resolve link-local addresses")
	}

	// This is the same logic as the API Server uses, except that if no interface is found the address is set to 0.0.0.0, which is invalid and cannot be used
	// for bootstrapping a cluster.
	ip, err := ChooseAPIServerBindAddress(addressIP)
	if err != nil {
		return err
	}
	cfg.AdvertiseAddress = ip.String()

	return nil
}

// SetClusterDynamicDefaults checks and sets values for the ClusterConfiguration object
func SetClusterDynamicDefaults(cfg *kubeadmapi.ClusterConfiguration, LocalAPIEndpoint *kubeadmapi.APIEndpoint) error {
	// Default all the embedded ComponentConfig structs
	componentconfigs.Default(cfg, LocalAPIEndpoint)

	// Resolve possible version labels and validate version string
	if err := NormalizeKubernetesVersion(cfg); err != nil {
		return err
	}

	// If ControlPlaneEndpoint is specified without a port number defaults it to
	// the bindPort number of the APIEndpoint.
	// This will allow join of additional control plane instances with different bindPort number
	if cfg.ControlPlaneEndpoint != "" {
		host, port, err := kubeadmutil.ParseHostPort(cfg.ControlPlaneEndpoint)
		if err != nil {
			return err
		}
		if port == "" {
			cfg.ControlPlaneEndpoint = net.JoinHostPort(host, strconv.FormatInt(int64(LocalAPIEndpoint.BindPort), 10))
		}
	}

	// Downcase SANs. Some domain names (like ELBs) have capitals in them.
	LowercaseSANs(cfg.APIServer.CertSANs)
	return nil
}

// DefaultedInitConfiguration takes a versioned init config (often populated by flags), defaults it and converts it into internal InitConfiguration
func DefaultedInitConfiguration(versionedInitCfg *kubeadmapiv1beta2.InitConfiguration, versionedClusterCfg *kubeadmapiv1beta2.ClusterConfiguration) (*kubeadmapi.InitConfiguration, error) {
	internalcfg := &kubeadmapi.InitConfiguration{}

	// Takes passed flags into account; the defaulting is executed once again enforcing assignment of
	// static default values to cfg only for values not provided with flags
	kubeadmscheme.Scheme.Default(versionedInitCfg)
	if err := kubeadmscheme.Scheme.Convert(versionedInitCfg, internalcfg, nil); err != nil {
		return nil, err
	}

	kubeadmscheme.Scheme.Default(versionedClusterCfg)
	if err := kubeadmscheme.Scheme.Convert(versionedClusterCfg, &internalcfg.ClusterConfiguration, nil); err != nil {
		return nil, err
	}

	// Applies dynamic defaults to settings not provided with flags
	if err := SetInitDynamicDefaults(internalcfg); err != nil {
		return nil, err
	}
	// Validates cfg (flags/configs + defaults + dynamic defaults)
	if err := validation.ValidateInitConfiguration(internalcfg).ToAggregate(); err != nil {
		return nil, err
	}
	return internalcfg, nil
}

// LoadInitConfigurationFromFile loads a supported versioned InitConfiguration from a file, converts it into internal config, defaults it and verifies it.
func LoadInitConfigurationFromFile(cfgPath string) (*kubeadmapi.InitConfiguration, error) {
	klog.V(1).Infof("loading configuration from %q", cfgPath)

	b, err := ioutil.ReadFile(cfgPath)
	if err != nil {
		return nil, errors.Wrapf(err, "unable to read config from %q ", cfgPath)
	}

	return BytesToInitConfiguration(b)
}

// LoadOrDefaultInitConfiguration takes a path to a config file and a versioned configuration that can serve as the default config
// If cfgPath is specified, the versioned configs will always get overridden with the one in the file (specified by cfgPath).
// The external, versioned configuration is defaulted and converted to the internal type.
// Right thereafter, the configuration is defaulted again with dynamic values (like IP addresses of a machine, etc)
// Lastly, the internal config is validated and returned.
func LoadOrDefaultInitConfiguration(cfgPath string, versionedInitCfg *kubeadmapiv1beta2.InitConfiguration, versionedClusterCfg *kubeadmapiv1beta2.ClusterConfiguration) (*kubeadmapi.InitConfiguration, error) {
	if cfgPath != "" {
		// Loads configuration from config file, if provided
		// Nb. --config overrides command line flags
		return LoadInitConfigurationFromFile(cfgPath)
	}

	return DefaultedInitConfiguration(versionedInitCfg, versionedClusterCfg)
}

// BytesToInitConfiguration converts a byte slice to an internal, defaulted and validated InitConfiguration object.
// The map may contain many different YAML documents. These YAML documents are parsed one-by-one
// and well-known ComponentConfig GroupVersionKinds are stored inside of the internal InitConfiguration struct.
// The resulting InitConfiguration is then dynamically defaulted and validated prior to return.
func BytesToInitConfiguration(b []byte) (*kubeadmapi.InitConfiguration, error) {
	gvkmap, err := kubeadmutil.SplitYAMLDocuments(b)
	if err != nil {
		return nil, err
	}

	return documentMapToInitConfiguration(gvkmap, false)
}

// documentMapToInitConfiguration converts a map of GVKs and YAML documents to defaulted and validated configuration object.
func documentMapToInitConfiguration(gvkmap kubeadmapi.DocumentMap, allowDeprecated bool) (*kubeadmapi.InitConfiguration, error) {
	var initcfg *kubeadmapi.InitConfiguration
	var clustercfg *kubeadmapi.ClusterConfiguration

	for gvk, fileContent := range gvkmap {
		// first, check if this GVK is supported and possibly not deprecated
		if err := validateSupportedVersion(gvk.GroupVersion(), allowDeprecated); err != nil {
			return nil, err
		}

		// verify the validity of the YAML
		strict.VerifyUnmarshalStrict(fileContent, gvk)

		if kubeadmutil.GroupVersionKindsHasInitConfiguration(gvk) {
			// Set initcfg to an empty struct value the deserializer will populate
			initcfg = &kubeadmapi.InitConfiguration{}
			// Decode the bytes into the internal struct. Under the hood, the bytes will be unmarshalled into the
			// right external version, defaulted, and converted into the internal version.
			if err := runtime.DecodeInto(kubeadmscheme.Codecs.UniversalDecoder(), fileContent, initcfg); err != nil {
				return nil, err
			}
			continue
		}
		if kubeadmutil.GroupVersionKindsHasClusterConfiguration(gvk) {
			// Set clustercfg to an empty struct value the deserializer will populate
			clustercfg = &kubeadmapi.ClusterConfiguration{}
			// Decode the bytes into the internal struct. Under the hood, the bytes will be unmarshalled into the
			// right external version, defaulted, and converted into the internal version.
			if err := runtime.DecodeInto(kubeadmscheme.Codecs.UniversalDecoder(), fileContent, clustercfg); err != nil {
				return nil, err
			}
			continue
		}

		// If the group is neither a kubeadm core type or of a supported component config group, we dump a warning about it being ignored
		if !componentconfigs.Scheme.IsGroupRegistered(gvk.Group) {
			fmt.Printf("[config] WARNING: Ignored YAML document with GroupVersionKind %v\n", gvk)
		}
	}

	// Enforce that InitConfiguration and/or ClusterConfiguration has to exist among the YAML documents
	if initcfg == nil && clustercfg == nil {
		return nil, errors.New("no InitConfiguration or ClusterConfiguration kind was found in the YAML file")
	}

	// If InitConfiguration wasn't given, default it by creating an external struct instance, default it and convert into the internal type
	if initcfg == nil {
		extinitcfg := &kubeadmapiv1beta2.InitConfiguration{}
		kubeadmscheme.Scheme.Default(extinitcfg)
		// Set initcfg to an empty struct value the deserializer will populate
		initcfg = &kubeadmapi.InitConfiguration{}
		if err := kubeadmscheme.Scheme.Convert(extinitcfg, initcfg, nil); err != nil {
			return nil, err
		}
	}
	// If ClusterConfiguration was given, populate it in the InitConfiguration struct
	if clustercfg != nil {
		initcfg.ClusterConfiguration = *clustercfg
	}

	// Load any component configs
	if err := componentconfigs.FetchFromDocumentMap(&initcfg.ClusterConfiguration, gvkmap); err != nil {
		return nil, err
	}

	// Applies dynamic defaults to settings not provided with flags
	if err := SetInitDynamicDefaults(initcfg); err != nil {
		return nil, err
	}

	// Validates cfg (flags/configs + defaults + dynamic defaults)
	if err := validation.ValidateInitConfiguration(initcfg).ToAggregate(); err != nil {
		return nil, err
	}

	return initcfg, nil
}

// MarshalInitConfigurationToBytes marshals the internal InitConfiguration object to bytes. It writes the embedded
// ClusterConfiguration object with ComponentConfigs out as separate YAML documents
func MarshalInitConfigurationToBytes(cfg *kubeadmapi.InitConfiguration, gv schema.GroupVersion) ([]byte, error) {
	initbytes, err := kubeadmutil.MarshalToYamlForCodecs(cfg, gv, kubeadmscheme.Codecs)
	if err != nil {
		return []byte{}, err
	}
	allFiles := [][]byte{initbytes}

	// Exception: If the specified groupversion is targeting the internal type, don't print embedded ClusterConfiguration contents
	// This is mostly used for unit testing. In a real scenario the internal version of the API is never marshalled as-is.
	if gv.Version != runtime.APIVersionInternal {
		clusterbytes, err := kubeadmutil.MarshalToYamlForCodecs(&cfg.ClusterConfiguration, gv, kubeadmscheme.Codecs)
		if err != nil {
			return []byte{}, err
		}
		allFiles = append(allFiles, clusterbytes)
	}
	return bytes.Join(allFiles, []byte(kubeadmconstants.YAMLDocumentSeparator)), nil
}
<|endoftext|>


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

package workflow

import (
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/venicegeo/pz-gocommon/elasticsearch"
	"github.com/venicegeo/pz-gocommon/gocommon"
)

type TriggerDB struct {
	*ResourceDB
	mapping string
}

func NewTriggerDB(service *WorkflowService, esi elasticsearch.IIndex) (*TriggerDB, error) {

	rdb, err := NewResourceDB(service, esi, TriggerIndexSettings)
	if err != nil {
		return nil, err
	}
	ardb := TriggerDB{ResourceDB: rdb, mapping: TriggerDBMapping}
	return &ardb, nil
}

func (db *TriggerDB) PostTrigger(trigger *Trigger, id piazza.Ident) (piazza.Ident, error) {

	{ //CHECK SERVICE EXISTS
		jobData := trigger.Job.JobType.Data
		serviceId := jobData["serviceId"]
		strServiceId, ok := serviceId.(string)
		if !ok {
			return piazza.NoIdent, LoggedError("TriggerDB.PostData faile: serviceId field not of type string")
		}
		serviceControllerURL, err := db.service.sys.GetURL("pz-servicecontroller")
		if err != nil {
			return piazza.NoIdent, LoggedError("TriggerDB.PostData failed to find ServiceController: %s", err)
		}
		response, err := http.Get(serviceControllerURL)
		if err != nil {
			return piazza.NoIdent, LoggedError("TriggerDB.PostData failed to make request to ServiceController: %s", err)
		}
		if response.StatusCode != 200 {
			return piazza.NoIdent, LoggedError("TriggerDB.PostData: serviceId %s does not exist", strServiceId)
		}
	}

	ifaceObj := trigger.Condition.Query
	//log.Printf("Query: %v", ifaceObj)
	body, err := json.Marshal(ifaceObj)
	if err != nil {
		return piazza.NoIdent, err
	}

	json := string(body)
	//log.Printf("Current json: %s", json)
	// Remove trailing }
	json = json[:len(json)-1]
	json += ",\"type\":["
	// Add the types that the percolation query can match
	for _, id := range trigger.Condition.EventTypeIds {
		json += fmt.Sprintf("\"%s\",", id)
	}
	json = json[:len(json)-1]
	// Add back trailing } and ] to close array
	json += "]}"

	//log.Printf("Posting percolation query: %s", body)
	indexResult, err := db.service.eventDB.Esi.AddPercolationQuery(string(trigger.TriggerId), piazza.JsonString(body))
	if err != nil {
		return piazza.NoIdent, LoggedError("TriggerDB.PostData addpercquery failed: %s", err)
	}
	if indexResult == nil {
		return piazza.NoIdent, LoggedError("TriggerDB.PostData addpercquery failed: no indexResult")
	}
	if !indexResult.Created {
		return piazza.NoIdent, LoggedError("TriggerDB.PostData addpercquery failed: not created")
	}

	//log.Printf("percolation query added: ID: %s, Type: %s, Index: %s", indexResult.Id, indexResult.Type, indexResult.Index)
	//log.Printf("percolation id: %s", indexResult.Id)
	trigger.PercolationId = piazza.Ident(indexResult.Id)

	indexResult2, err := db.Esi.PostData(db.mapping, id.String(), trigger)
	if err != nil {
		db.service.eventDB.Esi.DeletePercolationQuery(string(trigger.TriggerId))
		return piazza.NoIdent, LoggedError("TriggerDB.PostData failed: %s", err)
	}
	if !indexResult2.Created {
		db.service.eventDB.Esi.DeletePercolationQuery(string(trigger.TriggerId))
		return piazza.NoIdent, LoggedError("TriggerDB.PostData failed: not created")
	}

	return id, nil
}

func (db *TriggerDB) GetAll(format *piazza.JsonPagination) ([]Trigger, int64, error) {
	triggers := []Trigger{}

	exists, err := db.Esi.TypeExists(db.mapping)
	if err != nil {
		return triggers, 0, err
	}
	if !exists {
		return triggers, 0, nil
	}

	searchResult, err := db.Esi.FilterByMatchAll(db.mapping, format)
	if err != nil {
		return nil, 0, LoggedError("TriggerDB.GetAll failed: %s", err)
	}
	if searchResult == nil {
		return nil, 0, LoggedError("TriggerDB.GetAll failed: no searchResult")
	}

	if searchResult != nil && searchResult.GetHits() != nil {

		for _, hit := range *searchResult.GetHits() {
			var trigger Trigger
			err := json.Unmarshal(*hit.Source, &trigger)
			if err != nil {
				return nil, 0, err
			}
			triggers = append(triggers, trigger)
		}
	}
	return triggers, searchResult.TotalHits(), nil
}

func (db *TriggerDB) GetOne(id piazza.Ident) (*Trigger, bool, error) {

	getResult, err := db.Esi.GetByID(db.mapping, id.String())
	if err != nil {
		return nil, getResult.Found, LoggedError("TriggerDB.GetOne failed: %s", err)
	}
	if getResult == nil {
		return nil, true, LoggedError("TriggerDB.GetOne failed: no getResult")
	}

	src := getResult.Source
	var obj Trigger
	err = json.Unmarshal(*src, &obj)
	if err != nil {
		return nil, getResult.Found, err
	}

	return &obj, getResult.Found, nil
}

func (db *TriggerDB) DeleteTrigger(id piazza.Ident) (bool, error) {

	trigger, found, err := db.GetOne(id)
	if err != nil {
		return found, err
	}
	if trigger == nil {
		return false, nil
	}

	deleteResult, err := db.Esi.DeleteByID(db.mapping, string(id))
	if err != nil {
		return deleteResult.Found, LoggedError("TriggerDB.DeleteById failed: %s", err)
	}
	if deleteResult == nil {
		return false, LoggedError("TriggerDB.DeleteById failed: no deleteResult")
	}
	if !deleteResult.Found {
		return false, nil
	}

	deleteResult2, err := db.service.eventDB.Esi.DeletePercolationQuery(string(trigger.PercolationId))
	if err != nil {
		return deleteResult2.Found, LoggedError("TriggerDB.DeleteById percquery failed: %s", err)
	}
	if deleteResult2 == nil {
		return false, LoggedError("TriggerDB.DeleteById percquery failed: no deleteResult")
	}

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

package workflow

import (
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/venicegeo/pz-gocommon/elasticsearch"
	"github.com/venicegeo/pz-gocommon/gocommon"
)

type TriggerDB struct {
	*ResourceDB
	mapping string
}

func NewTriggerDB(service *WorkflowService, esi elasticsearch.IIndex) (*TriggerDB, error) {

	rdb, err := NewResourceDB(service, esi, TriggerIndexSettings)
	if err != nil {
		return nil, err
	}
	ardb := TriggerDB{ResourceDB: rdb, mapping: TriggerDBMapping}
	return &ardb, nil
}

func (db *TriggerDB) PostTrigger(trigger *Trigger, id piazza.Ident) (piazza.Ident, error) {

	{ //CHECK SERVICE EXISTS
		jobData := trigger.Job.JobType.Data
		serviceId := jobData["serviceId"]
		strServiceId, ok := serviceId.(string)
		if !ok {
			return piazza.NoIdent, LoggedError("TriggerDB.PostData faile: serviceId field not of type string")
		}
		serviceControllerURL, err := db.service.sys.GetURL("pz-servicecontroller")
		if err == nil {
			// TODO:
			// if err is nil, we have a servicecontroller to talk to
			// if err is not nil, we'll assume we are mocking (which means
			// we have no servicecontroller client to mock)
			response, err := http.Get(serviceControllerURL)
			if err != nil {
				return piazza.NoIdent, LoggedError("TriggerDB.PostData failed to make request to ServiceController: %s", err)
			}
			if response.StatusCode != 200 {
				return piazza.NoIdent, LoggedError("TriggerDB.PostData: serviceId %s does not exist", strServiceId)
			}
		}
	}

	ifaceObj := trigger.Condition.Query
	//log.Printf("Query: %v", ifaceObj)
	body, err := json.Marshal(ifaceObj)
	if err != nil {
		return piazza.NoIdent, err
	}

	json := string(body)
	//log.Printf("Current json: %s", json)
	// Remove trailing }
	json = json[:len(json)-1]
	json += ",\"type\":["
	// Add the types that the percolation query can match
	for _, id := range trigger.Condition.EventTypeIds {
		json += fmt.Sprintf("\"%s\",", id)
	}
	json = json[:len(json)-1]
	// Add back trailing } and ] to close array
	json += "]}"

	//log.Printf("Posting percolation query: %s", body)
	indexResult, err := db.service.eventDB.Esi.AddPercolationQuery(string(trigger.TriggerId), piazza.JsonString(body))
	if err != nil {
		return piazza.NoIdent, LoggedError("TriggerDB.PostData addpercquery failed: %s", err)
	}
	if indexResult == nil {
		return piazza.NoIdent, LoggedError("TriggerDB.PostData addpercquery failed: no indexResult")
	}
	if !indexResult.Created {
		return piazza.NoIdent, LoggedError("TriggerDB.PostData addpercquery failed: not created")
	}

	//log.Printf("percolation query added: ID: %s, Type: %s, Index: %s", indexResult.Id, indexResult.Type, indexResult.Index)
	//log.Printf("percolation id: %s", indexResult.Id)
	trigger.PercolationId = piazza.Ident(indexResult.Id)

	indexResult2, err := db.Esi.PostData(db.mapping, id.String(), trigger)
	if err != nil {
		db.service.eventDB.Esi.DeletePercolationQuery(string(trigger.TriggerId))
		return piazza.NoIdent, LoggedError("TriggerDB.PostData failed: %s", err)
	}
	if !indexResult2.Created {
		db.service.eventDB.Esi.DeletePercolationQuery(string(trigger.TriggerId))
		return piazza.NoIdent, LoggedError("TriggerDB.PostData failed: not created")
	}

	return id, nil
}

func (db *TriggerDB) GetAll(format *piazza.JsonPagination) ([]Trigger, int64, error) {
	triggers := []Trigger{}

	exists, err := db.Esi.TypeExists(db.mapping)
	if err != nil {
		return triggers, 0, err
	}
	if !exists {
		return triggers, 0, nil
	}

	searchResult, err := db.Esi.FilterByMatchAll(db.mapping, format)
	if err != nil {
		return nil, 0, LoggedError("TriggerDB.GetAll failed: %s", err)
	}
	if searchResult == nil {
		return nil, 0, LoggedError("TriggerDB.GetAll failed: no searchResult")
	}

	if searchResult != nil && searchResult.GetHits() != nil {

		for _, hit := range *searchResult.GetHits() {
			var trigger Trigger
			err := json.Unmarshal(*hit.Source, &trigger)
			if err != nil {
				return nil, 0, err
			}
			triggers = append(triggers, trigger)
		}
	}
	return triggers, searchResult.TotalHits(), nil
}

func (db *TriggerDB) GetOne(id piazza.Ident) (*Trigger, bool, error) {

	getResult, err := db.Esi.GetByID(db.mapping, id.String())
	if err != nil {
		return nil, getResult.Found, LoggedError("TriggerDB.GetOne failed: %s", err)
	}
	if getResult == nil {
		return nil, true, LoggedError("TriggerDB.GetOne failed: no getResult")
	}

	src := getResult.Source
	var obj Trigger
	err = json.Unmarshal(*src, &obj)
	if err != nil {
		return nil, getResult.Found, err
	}

	return &obj, getResult.Found, nil
}

func (db *TriggerDB) DeleteTrigger(id piazza.Ident) (bool, error) {

	trigger, found, err := db.GetOne(id)
	if err != nil {
		return found, err
	}
	if trigger == nil {
		return false, nil
	}

	deleteResult, err := db.Esi.DeleteByID(db.mapping, string(id))
	if err != nil {
		return deleteResult.Found, LoggedError("TriggerDB.DeleteById failed: %s", err)
	}
	if deleteResult == nil {
		return false, LoggedError("TriggerDB.DeleteById failed: no deleteResult")
	}
	if !deleteResult.Found {
		return false, nil
	}

	deleteResult2, err := db.service.eventDB.Esi.DeletePercolationQuery(string(trigger.PercolationId))
	if err != nil {
		return deleteResult2.Found, LoggedError("TriggerDB.DeleteById percquery failed: %s", err)
	}
	if deleteResult2 == nil {
		return false, LoggedError("TriggerDB.DeleteById percquery failed: no deleteResult")
	}

	return deleteResult2.Found, nil
}
<|endoftext|>


<commit_before>package vision

import (
	"os"
	"testing"

	"github.com/daviddengcn/go-assert"
)

func TestLoad(t *testing.T) {
	datasets := [...]struct {
		width, height int
		fn            string
	}{
		{177, 177, "gray-177x177.jpg"},
		{500, 374, "ycbcr-500x374.jpg"},
		{500, 374, "pal-500x374.gif"},
		{16, 16, "nrgba-16x16.png"},
	}

	os.MkdirAll("testout", 0755)

	for _, d := range datasets {
		img, err := ImageFromFile("testdata/" + d.fn)
		if err != nil {
			t.Error(err)
			continue
		}
		t.Logf("Image loaded: %v", d.fn)

		var m GrayImage
		m.SetImage(img)

		if m.Width != d.width || m.Height != d.height {
			t.Errorf("(GrayImage) Wrong size: %d, %d, expected %d, %d",
				m.Width, m.Height, d.width, d.height)
		}
		outImg := m.AsImage()
		if outImg.Bounds().Dx() != d.width || outImg.Bounds().Dy() != d.height {
			t.Errorf("(AsImage) Wrong size: %d, %d, expected %d, %d",
				outImg.Bounds().Dx, outImg.Bounds().Dy, d.width, d.height)
		}

		if err := SaveImageAsPng(outImg, "testout/gray-"+d.fn+".png"); err != nil {
			t.Error(err)
			continue
		}

		var rgbImg RGBImage
		rgbImg.SetImage(img)
		if rgbImg.Width != d.width || rgbImg.Height != d.height {
			t.Errorf("(RGBImage) Wrong size: %d, %d, expected %d, %d",
				rgbImg.Width, rgbImg.Height, d.width, d.height)
		}

		outImg = rgbImg.AsImage()
		if outImg.Bounds().Dx() != d.width || outImg.Bounds().Dy() != d.height {
			t.Errorf("(AsImage) Wrong size: %d, %d, expected %d, %d",
				outImg.Bounds().Dx, outImg.Bounds().Dy, d.width, d.height)
		}

		if err := SaveImageAsPng(outImg, "testout/rgb-"+d.fn+".png"); err != nil {
			t.Error(err)
			continue
		}
	}
}

func TestResize(t *testing.T) {
	var gray GrayImage
	gray.Resize(Size{123, 456})
	assert.Equals(t, "Size", gray.Size, Size{123, 456})
	assert.Equals(t, "len(Pixels)", len(gray.Pixels), 123*456)

	var ig IntGrayImage
	ig.Resize(Size{123, 555})
	assert.Equals(t, "Size", ig.Size, Size{123, 555})
	assert.Equals(t, "len(Pixels)", len(ig.Pixels), 123*555)

	var rgb RGBImage
	rgb.Resize(Size{123, 456})
	assert.Equals(t, "Size", rgb.Size, Size{123, 456})
	assert.Equals(t, "len(Pixels)", len(rgb.Pixels), 123*456)
}

func TestFill(t *testing.T) {
	var gray GrayImage
	gray.Resize(Size{456, 123})
	gray.Fill(123)
	assert.Equals(t, "[0,0]", gray.Pixels[0], byte(123))

	var ig IntGrayImage
	ig.Resize(Size{555, 123})
	ig.Fill(12345)
	assert.Equals(t, "[0,0]", ig.Pixels[0], int(12345))

	var rgb RGBImage
	rgb.Resize(Size{456, 123})
	rgb.Fill(RGB{1, 2, 3})
	assert.Equals(t, "[0,0]", rgb.Pixels[0], RGB{1, 2, 3})
}<commit_msg>Fix a format bug found by go vet<commit_after>package vision

import (
	"os"
	"testing"

	"github.com/daviddengcn/go-assert"
)

func TestLoad(t *testing.T) {
	datasets := [...]struct {
		width, height int
		fn            string
	}{
		{177, 177, "gray-177x177.jpg"},
		{500, 374, "ycbcr-500x374.jpg"},
		{500, 374, "pal-500x374.gif"},
		{16, 16, "nrgba-16x16.png"},
	}

	os.MkdirAll("testout", 0755)

	for _, d := range datasets {
		img, err := ImageFromFile("testdata/" + d.fn)
		if err != nil {
			t.Error(err)
			continue
		}
		t.Logf("Image loaded: %v", d.fn)

		var m GrayImage
		m.SetImage(img)

		if m.Width != d.width || m.Height != d.height {
			t.Errorf("(GrayImage) Wrong size: %d, %d, expected %d, %d",
				m.Width, m.Height, d.width, d.height)
		}
		outImg := m.AsImage()
		if outImg.Bounds().Dx() != d.width || outImg.Bounds().Dy() != d.height {
			t.Errorf("(AsImage) Wrong size: %d, %d, expected %d, %d",
				outImg.Bounds().Dx(), outImg.Bounds().Dy(), d.width, d.height)
		}

		if err := SaveImageAsPng(outImg, "testout/gray-"+d.fn+".png"); err != nil {
			t.Error(err)
			continue
		}

		var rgbImg RGBImage
		rgbImg.SetImage(img)
		if rgbImg.Width != d.width || rgbImg.Height != d.height {
			t.Errorf("(RGBImage) Wrong size: %d, %d, expected %d, %d",
				rgbImg.Width, rgbImg.Height, d.width, d.height)
		}

		outImg = rgbImg.AsImage()
		if outImg.Bounds().Dx() != d.width || outImg.Bounds().Dy() != d.height {
			t.Errorf("(AsImage) Wrong size: %d, %d, expected %d, %d",
				outImg.Bounds().Dx(), outImg.Bounds().Dy(), d.width, d.height)
		}

		if err := SaveImageAsPng(outImg, "testout/rgb-"+d.fn+".png"); err != nil {
			t.Error(err)
			continue
		}
	}
}

func TestResize(t *testing.T) {
	var gray GrayImage
	gray.Resize(Size{123, 456})
	assert.Equals(t, "Size", gray.Size, Size{123, 456})
	assert.Equals(t, "len(Pixels)", len(gray.Pixels), 123*456)

	var ig IntGrayImage
	ig.Resize(Size{123, 555})
	assert.Equals(t, "Size", ig.Size, Size{123, 555})
	assert.Equals(t, "len(Pixels)", len(ig.Pixels), 123*555)

	var rgb RGBImage
	rgb.Resize(Size{123, 456})
	assert.Equals(t, "Size", rgb.Size, Size{123, 456})
	assert.Equals(t, "len(Pixels)", len(rgb.Pixels), 123*456)
}

func TestFill(t *testing.T) {
	var gray GrayImage
	gray.Resize(Size{456, 123})
	gray.Fill(123)
	assert.Equals(t, "[0,0]", gray.Pixels[0], byte(123))

	var ig IntGrayImage
	ig.Resize(Size{555, 123})
	ig.Fill(12345)
	assert.Equals(t, "[0,0]", ig.Pixels[0], int(12345))

	var rgb RGBImage
	rgb.Resize(Size{456, 123})
	rgb.Fill(RGB{1, 2, 3})
	assert.Equals(t, "[0,0]", rgb.Pixels[0], RGB{1, 2, 3})
}
<|endoftext|>