<commit_before>package main

import (
	"bytes"
	"crypto/tls"
	"crypto/x509"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	//log "github.com/Sirupsen/logrus"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/crewjam/awsregion"
	"github.com/crewjam/ec2cluster"
)

type etcdState struct {
	Name       string         `json:"name"`
	ID         string         `json:"id"`
	State      string         `json:"state"`
	StartTime  time.Time      `json:"startTime"`
	LeaderInfo etcdLeaderInfo `json:"leaderInfo"`
}

type etcdLeaderInfo struct {
	Leader               string    `json:"leader"`
	Uptime               string    `json:"uptime"`
	StartTime            time.Time `json:"startTime"`
	RecvAppendRequestCnt int       `json:"recvAppendRequestCnt"`
	RecvPkgRate          int       `json:"recvPkgRate"`
	RecvBandwidthRate    int       `json:"recvBandwidthRate"`
	SendAppendRequestCnt int       `json:"sendAppendRequestCnt"`
}

type etcdMembers struct {
	Members []etcdMember `json:"members,omitempty"`
}

type etcdMember struct {
	ID         string   `json:"id,omitempty"`
	Name       string   `json:"name,omitempty"`
	PeerURLs   []string `json:"peerURLs,omitempty"`
	ClientURLs []string `json:"clientURLs,omitempty"`
}

var localInstance *ec2.Instance
var peerProtocol string
var clientProtocol string
var etcdCertFile *string
var etcdKeyFile *string
var etcdTrustedCaFile *string
var clientTlsEnabled bool

func getTlsConfig() (*tls.Config, error) {
	// Load client cert
	cert, err := tls.LoadX509KeyPair(*etcdCertFile, *etcdKeyFile)
	if err != nil {
		return nil, fmt.Errorf("ERROR: %s", err)
	}

	// Load CA cert
	caCert, err := ioutil.ReadFile(*etcdTrustedCaFile)
	if err != nil {
		return nil, fmt.Errorf("ERROR: %s", err)
	}
	caCertPool := x509.NewCertPool()
	caCertPool.AppendCertsFromPEM(caCert)

	// Setup HTTPS client
	tlsConfig := &tls.Config{
		Certificates: []tls.Certificate{cert},
		RootCAs:      caCertPool,
	}
	tlsConfig.BuildNameToCertificate()
	return tlsConfig, nil
}

func getApiResponse(privateIpAddress string, instanceId string, path string, method string) (*http.Response, error) {
	return getApiResponseWithBody(privateIpAddress, instanceId, path, method, "", nil)
}

func getApiResponseWithBody(privateIpAddress string, instanceId string, path string, method string, bodyType string, body io.Reader) (*http.Response, error) {
	var resp *http.Response
	var err error
	var req *http.Request

	url := fmt.Sprintf("%s://%s:2379/v2/%s", clientProtocol, privateIpAddress, path)

	req, err = http.NewRequest(method, url, body)
	if err != nil {
		return nil, fmt.Errorf("%s: %s %s://%s:2379/v2/%s: %s", instanceId, method, clientProtocol, privateIpAddress, path, err)
	}

	if bodyType != "" {
		req.Header.Set("Content-Type", bodyType)
	}

	client := http.DefaultClient
	if clientTlsEnabled {
		tlsConfig, err := getTlsConfig()
		if err != nil {
			log.Fatalf("Error in getTlsConfig: %s", err)
		}
		transport := &http.Transport{TLSClientConfig: tlsConfig}
		client = &http.Client{Transport: transport}
	}

	resp, err = client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("%s: %s %s://%s:2379/v2/%s: %s", instanceId, method, clientProtocol, privateIpAddress, path, err)
	}
	return resp, nil
}

func buildCluster(s *ec2cluster.Cluster) (initialClusterState string, initialCluster []string, err error) {

	localInstance, err := s.Instance()
	if err != nil {
		return "", nil, err
	}

	clusterInstances, err := s.Members()
	if err != nil {
		return "", nil, fmt.Errorf("list members: %s", err)
	}

	initialClusterState = "new"
	initialCluster = []string{}
	for _, instance := range clusterInstances {
		if instance.PrivateDnsName == nil {
			continue
		}

		// add this instance to the initialCluster expression
		initialCluster = append(initialCluster, fmt.Sprintf("%s=%s://%s:2380",
			*instance.InstanceId, peerProtocol, *instance.PrivateDnsName))

		// skip the local node, since we know it is not running yet
		if *instance.InstanceId == *localInstance.InstanceId {
			continue
		}

		// fetch the state of the node.
		path := "stats/self"
		resp, err := getApiResponse(*instance.PrivateDnsName, *instance.InstanceId, path, http.MethodGet)
		if err != nil {
			log.Printf("%s: %s://%s:2379/v2/%s: %s", *instance.InstanceId, clientProtocol,
				*instance.PrivateDnsName, path, err)
			continue
		}
		nodeState := etcdState{}
		if err := json.NewDecoder(resp.Body).Decode(&nodeState); err != nil {
			log.Printf("%s: %s://%s:2379/v2/%s: %s", *instance.InstanceId, clientProtocol,
				*instance.PrivateDnsName, path, err)
			continue
		}

		if nodeState.LeaderInfo.Leader == "" {
			log.Printf("%s: %s://%s:2379/v2/%s: alive, no leader", *instance.InstanceId, clientProtocol,
				*instance.PrivateDnsName, path)
			continue
		}

		log.Printf("%s: %s://%s:2379/v2/%s: has leader %s", *instance.InstanceId, clientProtocol,
			*instance.PrivateDnsName, path, nodeState.LeaderInfo.Leader)
		if initialClusterState != "existing" {
			initialClusterState = "existing"

			// inform the node we found about the new node we're about to add so that
			// when etcd starts we can avoid etcd thinking the cluster is out of sync.
			log.Printf("joining cluster via %s", *instance.InstanceId)
			m := etcdMember{
				Name:     *localInstance.InstanceId,
				PeerURLs: []string{fmt.Sprintf("%s://%s:2380", peerProtocol, *localInstance.PrivateDnsName)},
			}
			body, _ := json.Marshal(m)
			getApiResponseWithBody(*instance.PrivateDnsName, *instance.InstanceId, "members", http.MethodPost, "application/json", bytes.NewReader(body))
		}
	}
	return initialClusterState, initialCluster, nil
}

func main() {
	instanceID := flag.String("instance", "",
		"The instance ID of the cluster member. If not supplied, then the instance ID is determined from EC2 metadata")
	clusterTagName := flag.String("tag", "aws:autoscaling:groupName",
		"The instance tag that is common to all members of the cluster")

	etcdKeyFile = flag.String("etcd-key-file", "", "Path to the TLS key")
	etcdCertFile = flag.String("etcd-cert-file", os.Getenv("ETCD_CERT_FILE"),
		"Path to the client server TLS cert file. "+
			"Environment variable: ETCD_CERT_FILE")
	etcdTrustedCaFile = flag.String("etcd-ca-file", os.Getenv("ETCD_TRUSTED_CA_FILE"),
		"Path to the client server TLS trusted CA key file. "+
			"Environment variable: ETCD_TRUSTED_CA_FILE")

	flag.Parse()

	// Note: We're kinda assuming that if SSL is on at all, it's on for everything.
	clientTlsEnabled = false
	clientProtocol = "http"
	peerProtocol = "http"
	if *etcdCertFile != "" {
		clientTlsEnabled = true
		clientProtocol = "https"
		peerProtocol = "https"
	}

	var err error
	if *instanceID == "" {
		*instanceID, err = ec2cluster.DiscoverInstanceID()
		if err != nil {
			log.Fatalf("ERROR: %s", err)
		}
	}

	awsSession := session.New()
	if region := os.Getenv("AWS_REGION"); region != "" {
		awsSession.Config.WithRegion(region)
	}
	awsregion.GuessRegion(awsSession.Config)

	s := &ec2cluster.Cluster{
		AwsSession: awsSession,
		InstanceID: *instanceID,
		TagName:    *clusterTagName,
	}

	localInstance, err := s.Instance()
	if err != nil {
		log.Fatalf("ERROR: %s", err)
	}

	initialClusterState, initialCluster, err := buildCluster(s)

	envs := []string{
		fmt.Sprintf("ETCD_NAME=%s", *localInstance.InstanceId),
		fmt.Sprintf("ETCD_ADVERTISE_CLIENT_URLS=%s://%s:2379", clientProtocol, *localInstance.PrivateDnsName),
		fmt.Sprintf("ETCD_LISTEN_CLIENT_URLS=%s://0.0.0.0:2379", clientProtocol),
		fmt.Sprintf("ETCD_LISTEN_PEER_URLS=%s://0.0.0.0:2380", peerProtocol),
		fmt.Sprintf("ETCD_INITIAL_CLUSTER_STATE=%s", initialClusterState),
		fmt.Sprintf("ETCD_INITIAL_CLUSTER=%s", strings.Join(initialCluster, ",")),
		fmt.Sprintf("ETCD_INITIAL_ADVERTISE_PEER_URLS=%s://%s:2380", peerProtocol, *localInstance.PrivateDnsName),
	}
	asg, _ := s.AutoscalingGroup()
	if asg != nil {
		envs = append(envs, fmt.Sprintf("ETCD_INITIAL_CLUSTER_TOKEN=%s", *asg.AutoScalingGroupARN))
	}

	for _, line := range envs {
		fmt.Println(line)
	}
}
<commit_msg>Don't add terminated hosts to the INITIAL_CLUSTER.<commit_after>package main

import (
	"bytes"
	"crypto/tls"
	"crypto/x509"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	//log "github.com/Sirupsen/logrus"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/crewjam/awsregion"
	"github.com/crewjam/ec2cluster"
)

type etcdState struct {
	Name       string         `json:"name"`
	ID         string         `json:"id"`
	State      string         `json:"state"`
	StartTime  time.Time      `json:"startTime"`
	LeaderInfo etcdLeaderInfo `json:"leaderInfo"`
}

type etcdLeaderInfo struct {
	Leader               string    `json:"leader"`
	Uptime               string    `json:"uptime"`
	StartTime            time.Time `json:"startTime"`
	RecvAppendRequestCnt int       `json:"recvAppendRequestCnt"`
	RecvPkgRate          int       `json:"recvPkgRate"`
	RecvBandwidthRate    int       `json:"recvBandwidthRate"`
	SendAppendRequestCnt int       `json:"sendAppendRequestCnt"`
}

type etcdMembers struct {
	Members []etcdMember `json:"members,omitempty"`
}

type etcdMember struct {
	ID         string   `json:"id,omitempty"`
	Name       string   `json:"name,omitempty"`
	PeerURLs   []string `json:"peerURLs,omitempty"`
	ClientURLs []string `json:"clientURLs,omitempty"`
}

var localInstance *ec2.Instance
var peerProtocol string
var clientProtocol string
var etcdCertFile *string
var etcdKeyFile *string
var etcdTrustedCaFile *string
var clientTlsEnabled bool

func getTlsConfig() (*tls.Config, error) {
	// Load client cert
	cert, err := tls.LoadX509KeyPair(*etcdCertFile, *etcdKeyFile)
	if err != nil {
		return nil, fmt.Errorf("ERROR: %s", err)
	}

	// Load CA cert
	caCert, err := ioutil.ReadFile(*etcdTrustedCaFile)
	if err != nil {
		return nil, fmt.Errorf("ERROR: %s", err)
	}
	caCertPool := x509.NewCertPool()
	caCertPool.AppendCertsFromPEM(caCert)

	// Setup HTTPS client
	tlsConfig := &tls.Config{
		Certificates: []tls.Certificate{cert},
		RootCAs:      caCertPool,
	}
	tlsConfig.BuildNameToCertificate()
	return tlsConfig, nil
}

func getApiResponse(privateIpAddress string, instanceId string, path string, method string) (*http.Response, error) {
	return getApiResponseWithBody(privateIpAddress, instanceId, path, method, "", nil)
}

func getApiResponseWithBody(privateIpAddress string, instanceId string, path string, method string, bodyType string, body io.Reader) (*http.Response, error) {
	var resp *http.Response
	var err error
	var req *http.Request

	url := fmt.Sprintf("%s://%s:2379/v2/%s", clientProtocol, privateIpAddress, path)

	req, err = http.NewRequest(method, url, body)
	if err != nil {
		return nil, fmt.Errorf("%s: %s %s://%s:2379/v2/%s: %s", instanceId, method, clientProtocol, privateIpAddress, path, err)
	}

	if bodyType != "" {
		req.Header.Set("Content-Type", bodyType)
	}

	client := http.DefaultClient
	if clientTlsEnabled {
		tlsConfig, err := getTlsConfig()
		if err != nil {
			log.Fatalf("Error in getTlsConfig: %s", err)
		}
		transport := &http.Transport{TLSClientConfig: tlsConfig}
		client = &http.Client{Transport: transport}
	}

	resp, err = client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("%s: %s %s://%s:2379/v2/%s: %s", instanceId, method, clientProtocol, privateIpAddress, path, err)
	}
	return resp, nil
}

func buildCluster(s *ec2cluster.Cluster) (initialClusterState string, initialCluster []string, err error) {

	localInstance, err := s.Instance()
	if err != nil {
		return "", nil, err
	}

	clusterInstances, err := s.Members()
	if err != nil {
		return "", nil, fmt.Errorf("list members: %s", err)
	}

	initialClusterState = "new"
	initialCluster = []string{}
	for _, instance := range clusterInstances {
		if instance.PrivateDnsName == nil {
			continue
		}
		state := *instance.State.Name

		if state == ec2.InstanceStateNameTerminated {
			continue
		}

		// add this instance to the initialCluster expression
		initialCluster = append(initialCluster, fmt.Sprintf("%s=%s://%s:2380",
			*instance.InstanceId, peerProtocol, *instance.PrivateDnsName))

		// skip the local node, since we know it is not running yet
		if *instance.InstanceId == *localInstance.InstanceId {
			continue
		}

		// fetch the state of the node.
		path := "stats/self"
		resp, err := getApiResponse(*instance.PrivateDnsName, *instance.InstanceId, path, http.MethodGet)
		if err != nil {
			log.Printf("%s: %s://%s:2379/v2/%s: %s", *instance.InstanceId, clientProtocol,
				*instance.PrivateDnsName, path, err)
			continue
		}
		nodeState := etcdState{}
		if err := json.NewDecoder(resp.Body).Decode(&nodeState); err != nil {
			log.Printf("%s: %s://%s:2379/v2/%s: %s", *instance.InstanceId, clientProtocol,
				*instance.PrivateDnsName, path, err)
			continue
		}

		if nodeState.LeaderInfo.Leader == "" {
			log.Printf("%s: %s://%s:2379/v2/%s: alive, no leader", *instance.InstanceId, clientProtocol,
				*instance.PrivateDnsName, path)
			continue
		}

		log.Printf("%s: %s://%s:2379/v2/%s: has leader %s", *instance.InstanceId, clientProtocol,
			*instance.PrivateDnsName, path, nodeState.LeaderInfo.Leader)
		if initialClusterState != "existing" {
			initialClusterState = "existing"

			// inform the node we found about the new node we're about to add so that
			// when etcd starts we can avoid etcd thinking the cluster is out of sync.
			log.Printf("joining cluster via %s", *instance.InstanceId)
			m := etcdMember{
				Name:     *localInstance.InstanceId,
				PeerURLs: []string{fmt.Sprintf("%s://%s:2380", peerProtocol, *localInstance.PrivateDnsName)},
			}
			body, _ := json.Marshal(m)
			getApiResponseWithBody(*instance.PrivateDnsName, *instance.InstanceId, "members", http.MethodPost, "application/json", bytes.NewReader(body))
		}
	}
	return initialClusterState, initialCluster, nil
}

func main() {
	instanceID := flag.String("instance", "",
		"The instance ID of the cluster member. If not supplied, then the instance ID is determined from EC2 metadata")
	clusterTagName := flag.String("tag", "aws:autoscaling:groupName",
		"The instance tag that is common to all members of the cluster")

	etcdKeyFile = flag.String("etcd-key-file", "", "Path to the TLS key")
	etcdCertFile = flag.String("etcd-cert-file", os.Getenv("ETCD_CERT_FILE"),
		"Path to the client server TLS cert file. "+
			"Environment variable: ETCD_CERT_FILE")
	etcdTrustedCaFile = flag.String("etcd-ca-file", os.Getenv("ETCD_TRUSTED_CA_FILE"),
		"Path to the client server TLS trusted CA key file. "+
			"Environment variable: ETCD_TRUSTED_CA_FILE")

	flag.Parse()

	// Note: We're kinda assuming that if SSL is on at all, it's on for everything.
	clientTlsEnabled = false
	clientProtocol = "http"
	peerProtocol = "http"
	if *etcdCertFile != "" {
		clientTlsEnabled = true
		clientProtocol = "https"
		peerProtocol = "https"
	}

	var err error
	if *instanceID == "" {
		*instanceID, err = ec2cluster.DiscoverInstanceID()
		if err != nil {
			log.Fatalf("ERROR: %s", err)
		}
	}

	awsSession := session.New()
	if region := os.Getenv("AWS_REGION"); region != "" {
		awsSession.Config.WithRegion(region)
	}
	awsregion.GuessRegion(awsSession.Config)

	s := &ec2cluster.Cluster{
		AwsSession: awsSession,
		InstanceID: *instanceID,
		TagName:    *clusterTagName,
	}

	localInstance, err := s.Instance()
	if err != nil {
		log.Fatalf("ERROR: %s", err)
	}

	initialClusterState, initialCluster, err := buildCluster(s)

	envs := []string{
		fmt.Sprintf("ETCD_NAME=%s", *localInstance.InstanceId),
		fmt.Sprintf("ETCD_ADVERTISE_CLIENT_URLS=%s://%s:2379", clientProtocol, *localInstance.PrivateDnsName),
		fmt.Sprintf("ETCD_LISTEN_CLIENT_URLS=%s://0.0.0.0:2379", clientProtocol),
		fmt.Sprintf("ETCD_LISTEN_PEER_URLS=%s://0.0.0.0:2380", peerProtocol),
		fmt.Sprintf("ETCD_INITIAL_CLUSTER_STATE=%s", initialClusterState),
		fmt.Sprintf("ETCD_INITIAL_CLUSTER=%s", strings.Join(initialCluster, ",")),
		fmt.Sprintf("ETCD_INITIAL_ADVERTISE_PEER_URLS=%s://%s:2380", peerProtocol, *localInstance.PrivateDnsName),
	}
	asg, _ := s.AutoscalingGroup()
	if asg != nil {
		envs = append(envs, fmt.Sprintf("ETCD_INITIAL_CLUSTER_TOKEN=%s", *asg.AutoScalingGroupARN))
	}

	for _, line := range envs {
		fmt.Println(line)
	}
}
<|endoftext|>


<commit_before>// Package response defines the how the default microservice response must look and behave like.
package response

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

	"github.com/LUSHDigital/microservice-core-golang/pagination"
	"database/sql"
	"github.com/VividCortex/mysqlerr"
	"github.com/go-sql-driver/mysql"
)

// Standard response statuses.
const (
	StatusOk   = "ok"
	StatusFail = "fail"
)

// ResponseInterface - Interface for microservice responses.
type ResponseInterface interface {
	// ExtractData returns a particular item of data from the response.
	ExtractData(srcKey string, dst interface{}) error

	// GetCode returns the response code.
	GetCode() int
}

// Response - A standardised response format for a microservice.
type Response struct {
	Status  string `json:"status"`         // Can be 'ok' or 'fail'
	Code    int    `json:"code"`           // Any valid HTTP response code
	Message string `json:"message"`        // Any relevant message (optional)
	Data    *Data  `json:"data,omitempty"` // Data to pass along to the response (optional)
}

// New returns a new Response for a microservice endpoint
// This ensures that all API endpoints return data in a standardised format:
//
//    {
//       "status": "ok or fail",
//       "code": any HTTP response code,
//       "message": "any relevant message (optional)",
//       "data": {[
//          ...
//       ]}
//    }
func New(code int, message string, data *Data) *Response {
	var status string
	switch {
	case code >= http.StatusOK && code < http.StatusBadRequest:
		status = StatusOk
	default:
		status = StatusFail
	}
	return &Response{
		Code:    code,
		Status:  status,
		Message: message,
		Data:    data,
	}
}

// SQLError returns a prepared 422 Unprocessable Entity response if the error passed is of type sql.ErrNoRows,
// otherwise, returns a 500 Internal Server Error prepared response.
func SQLError(err error) *Response {
	if err == sql.ErrNoRows {
		return New(http.StatusUnprocessableEntity, "no data found", nil)
	}
	if driverErr, ok := err.(*mysql.MySQLError); ok {
		if driverErr.Number == mysqlerr.ER_DUP_ENTRY {
			return New(http.StatusUnprocessableEntity, "duplicate entry.", nil)
		}
	}
	return New(http.StatusInternalServerError, fmt.Sprintf("db error: %v", err), nil)
}

// JSONError returns a prepared 422 Unprocessable Entity response if the error passed is of type *json.SyntaxError,
// otherwise, returns a 500 Internal Server Error prepared response.
func JSONError(err error) *Response {
	if syn, ok := err.(*json.SyntaxError); ok {
		return New(http.StatusUnprocessableEntity, fmt.Sprintf("invalid json: %v", syn), nil)
	}
	return New(http.StatusInternalServerError, fmt.Sprintf("json error: %v", err), nil)
}

// ParamError returns a prepared 422 Unprocessable Entity response, including the name of
// the failing parameter in the message field of the response object.
func ParamError(name string) *Response {
	return New(http.StatusUnprocessableEntity, fmt.Sprintf("invalid or missing parameter: %v", name), nil)
}

// ValidationError returns a prepared 422 Unprocessable Entity response, including the name of
// the failing validation/validator in the message field of the response object.
func ValidationError(err error, name string) *Response {
	return New(http.StatusUnprocessableEntity, fmt.Sprintf("validation error on %s: %v", name, err), nil)
}

// NotFoundErr returns a prepared 404 Not Found response, including the message passed by the user
// in the message field of the response object.
func NotFoundErr(msg string) *Response {
	return New(http.StatusNotFound, msg, nil)
}

// InternalError returns a prepared 500 Internal Server Error, including the error
// message in the message field of the response object
func InternalError(err error) *Response {
	return New(http.StatusInternalServerError, fmt.Sprintf("internal server error: %v", err), nil)
}

// WriteTo - pick a response writer to write the default json response to.
func (r *Response) WriteTo(w http.ResponseWriter) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(r.Code)
	json.NewEncoder(w).Encode(r)
}

// ExtractData returns a particular item of data from the response.
func (r *Response) ExtractData(srcKey string, dst interface{}) error {
	if !r.Data.Valid() {
		return fmt.Errorf("invalid data provided: %v", r.Data)
	}
	for key, value := range r.Data.Map() {
		if key != srcKey {
			continue
		}

		// Get the raw JSON just for the endpoints.
		rawJSON, err := json.Marshal(value)
		if err != nil {
			return err
		}

		// Decode the raw JSON.
		json.Unmarshal(rawJSON, &dst)
	}

	return nil
}

// GetCode returns the response code.
func (r *Response) GetCode() int {
	return r.Code
}

// PaginatedResponse - A paginated response format for a microservice.
type PaginatedResponse struct {
	Status     string               `json:"status"`         // Can be 'ok' or 'fail'
	Code       int                  `json:"code"`           // Any valid HTTP response code
	Message    string               `json:"message"`        // Any relevant message (optional)
	Data       *Data                `json:"data,omitempty"` // Data to pass along to the response (optional)
	Pagination *pagination.Response `json:"pagination"`     // Pagination data
}

// NewPaginated returns a new PaginatedResponse for a microservice endpoint
func NewPaginated(paginator *pagination.Paginator, code int, message string, data *Data) *PaginatedResponse {
	var status string
	switch {
	case code >= http.StatusOK && code < http.StatusBadRequest:
		status = StatusOk
	default:
		status = StatusFail
	}
	return &PaginatedResponse{
		Code:       code,
		Status:     status,
		Message:    message,
		Data:       data,
		Pagination: paginator.PrepareResponse(),
	}
}

func (p *PaginatedResponse) WriteTo(w http.ResponseWriter) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(p.Code)
	json.NewEncoder(w).Encode(p)
}

// ExtractData returns a particular item of data from the response.
func (p *PaginatedResponse) ExtractData(srcKey string, dst interface{}) error {
	if !p.Data.Valid() {
		return fmt.Errorf("invalid data provided: %v", p.Data)
	}
	for key, value := range p.Data.Map() {
		if key != srcKey {
			continue
		}

		// Get the raw JSON just for the endpoints.
		rawJSON, err := json.Marshal(value)
		if err != nil {
			return err
		}

		// Decode the raw JSON.
		json.Unmarshal(rawJSON, &dst)
	}

	return nil
}

// GetCode returns the response code.
func (p *PaginatedResponse) GetCode() int {
	return p.Code
}

// Data represents the collection data the the response will return to the consumer.
// Type ends up being the name of the key containing the collection of Content
type Data struct {
	Type    string
	Content interface{}
}

// UnmarshalJSON implements the Unmarshaler interface
// this implementation will fill the type in the case we're been provided a valid single collection
// and set the content to the contents of said collection.
// for every other options, it behaves like normal.
// Despite the fact that we are not suposed to marshal without a type set,
// this is purposefuly left open to unmarshal without a collection name set, in case you may want to set it later,
// and for interop with other systems which may not send the collection properly.
func (d *Data) UnmarshalJSON(b []byte) error {
	if err := json.Unmarshal(b, &d.Content); err != nil {
		log.Printf("cannot unmarshal data: %v", err)
	}

	data, ok := d.Content.(map[string]interface{})
	if ok {
		// count how many collections were provided
		var count int
		for _, value := range data {
			if _, ok := value.(map[string]interface{}); ok {
				count++
			}
			if _, ok := value.([]interface{}); ok {
				count++
			}
		}
		if count > 1 {
			// we can stop there since this is not a single collection
			return nil
		}

		for key, value := range data {
			if _, ok := value.(map[string]interface{}); ok {
				d.Type = key
				d.Content = data[key]
			} else if _, ok := value.([]interface{}); ok {
				d.Type = key
				d.Content = data[key]
			}
		}
	}

	return nil
}

// Valid ensures the Data passed to the response is correct (it must contain a Type along with the data).
func (d *Data) Valid() bool {
	if d.Type != "" {
		return true
	}
	return false
}

// MarshalJSON implements the Marshaler interface and is there to ensure the output
// is correct when we return data to the consumer
func (d *Data) MarshalJSON() ([]byte, error) {
	return json.Marshal(d.Map())
}

// Map returns a version of the data as a map
func (d *Data) Map() map[string]interface{} {
	if !d.Valid() {
		return nil
	}
	d.Type = strings.Replace(strings.ToLower(d.Type), " ", "-", -1)

	return map[string]interface{}{
		d.Type: d.Content,
	}
}
<commit_msg>added Conflict response<commit_after>// Package response defines the how the default microservice response must look and behave like.
package response

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

	"github.com/LUSHDigital/microservice-core-golang/pagination"
	"database/sql"
	"github.com/VividCortex/mysqlerr"
	"github.com/go-sql-driver/mysql"
)

// Standard response statuses.
const (
	StatusOk   = "ok"
	StatusFail = "fail"
)

// ResponseInterface - Interface for microservice responses.
type ResponseInterface interface {
	// ExtractData returns a particular item of data from the response.
	ExtractData(srcKey string, dst interface{}) error

	// GetCode returns the response code.
	GetCode() int
}

// Response - A standardised response format for a microservice.
type Response struct {
	Status  string `json:"status"`         // Can be 'ok' or 'fail'
	Code    int    `json:"code"`           // Any valid HTTP response code
	Message string `json:"message"`        // Any relevant message (optional)
	Data    *Data  `json:"data,omitempty"` // Data to pass along to the response (optional)
}

// New returns a new Response for a microservice endpoint
// This ensures that all API endpoints return data in a standardised format:
//
//    {
//       "status": "ok or fail",
//       "code": any HTTP response code,
//       "message": "any relevant message (optional)",
//       "data": {[
//          ...
//       ]}
//    }
func New(code int, message string, data *Data) *Response {
	var status string
	switch {
	case code >= http.StatusOK && code < http.StatusBadRequest:
		status = StatusOk
	default:
		status = StatusFail
	}
	return &Response{
		Code:    code,
		Status:  status,
		Message: message,
		Data:    data,
	}
}

// SQLError returns a prepared 422 Unprocessable Entity response if the error passed is of type sql.ErrNoRows,
// otherwise, returns a 500 Internal Server Error prepared response.
func SQLError(err error) *Response {
	if err == sql.ErrNoRows {
		return New(http.StatusUnprocessableEntity, "no data found", nil)
	}
	if driverErr, ok := err.(*mysql.MySQLError); ok {
		if driverErr.Number == mysqlerr.ER_DUP_ENTRY {
			return New(http.StatusUnprocessableEntity, "duplicate entry.", nil)
		}
	}
	return New(http.StatusInternalServerError, fmt.Sprintf("db error: %v", err), nil)
}

// JSONError returns a prepared 422 Unprocessable Entity response if the error passed is of type *json.SyntaxError,
// otherwise, returns a 500 Internal Server Error prepared response.
func JSONError(err error) *Response {
	if syn, ok := err.(*json.SyntaxError); ok {
		return New(http.StatusUnprocessableEntity, fmt.Sprintf("invalid json: %v", syn), nil)
	}
	return New(http.StatusInternalServerError, fmt.Sprintf("json error: %v", err), nil)
}

// ParamError returns a prepared 422 Unprocessable Entity response, including the name of
// the failing parameter in the message field of the response object.
func ParamError(name string) *Response {
	return New(http.StatusUnprocessableEntity, fmt.Sprintf("invalid or missing parameter: %v", name), nil)
}

// ValidationError returns a prepared 422 Unprocessable Entity response, including the name of
// the failing validation/validator in the message field of the response object.
func ValidationError(err error, name string) *Response {
	return New(http.StatusUnprocessableEntity, fmt.Sprintf("validation error on %s: %v", name, err), nil)
}

// NotFoundErr returns a prepared 404 Not Found response, including the message passed by the user
// in the message field of the response object.
func NotFoundErr(msg string) *Response {
	return New(http.StatusNotFound, msg, nil)
}

// ConflictErr returns a prepared 409 Conflict response, including the message passed by the user
// in the message field of the response object.
func ConflictErr(msg string) *Response {
	return New(http.StatusConflict, msg, nil)
}

// InternalError returns a prepared 500 Internal Server Error, including the error
// message in the message field of the response object
func InternalError(err error) *Response {
	return New(http.StatusInternalServerError, fmt.Sprintf("internal server error: %v", err), nil)
}

// WriteTo - pick a response writer to write the default json response to.
func (r *Response) WriteTo(w http.ResponseWriter) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(r.Code)
	json.NewEncoder(w).Encode(r)
}

// ExtractData returns a particular item of data from the response.
func (r *Response) ExtractData(srcKey string, dst interface{}) error {
	if !r.Data.Valid() {
		return fmt.Errorf("invalid data provided: %v", r.Data)
	}
	for key, value := range r.Data.Map() {
		if key != srcKey {
			continue
		}

		// Get the raw JSON just for the endpoints.
		rawJSON, err := json.Marshal(value)
		if err != nil {
			return err
		}

		// Decode the raw JSON.
		json.Unmarshal(rawJSON, &dst)
	}

	return nil
}

// GetCode returns the response code.
func (r *Response) GetCode() int {
	return r.Code
}

// PaginatedResponse - A paginated response format for a microservice.
type PaginatedResponse struct {
	Status     string               `json:"status"`         // Can be 'ok' or 'fail'
	Code       int                  `json:"code"`           // Any valid HTTP response code
	Message    string               `json:"message"`        // Any relevant message (optional)
	Data       *Data                `json:"data,omitempty"` // Data to pass along to the response (optional)
	Pagination *pagination.Response `json:"pagination"`     // Pagination data
}

// NewPaginated returns a new PaginatedResponse for a microservice endpoint
func NewPaginated(paginator *pagination.Paginator, code int, message string, data *Data) *PaginatedResponse {
	var status string
	switch {
	case code >= http.StatusOK && code < http.StatusBadRequest:
		status = StatusOk
	default:
		status = StatusFail
	}
	return &PaginatedResponse{
		Code:       code,
		Status:     status,
		Message:    message,
		Data:       data,
		Pagination: paginator.PrepareResponse(),
	}
}

func (p *PaginatedResponse) WriteTo(w http.ResponseWriter) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(p.Code)
	json.NewEncoder(w).Encode(p)
}

// ExtractData returns a particular item of data from the response.
func (p *PaginatedResponse) ExtractData(srcKey string, dst interface{}) error {
	if !p.Data.Valid() {
		return fmt.Errorf("invalid data provided: %v", p.Data)
	}
	for key, value := range p.Data.Map() {
		if key != srcKey {
			continue
		}

		// Get the raw JSON just for the endpoints.
		rawJSON, err := json.Marshal(value)
		if err != nil {
			return err
		}

		// Decode the raw JSON.
		json.Unmarshal(rawJSON, &dst)
	}

	return nil
}

// GetCode returns the response code.
func (p *PaginatedResponse) GetCode() int {
	return p.Code
}

// Data represents the collection data the the response will return to the consumer.
// Type ends up being the name of the key containing the collection of Content
type Data struct {
	Type    string
	Content interface{}
}

// UnmarshalJSON implements the Unmarshaler interface
// this implementation will fill the type in the case we're been provided a valid single collection
// and set the content to the contents of said collection.
// for every other options, it behaves like normal.
// Despite the fact that we are not suposed to marshal without a type set,
// this is purposefuly left open to unmarshal without a collection name set, in case you may want to set it later,
// and for interop with other systems which may not send the collection properly.
func (d *Data) UnmarshalJSON(b []byte) error {
	if err := json.Unmarshal(b, &d.Content); err != nil {
		log.Printf("cannot unmarshal data: %v", err)
	}

	data, ok := d.Content.(map[string]interface{})
	if ok {
		// count how many collections were provided
		var count int
		for _, value := range data {
			if _, ok := value.(map[string]interface{}); ok {
				count++
			}
			if _, ok := value.([]interface{}); ok {
				count++
			}
		}
		if count > 1 {
			// we can stop there since this is not a single collection
			return nil
		}

		for key, value := range data {
			if _, ok := value.(map[string]interface{}); ok {
				d.Type = key
				d.Content = data[key]
			} else if _, ok := value.([]interface{}); ok {
				d.Type = key
				d.Content = data[key]
			}
		}
	}

	return nil
}

// Valid ensures the Data passed to the response is correct (it must contain a Type along with the data).
func (d *Data) Valid() bool {
	if d.Type != "" {
		return true
	}
	return false
}

// MarshalJSON implements the Marshaler interface and is there to ensure the output
// is correct when we return data to the consumer
func (d *Data) MarshalJSON() ([]byte, error) {
	return json.Marshal(d.Map())
}

// Map returns a version of the data as a map
func (d *Data) Map() map[string]interface{} {
	if !d.Valid() {
		return nil
	}
	d.Type = strings.Replace(strings.ToLower(d.Type), " ", "-", -1)

	return map[string]interface{}{
		d.Type: d.Content,
	}
}
<|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 features

import (
	"k8s.io/apimachinery/pkg/util/runtime"

	utilfeature "k8s.io/apiserver/pkg/util/feature"
	"k8s.io/component-base/featuregate"
)

const (
	// Every feature gate should add method here following this template:
	//
	// // owner: @username
	// // alpha: v1.4
	// MyFeature() bool

	// owner: @tallclair
	// alpha: v1.5
	// beta: v1.6
	// deprecated: v1.18
	//
	// StreamingProxyRedirects controls whether the apiserver should intercept (and follow)
	// redirects from the backend (Kubelet) for streaming requests (exec/attach/port-forward).
	//
	// This feature is deprecated, and will be removed in v1.22.
	StreamingProxyRedirects featuregate.Feature = "StreamingProxyRedirects"

	// owner: @tallclair
	// alpha: v1.12
	// beta: v1.14
	//
	// ValidateProxyRedirects controls whether the apiserver should validate that redirects are only
	// followed to the same host. Only used if StreamingProxyRedirects is enabled.
	ValidateProxyRedirects featuregate.Feature = "ValidateProxyRedirects"

	// owner: @tallclair
	// alpha: v1.7
	// beta: v1.8
	// GA: v1.12
	//
	// AdvancedAuditing enables a much more general API auditing pipeline, which includes support for
	// pluggable output backends and an audit policy specifying how different requests should be
	// audited.
	AdvancedAuditing featuregate.Feature = "AdvancedAuditing"

	// owner: @ilackams
	// alpha: v1.7
	//
	// Enables compression of REST responses (GET and LIST only)
	APIResponseCompression featuregate.Feature = "APIResponseCompression"

	// owner: @smarterclayton
	// alpha: v1.8
	// beta: v1.9
	//
	// Allow API clients to retrieve resource lists in chunks rather than
	// all at once.
	APIListChunking featuregate.Feature = "APIListChunking"

	// owner: @apelisse
	// alpha: v1.12
	// beta: v1.13
	// stable: v1.18
	//
	// Allow requests to be processed but not stored, so that
	// validation, merging, mutation can be tested without
	// committing.
	DryRun featuregate.Feature = "DryRun"

	// owner: @caesarxuchao
	// alpha: v1.15
	//
	// Allow apiservers to show a count of remaining items in the response
	// to a chunking list request.
	RemainingItemCount featuregate.Feature = "RemainingItemCount"

	// owner: @apelisse, @lavalamp
	// alpha: v1.14
	// beta: v1.16
	//
	// Server-side apply. Merging happens on the server.
	ServerSideApply featuregate.Feature = "ServerSideApply"

	// owner: @caesarxuchao
	// alpha: v1.14
	// beta: v1.15
	//
	// Allow apiservers to expose the storage version hash in the discovery
	// document.
	StorageVersionHash featuregate.Feature = "StorageVersionHash"

	// owner: @wojtek-t
	// alpha: v1.15
	// beta: v1.16
	// GA: v1.17
	//
	// Enables support for watch bookmark events.
	WatchBookmark featuregate.Feature = "WatchBookmark"

	// owner: @MikeSpreitzer @yue9944882
	// alpha: v1.15
	//
	//
	// Enables managing request concurrency with prioritization and fairness at each server
	APIPriorityAndFairness featuregate.Feature = "APIPriorityAndFairness"

	// owner: @wojtek-t
	// alpha: v1.16
	// beta: v1.20
	//
	// Deprecates and removes SelfLink from ObjectMeta and ListMeta.
	RemoveSelfLink featuregate.Feature = "RemoveSelfLink"

	// owner: @shaloulcy, @wojtek-t
	// alpha: v1.18
	// beta: v1.19
	// GA: v1.20
	//
	// Allows label and field based indexes in apiserver watch cache to accelerate list operations.
	SelectorIndex featuregate.Feature = "SelectorIndex"

	// owner: @liggitt
	// beta: v1.19
	//
	// Allows sending warning headers in API responses.
	WarningHeaders featuregate.Feature = "WarningHeaders"

	// owner: @wojtek-t
	// alpha: v1.20
	//
	// Allows for updating watchcache resource version with progress notify events.
	EfficientWatchResumption featuregate.Feature = "EfficientWatchResumption"
)

func init() {
	runtime.Must(utilfeature.DefaultMutableFeatureGate.Add(defaultKubernetesFeatureGates))
}

// defaultKubernetesFeatureGates consists of all known Kubernetes-specific feature keys.
// To add a new feature, define a key for it above and add it here. The features will be
// available throughout Kubernetes binaries.
var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
	StreamingProxyRedirects:  {Default: true, PreRelease: featuregate.Deprecated},
	ValidateProxyRedirects:   {Default: true, PreRelease: featuregate.Beta},
	AdvancedAuditing:         {Default: true, PreRelease: featuregate.GA},
	APIResponseCompression:   {Default: true, PreRelease: featuregate.Beta},
	APIListChunking:          {Default: true, PreRelease: featuregate.Beta},
	DryRun:                   {Default: true, PreRelease: featuregate.GA},
	RemainingItemCount:       {Default: true, PreRelease: featuregate.Beta},
	ServerSideApply:          {Default: true, PreRelease: featuregate.Beta},
	StorageVersionHash:       {Default: true, PreRelease: featuregate.Beta},
	WatchBookmark:            {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
	APIPriorityAndFairness:   {Default: false, PreRelease: featuregate.Alpha},
	RemoveSelfLink:           {Default: true, PreRelease: featuregate.Beta},
	SelectorIndex:            {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
	WarningHeaders:           {Default: true, PreRelease: featuregate.Beta},
	EfficientWatchResumption: {Default: false, PreRelease: featuregate.Alpha},
}
<commit_msg>add an APIServerIdentity feature gate<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 features

import (
	"k8s.io/apimachinery/pkg/util/runtime"

	utilfeature "k8s.io/apiserver/pkg/util/feature"
	"k8s.io/component-base/featuregate"
)

const (
	// Every feature gate should add method here following this template:
	//
	// // owner: @username
	// // alpha: v1.4
	// MyFeature() bool

	// owner: @tallclair
	// alpha: v1.5
	// beta: v1.6
	// deprecated: v1.18
	//
	// StreamingProxyRedirects controls whether the apiserver should intercept (and follow)
	// redirects from the backend (Kubelet) for streaming requests (exec/attach/port-forward).
	//
	// This feature is deprecated, and will be removed in v1.22.
	StreamingProxyRedirects featuregate.Feature = "StreamingProxyRedirects"

	// owner: @tallclair
	// alpha: v1.12
	// beta: v1.14
	//
	// ValidateProxyRedirects controls whether the apiserver should validate that redirects are only
	// followed to the same host. Only used if StreamingProxyRedirects is enabled.
	ValidateProxyRedirects featuregate.Feature = "ValidateProxyRedirects"

	// owner: @tallclair
	// alpha: v1.7
	// beta: v1.8
	// GA: v1.12
	//
	// AdvancedAuditing enables a much more general API auditing pipeline, which includes support for
	// pluggable output backends and an audit policy specifying how different requests should be
	// audited.
	AdvancedAuditing featuregate.Feature = "AdvancedAuditing"

	// owner: @ilackams
	// alpha: v1.7
	//
	// Enables compression of REST responses (GET and LIST only)
	APIResponseCompression featuregate.Feature = "APIResponseCompression"

	// owner: @smarterclayton
	// alpha: v1.8
	// beta: v1.9
	//
	// Allow API clients to retrieve resource lists in chunks rather than
	// all at once.
	APIListChunking featuregate.Feature = "APIListChunking"

	// owner: @apelisse
	// alpha: v1.12
	// beta: v1.13
	// stable: v1.18
	//
	// Allow requests to be processed but not stored, so that
	// validation, merging, mutation can be tested without
	// committing.
	DryRun featuregate.Feature = "DryRun"

	// owner: @caesarxuchao
	// alpha: v1.15
	//
	// Allow apiservers to show a count of remaining items in the response
	// to a chunking list request.
	RemainingItemCount featuregate.Feature = "RemainingItemCount"

	// owner: @apelisse, @lavalamp
	// alpha: v1.14
	// beta: v1.16
	//
	// Server-side apply. Merging happens on the server.
	ServerSideApply featuregate.Feature = "ServerSideApply"

	// owner: @caesarxuchao
	// alpha: v1.14
	// beta: v1.15
	//
	// Allow apiservers to expose the storage version hash in the discovery
	// document.
	StorageVersionHash featuregate.Feature = "StorageVersionHash"

	// owner: @wojtek-t
	// alpha: v1.15
	// beta: v1.16
	// GA: v1.17
	//
	// Enables support for watch bookmark events.
	WatchBookmark featuregate.Feature = "WatchBookmark"

	// owner: @MikeSpreitzer @yue9944882
	// alpha: v1.15
	//
	//
	// Enables managing request concurrency with prioritization and fairness at each server
	APIPriorityAndFairness featuregate.Feature = "APIPriorityAndFairness"

	// owner: @wojtek-t
	// alpha: v1.16
	// beta: v1.20
	//
	// Deprecates and removes SelfLink from ObjectMeta and ListMeta.
	RemoveSelfLink featuregate.Feature = "RemoveSelfLink"

	// owner: @shaloulcy, @wojtek-t
	// alpha: v1.18
	// beta: v1.19
	// GA: v1.20
	//
	// Allows label and field based indexes in apiserver watch cache to accelerate list operations.
	SelectorIndex featuregate.Feature = "SelectorIndex"

	// owner: @liggitt
	// beta: v1.19
	//
	// Allows sending warning headers in API responses.
	WarningHeaders featuregate.Feature = "WarningHeaders"

	// owner: @wojtek-t
	// alpha: v1.20
	//
	// Allows for updating watchcache resource version with progress notify events.
	EfficientWatchResumption featuregate.Feature = "EfficientWatchResumption"

	// owner: @roycaihw
	// alpha: v1.20
	//
	// Assigns each kube-apiserver an ID in a cluster.
	APIServerIdentity featuregate.Feature = "APIServerIdentity"
)

func init() {
	runtime.Must(utilfeature.DefaultMutableFeatureGate.Add(defaultKubernetesFeatureGates))
}

// defaultKubernetesFeatureGates consists of all known Kubernetes-specific feature keys.
// To add a new feature, define a key for it above and add it here. The features will be
// available throughout Kubernetes binaries.
var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
	StreamingProxyRedirects:  {Default: true, PreRelease: featuregate.Deprecated},
	ValidateProxyRedirects:   {Default: true, PreRelease: featuregate.Beta},
	AdvancedAuditing:         {Default: true, PreRelease: featuregate.GA},
	APIResponseCompression:   {Default: true, PreRelease: featuregate.Beta},
	APIListChunking:          {Default: true, PreRelease: featuregate.Beta},
	DryRun:                   {Default: true, PreRelease: featuregate.GA},
	RemainingItemCount:       {Default: true, PreRelease: featuregate.Beta},
	ServerSideApply:          {Default: true, PreRelease: featuregate.Beta},
	StorageVersionHash:       {Default: true, PreRelease: featuregate.Beta},
	WatchBookmark:            {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
	APIPriorityAndFairness:   {Default: false, PreRelease: featuregate.Alpha},
	RemoveSelfLink:           {Default: true, PreRelease: featuregate.Beta},
	SelectorIndex:            {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
	WarningHeaders:           {Default: true, PreRelease: featuregate.Beta},
	EfficientWatchResumption: {Default: false, PreRelease: featuregate.Alpha},
	APIServerIdentity:        {Default: false, PreRelease: featuregate.Alpha},
}
<|endoftext|>


<commit_before>package allyourbase

import (
	"errors"
	"fmt"
	"math"
)

func ConvertToBase(inputBase int, inputDigits []int, outputBase int) (outputDigits []int, e error) {
	if inputBase < 2 {
		return []int{}, errors.New("input base must be >= 2")
	}
	if outputBase < 2 {
		return []int{}, errors.New("output base must be >= 2")
	}
	if invalidDigit(inputBase, inputDigits) {
		return []int{}, errors.New("all digits must satisfy 0 <= d < input base")
	}
	base10 := getBase10Input(inputBase, inputDigits)
	if base10 == 0 {
		return []int{0}, nil
	}
	for base10 > 0 {
		digit := base10 % outputBase
		outputDigits = append([]int{digit}, outputDigits...)
		base10 = base10 / outputBase
	}
	return outputDigits, nil
}

func getBase10Input(inputBase int, inputDigits []int) (base10Input int) {
	for i, digit := range reverse(inputDigits) {
		base10Input += powInt(inputBase, i) * digit
	}
	fmt.Printf("getBase10Input(%d, %v)=%d\n", inputBase, inputDigits, base10Input)
	return base10Input
}

func invalidDigit(inputBase int, input []int) bool {
	for _, digit := range input {
		if digit < 0 {
			return true
		}
		if digit >= inputBase {
			return true
		}
	}
	return false
}

func reverse(input []int) (reversed []int) {
	for i := len(input) - 1; i >= 0; i-- {
		reversed = append(reversed, input[i])
	}
	return reversed
}

func powInt(x, y int) int {
	return int(math.Pow(float64(x), float64(y)))
}
<commit_msg>Minor refactor<commit_after>package allyourbase

import (
	"errors"
	"math"
)

func ConvertToBase(inputBase int, inputDigits []int, outputBase int) (outputDigits []int, e error) {
	if inputBase < 2 {
		return []int{}, errors.New("input base must be >= 2")
	}
	if outputBase < 2 {
		return []int{}, errors.New("output base must be >= 2")
	}
	if invalidDigit(inputBase, inputDigits) {
		return []int{}, errors.New("all digits must satisfy 0 <= d < input base")
	}
	base10 := getBase10Input(inputBase, inputDigits)
	if base10 == 0 {
		return []int{0}, nil
	}
	for base10 > 0 {
		digit := base10 % outputBase
		outputDigits = append([]int{digit}, outputDigits...)
		base10 = base10 / outputBase
	}
	return outputDigits, nil
}

func getBase10Input(inputBase int, inputDigits []int) (base10Input int) {
	for i, digit := range reverse(inputDigits) {
		base10Input += powInt(inputBase, i) * digit
	}
	return base10Input
}

func invalidDigit(inputBase int, input []int) bool {
	for _, digit := range input {
		if digit < 0 || digit >= inputBase {
			return true
		}
	}
	return false
}

func reverse(input []int) (reversed []int) {
	for i := len(input) - 1; i >= 0; i-- {
		reversed = append(reversed, input[i])
	}
	return reversed
}

func powInt(x, y int) int {
	return int(math.Pow(float64(x), float64(y)))
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor:
// - Aaron Meihm ameihm@mozilla.com
package main

import (
	"bufio"
	"encoding/xml"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"oval"
	"path"
	"regexp"
	"strings"
)

type distPatchInfo map[string]string

type cveEntry struct {
	cveID  string
	pkgMap map[string]distPatchInfo
}

var entries []cveEntry
var matchFilter *regexp.Regexp

func parseEntryFile(fpath string) (ret cveEntry) {
	const (
		_ = iota
		INNER_NONE
		INNER_PATCH
	)
	fd, err := os.Open(fpath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(1)
	}
	defer func() {
		fd.Close()
	}()

	scanner := bufio.NewScanner(fd)
	parserMode := INNER_NONE
	curPkgName := ""
	ret.cveID = path.Base(fpath)
	ret.pkgMap = make(map[string]distPatchInfo)
	for scanner.Scan() {
		tokens := strings.Fields(scanner.Text())
		if len(tokens) == 0 {
			parserMode = INNER_NONE
			curPkgName = ""
			continue
		}

		if strings.HasPrefix(tokens[0], "Patches_") {
			parserMode = INNER_PATCH
			curPkgName = strings.TrimPrefix(tokens[0], "Patches_")
			curPkgName = strings.TrimRight(curPkgName, ":")
			ret.pkgMap[curPkgName] = make(map[string]string)
			continue
		}

		if parserMode == INNER_PATCH {
			if len(tokens) < 2 {
				continue
			}
			idx := strings.Index(tokens[0], "_")
			if idx == -1 {
				continue
			}
			distname := tokens[0][:idx]
			if tokens[1] == "released" && len(tokens) > 2 {
				patchver := tokens[2]
				patchver = strings.Trim(patchver, "()")
				ret.pkgMap[curPkgName][distname] = patchver
			}
		}
	}
	if err = scanner.Err(); err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(1)
	}

	return
}

func loadEntries(dirpath string) {
	dirents, err := ioutil.ReadDir(dirpath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(1)
	}
	for _, i := range dirents {
		if !strings.HasPrefix(i.Name(), "CVE-") {
			continue
		}
		if matchFilter != nil {
			if !matchFilter.MatchString(i.Name()) {
				continue
			}
		}
		fname := path.Join(dirpath, i.Name())
		entries = append(entries, parseEntryFile(fname))
	}
}

func addDefinition(o *oval.GOvalDefinitions, prefix string, pkgname string, dist string, cve cveEntry) {
	// Create a state
	stateid := fmt.Sprintf("%v-state", prefix)
	state := oval.GDPKGInfoState{}
	state.ID = stateid
	state.EVRCheck.DataType = "evr_string"
	state.EVRCheck.Operation = "less than"
	state.EVRCheck.Value = cve.pkgMap[pkgname][dist]

	// Create an object definition for the package
	objid := fmt.Sprintf("%v-object", prefix)
	obj := oval.GDPKGInfoObj{}
	obj.Name = pkgname
	obj.ID = objid

	// Create a test
	testid := fmt.Sprintf("%v-test", prefix)
	test := oval.GDPKGInfoTest{}
	test.ID = testid
	test.Object.ObjectRef = objid
	test.State.StateRef = stateid

	// Create the new definition
	def := oval.GDefinition{}
	def.ID = prefix
	def.Class = "patch"
	def.Metadata.Title = fmt.Sprintf("%v (%v) test for %v", cve.cveID, pkgname, dist)

	criterion := oval.GCriterion{}
	criterion.Test = testid
	def.Criteria.Operator = "AND"
	def.Criteria.Criterion = append(def.Criteria.Criterion, criterion)

	o.Definitions.Definitions = append(o.Definitions.Definitions, def)
	o.States.DPKGInfoStates = append(o.States.DPKGInfoStates, state)
	o.Objects.DPKGInfoObjects = append(o.Objects.DPKGInfoObjects, obj)
	o.Tests.DPKGInfoTests = append(o.Tests.DPKGInfoTests, test)
}

func processEntries() {
	root := oval.GOvalDefinitions{}

	for i, ent := range entries {
		for x := range ent.pkgMap {
			for y := range ent.pkgMap[x] {
				prefix := fmt.Sprintf("ubuntu-%v-%v-%v", i, x, y)
				addDefinition(&root, prefix, x, y, ent)
			}
		}
	}

	enc := xml.NewEncoder(os.Stdout)
	enc.Indent("", "  ")
	if err := enc.Encode(root); err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(1)
	}
}

func main() {
	var fMatch string

	flag.StringVar(&fMatch, "i", "", "filter regexp")
	flag.Parse()
	args := flag.Args()
	if len(args) < 1 {
		fmt.Fprintf(os.Stderr, "specify path to ubuntu-cve-tracker directory\n")
		os.Exit(1)
	}

	fm, err := regexp.Compile(fMatch)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(1)
	}
	matchFilter = fm

	entries = make([]cveEntry, 0)

	procdir := path.Join(args[0], "active")
	loadEntries(procdir)
	procdir = path.Join(args[0], "retired")
	loadEntries(procdir)
	processEntries()
}
<commit_msg>special handling for ubuntu kernel package revisions<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor:
// - Aaron Meihm ameihm@mozilla.com
package main

import (
	"bufio"
	"encoding/xml"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"oval"
	"path"
	"regexp"
	"strings"
	"unicode"
)

type distPatchInfo map[string]string

type cveEntry struct {
	cveID  string
	pkgMap map[string]distPatchInfo
}

var entries []cveEntry
var matchFilter *regexp.Regexp

// The hackTranslate* functions perform conversion on name and version
// strings if the package name is either "linux" or begins with "linux-". If
// this is the case, linux in the package name is translated to be
// "linux-image-generic". Additionally, the upload revision element if
// present in the version string is removed. This allows a comparison of
// the version to occur against a known package name (linux-image-generic),
// instead of requiring resolution of whatever the most recent installed
// kernel image package is which will be named linux-image-<ver>-generic.
func hackTranslateName(pkgname string) string {
	if pkgname != "linux" && !strings.HasPrefix(pkgname, "linux-") {
		return pkgname
	}
	return strings.Replace(pkgname, "linux", "linux-image-generic", 1)
}

func hackTranslateVersion(pkgname string, ver string) string {
	if !strings.HasPrefix(pkgname, "linux-image-generic") {
		return ver
	}

	ffunc := func(c rune) bool {
		if c == '-' {
			return true
		}
		return false
	}
	f := strings.FieldsFunc(ver, ffunc)
	if len(f) != 2 {
		return ver
	}
	ret := f[1]
	idx := strings.Index(ret, ".")
	if idx == -1 {
		return ver
	}
	idx2 := idx + 1
	for _, c := range ret[idx2:] {
		if !unicode.IsDigit(c) {
			break
		}
		idx2++
	}
	ret = f[0] + "." + ret[:idx] + ret[idx2:]

	return ret
}

func parseEntryFile(fpath string) (ret cveEntry) {
	const (
		_ = iota
		INNER_NONE
		INNER_PATCH
	)
	fd, err := os.Open(fpath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(1)
	}
	defer func() {
		fd.Close()
	}()

	scanner := bufio.NewScanner(fd)
	parserMode := INNER_NONE
	curPkgName := ""
	ret.cveID = path.Base(fpath)
	ret.pkgMap = make(map[string]distPatchInfo)
	for scanner.Scan() {
		tokens := strings.Fields(scanner.Text())
		if len(tokens) == 0 {
			parserMode = INNER_NONE
			curPkgName = ""
			continue
		}

		if strings.HasPrefix(tokens[0], "Patches_") {
			parserMode = INNER_PATCH
			curPkgName = strings.TrimPrefix(tokens[0], "Patches_")
			curPkgName = strings.TrimRight(curPkgName, ":")
			curPkgName = hackTranslateName(curPkgName)
			ret.pkgMap[curPkgName] = make(map[string]string)
			continue
		}

		if parserMode == INNER_PATCH {
			if len(tokens) < 2 {
				continue
			}
			idx := strings.Index(tokens[0], "_")
			if idx == -1 {
				continue
			}
			distname := tokens[0][:idx]
			if tokens[1] == "released" && len(tokens) > 2 {
				patchver := tokens[2]
				patchver = strings.Trim(patchver, "()")
				patchver = hackTranslateVersion(curPkgName, patchver)
				ret.pkgMap[curPkgName][distname] = patchver
			}
		}
	}
	if err = scanner.Err(); err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(1)
	}

	return
}

func loadEntries(dirpath string) {
	dirents, err := ioutil.ReadDir(dirpath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(1)
	}
	for _, i := range dirents {
		if !strings.HasPrefix(i.Name(), "CVE-") {
			continue
		}
		if matchFilter != nil {
			if !matchFilter.MatchString(i.Name()) {
				continue
			}
		}
		fname := path.Join(dirpath, i.Name())
		entries = append(entries, parseEntryFile(fname))
	}
}

func addDefinition(o *oval.GOvalDefinitions, prefix string, pkgname string, dist string, cve cveEntry) {
	// Create a state
	stateid := fmt.Sprintf("%v-state", prefix)
	state := oval.GDPKGInfoState{}
	state.ID = stateid
	state.EVRCheck.DataType = "evr_string"
	state.EVRCheck.Operation = "less than"
	state.EVRCheck.Value = cve.pkgMap[pkgname][dist]

	// Create an object definition for the package
	objid := fmt.Sprintf("%v-object", prefix)
	obj := oval.GDPKGInfoObj{}
	obj.Name = pkgname
	obj.ID = objid

	// Create a test
	testid := fmt.Sprintf("%v-test", prefix)
	test := oval.GDPKGInfoTest{}
	test.ID = testid
	test.Object.ObjectRef = objid
	test.State.StateRef = stateid

	// Create the new definition
	def := oval.GDefinition{}
	def.ID = prefix
	def.Class = "patch"
	def.Metadata.Title = fmt.Sprintf("%v (%v) test for %v", cve.cveID, pkgname, dist)

	criterion := oval.GCriterion{}
	criterion.Test = testid
	def.Criteria.Operator = "AND"
	def.Criteria.Criterion = append(def.Criteria.Criterion, criterion)

	o.Definitions.Definitions = append(o.Definitions.Definitions, def)
	o.States.DPKGInfoStates = append(o.States.DPKGInfoStates, state)
	o.Objects.DPKGInfoObjects = append(o.Objects.DPKGInfoObjects, obj)
	o.Tests.DPKGInfoTests = append(o.Tests.DPKGInfoTests, test)
}

func processEntries() {
	root := oval.GOvalDefinitions{}

	for i, ent := range entries {
		for x := range ent.pkgMap {
			for y := range ent.pkgMap[x] {
				prefix := fmt.Sprintf("ubuntu-%v-%v-%v", i, x, y)
				addDefinition(&root, prefix, x, y, ent)
			}
		}
	}

	enc := xml.NewEncoder(os.Stdout)
	enc.Indent("", "  ")
	if err := enc.Encode(root); err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(1)
	}
}

func main() {
	var fMatch string

	flag.StringVar(&fMatch, "i", "", "filter regexp")
	flag.Parse()
	args := flag.Args()
	if len(args) < 1 {
		fmt.Fprintf(os.Stderr, "specify path to ubuntu-cve-tracker directory\n")
		os.Exit(1)
	}

	fm, err := regexp.Compile(fMatch)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(1)
	}
	matchFilter = fm

	entries = make([]cveEntry, 0)

	procdir := path.Join(args[0], "active")
	loadEntries(procdir)
	procdir = path.Join(args[0], "retired")
	loadEntries(procdir)
	processEntries()
}
<|endoftext|>


<commit_before>package kubernetes

import (
	"io/ioutil"
	"os"
	"strings"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/labels"

	"github.com/weaveworks/scope/common/mtime"
	"github.com/weaveworks/scope/probe"
	"github.com/weaveworks/scope/probe/controls"
	"github.com/weaveworks/scope/probe/docker"
	"github.com/weaveworks/scope/report"
)

// Exposed for testing
var (
	PodMetadataTemplates = report.MetadataTemplates{
		PodID:      {ID: PodID, Label: "ID", From: report.FromLatest, Priority: 1},
		PodState:   {ID: PodState, Label: "State", From: report.FromLatest, Priority: 2},
		PodIP:      {ID: PodIP, Label: "IP", From: report.FromLatest, Priority: 3},
		Namespace:  {ID: Namespace, Label: "Namespace", From: report.FromLatest, Priority: 5},
		PodCreated: {ID: PodCreated, Label: "Created", From: report.FromLatest, Priority: 6},
	}

	ServiceMetadataTemplates = report.MetadataTemplates{
		ServiceID:       {ID: ServiceID, Label: "ID", From: report.FromLatest, Priority: 1},
		Namespace:       {ID: Namespace, Label: "Namespace", From: report.FromLatest, Priority: 2},
		ServiceCreated:  {ID: ServiceCreated, Label: "Created", From: report.FromLatest, Priority: 3},
		ServicePublicIP: {ID: ServicePublicIP, Label: "Public IP", From: report.FromLatest, Priority: 4},
		ServiceIP:       {ID: ServiceIP, Label: "Internal IP", From: report.FromLatest, Priority: 5},
	}

	PodTableTemplates = report.TableTemplates{
		PodLabelPrefix: {ID: PodLabelPrefix, Label: "Kubernetes Labels", Prefix: PodLabelPrefix},
	}

	ServiceTableTemplates = report.TableTemplates{
		ServiceLabelPrefix: {ID: ServiceLabelPrefix, Label: "Kubernetes Labels", Prefix: ServiceLabelPrefix},
	}
)

// Reporter generate Reports containing Container and ContainerImage topologies
type Reporter struct {
	client  Client
	pipes   controls.PipeClient
	probeID string
	probe   *probe.Probe
}

// NewReporter makes a new Reporter
func NewReporter(client Client, pipes controls.PipeClient, probeID string, probe *probe.Probe) *Reporter {
	reporter := &Reporter{
		client:  client,
		pipes:   pipes,
		probeID: probeID,
		probe:   probe,
	}
	reporter.registerControls()
	client.WatchPods(reporter.podEvent)
	return reporter
}

// Stop unregisters controls.
func (r *Reporter) Stop() {
	r.deregisterControls()
}

// Name of this reporter, for metrics gathering
func (Reporter) Name() string { return "K8s" }

func (r *Reporter) podEvent(e Event, pod Pod) {
	switch e {
	case ADD:
		rpt := report.MakeReport()
		rpt.Shortcut = true
		rpt.Pod.AddNode(pod.GetNode(r.probeID))
		r.probe.Publish(rpt)
	case DELETE:
		rpt := report.MakeReport()
		rpt.Shortcut = true
		rpt.Pod.AddNode(
			report.MakeNodeWith(
				report.MakePodNodeID(pod.UID()),
				map[string]string{PodState: StateDeleted},
			),
		)
		r.probe.Publish(rpt)
	}
}

func isPauseContainer(n report.Node, rpt report.Report) bool {
	containerImageIDs, ok := n.Sets.Lookup(report.ContainerImage)
	if !ok {
		return false
	}
	for _, imageNodeID := range containerImageIDs {
		imageNode, ok := rpt.ContainerImage.Nodes[imageNodeID]
		if !ok {
			continue
		}
		imageName, ok := imageNode.Latest.Lookup(docker.ImageName)
		if !ok {
			continue
		}
		if docker.ImageNameWithoutVersion(imageName) == "google_containers/pause" {
			return true
		}
	}
	return false
}

// Tag adds pod parents to container nodes.
func (r *Reporter) Tag(rpt report.Report) (report.Report, error) {
	for id, n := range rpt.Container.Nodes {
		uid, ok := n.Latest.Lookup(docker.LabelPrefix + "io.kubernetes.pod.uid")
		if !ok {
			continue
		}

		// Tag the pause containers with "does-not-make-connections"
		if isPauseContainer(n, rpt) {
			n = n.WithLatest(report.DoesNotMakeConnections, mtime.Now(), "")
		}

		rpt.Container.Nodes[id] = n.WithParents(report.EmptySets.Add(
			report.Pod,
			report.EmptyStringSet.Add(report.MakePodNodeID(uid)),
		))
	}
	return rpt, nil
}

// Report generates a Report containing Container and ContainerImage topologies
func (r *Reporter) Report() (report.Report, error) {
	result := report.MakeReport()
	serviceTopology, services, err := r.serviceTopology()
	if err != nil {
		return result, err
	}
	podTopology, err := r.podTopology(services)
	if err != nil {
		return result, err
	}
	result.Service = result.Service.Merge(serviceTopology)
	result.Pod = result.Pod.Merge(podTopology)
	return result, nil
}

func (r *Reporter) serviceTopology() (report.Topology, []Service, error) {
	var (
		result = report.MakeTopology().
			WithMetadataTemplates(ServiceMetadataTemplates).
			WithTableTemplates(ServiceTableTemplates)
		services = []Service{}
	)
	err := r.client.WalkServices(func(s Service) error {
		result = result.AddNode(s.GetNode())
		services = append(services, s)
		return nil
	})
	return result, services, err
}

// GetNodeName return the k8s node name for the current machine.
// It is exported for testing.
var GetNodeName = func(r *Reporter) (string, error) {
	uuidBytes, err := ioutil.ReadFile("/sys/class/dmi/id/product_uuid")
	if os.IsNotExist(err) {
		uuidBytes, err = ioutil.ReadFile("/sys/hypervisor/uuid")
	}
	if err != nil {
		return "", err
	}
	uuid := strings.Trim(string(uuidBytes), "\n")
	nodeName := ""
	err = r.client.WalkNodes(func(node *api.Node) error {
		if node.Status.NodeInfo.SystemUUID == string(uuid) {
			nodeName = node.ObjectMeta.Name
		}
		return nil
	})
	return nodeName, err
}

func (r *Reporter) podTopology(services []Service) (report.Topology, error) {
	var (
		pods = report.MakeTopology().
			WithMetadataTemplates(PodMetadataTemplates).
			WithTableTemplates(PodTableTemplates)
		selectors = map[string]labels.Selector{}
	)
	pods.Controls.AddControl(report.Control{
		ID:    GetLogs,
		Human: "Get logs",
		Icon:  "fa-desktop",
		Rank:  0,
	})
	pods.Controls.AddControl(report.Control{
		ID:    DeletePod,
		Human: "Delete",
		Icon:  "fa-trash-o",
		Rank:  1,
	})
	for _, service := range services {
		selectors[service.ID()] = service.Selector()
	}

	thisNodeName, err := GetNodeName(r)
	if err != nil {
		return pods, err
	}
	err = r.client.WalkPods(func(p Pod) error {
		if p.NodeName() != thisNodeName {
			return nil
		}
		for serviceID, selector := range selectors {
			if selector.Matches(p.Labels()) {
				p.AddServiceID(serviceID)
			}
		}
		pods = pods.AddNode(p.GetNode(r.probeID))
		return nil
	})
	return pods, err
}
<commit_msg>Detect pause containers correctly<commit_after>package kubernetes

import (
	"io/ioutil"
	"os"
	"strings"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/labels"

	"github.com/weaveworks/scope/common/mtime"
	"github.com/weaveworks/scope/probe"
	"github.com/weaveworks/scope/probe/controls"
	"github.com/weaveworks/scope/probe/docker"
	"github.com/weaveworks/scope/report"
)

// Exposed for testing
var (
	PodMetadataTemplates = report.MetadataTemplates{
		PodID:      {ID: PodID, Label: "ID", From: report.FromLatest, Priority: 1},
		PodState:   {ID: PodState, Label: "State", From: report.FromLatest, Priority: 2},
		PodIP:      {ID: PodIP, Label: "IP", From: report.FromLatest, Priority: 3},
		Namespace:  {ID: Namespace, Label: "Namespace", From: report.FromLatest, Priority: 5},
		PodCreated: {ID: PodCreated, Label: "Created", From: report.FromLatest, Priority: 6},
	}

	ServiceMetadataTemplates = report.MetadataTemplates{
		ServiceID:       {ID: ServiceID, Label: "ID", From: report.FromLatest, Priority: 1},
		Namespace:       {ID: Namespace, Label: "Namespace", From: report.FromLatest, Priority: 2},
		ServiceCreated:  {ID: ServiceCreated, Label: "Created", From: report.FromLatest, Priority: 3},
		ServicePublicIP: {ID: ServicePublicIP, Label: "Public IP", From: report.FromLatest, Priority: 4},
		ServiceIP:       {ID: ServiceIP, Label: "Internal IP", From: report.FromLatest, Priority: 5},
	}

	PodTableTemplates = report.TableTemplates{
		PodLabelPrefix: {ID: PodLabelPrefix, Label: "Kubernetes Labels", Prefix: PodLabelPrefix},
	}

	ServiceTableTemplates = report.TableTemplates{
		ServiceLabelPrefix: {ID: ServiceLabelPrefix, Label: "Kubernetes Labels", Prefix: ServiceLabelPrefix},
	}
)

// Reporter generate Reports containing Container and ContainerImage topologies
type Reporter struct {
	client  Client
	pipes   controls.PipeClient
	probeID string
	probe   *probe.Probe
}

// NewReporter makes a new Reporter
func NewReporter(client Client, pipes controls.PipeClient, probeID string, probe *probe.Probe) *Reporter {
	reporter := &Reporter{
		client:  client,
		pipes:   pipes,
		probeID: probeID,
		probe:   probe,
	}
	reporter.registerControls()
	client.WatchPods(reporter.podEvent)
	return reporter
}

// Stop unregisters controls.
func (r *Reporter) Stop() {
	r.deregisterControls()
}

// Name of this reporter, for metrics gathering
func (Reporter) Name() string { return "K8s" }

func (r *Reporter) podEvent(e Event, pod Pod) {
	switch e {
	case ADD:
		rpt := report.MakeReport()
		rpt.Shortcut = true
		rpt.Pod.AddNode(pod.GetNode(r.probeID))
		r.probe.Publish(rpt)
	case DELETE:
		rpt := report.MakeReport()
		rpt.Shortcut = true
		rpt.Pod.AddNode(
			report.MakeNodeWith(
				report.MakePodNodeID(pod.UID()),
				map[string]string{PodState: StateDeleted},
			),
		)
		r.probe.Publish(rpt)
	}
}

func isPauseContainer(n report.Node, rpt report.Report) bool {
	containerImageIDs, ok := n.Parents.Lookup(report.ContainerImage)
	if !ok {
		return false
	}
	for _, imageNodeID := range containerImageIDs {
		imageNode, ok := rpt.ContainerImage.Nodes[imageNodeID]
		if !ok {
			continue
		}
		imageName, ok := imageNode.Latest.Lookup(docker.ImageName)
		if !ok {
			continue
		}
		if docker.ImageNameWithoutVersion(imageName) == "google_containers/pause" {
			return true
		}
	}
	return false
}

// Tag adds pod parents to container nodes.
func (r *Reporter) Tag(rpt report.Report) (report.Report, error) {
	for id, n := range rpt.Container.Nodes {
		uid, ok := n.Latest.Lookup(docker.LabelPrefix + "io.kubernetes.pod.uid")
		if !ok {
			continue
		}

		// Tag the pause containers with "does-not-make-connections"
		if isPauseContainer(n, rpt) {
			n = n.WithLatest(report.DoesNotMakeConnections, mtime.Now(), "")
		}

		rpt.Container.Nodes[id] = n.WithParents(report.EmptySets.Add(
			report.Pod,
			report.EmptyStringSet.Add(report.MakePodNodeID(uid)),
		))
	}
	return rpt, nil
}

// Report generates a Report containing Container and ContainerImage topologies
func (r *Reporter) Report() (report.Report, error) {
	result := report.MakeReport()
	serviceTopology, services, err := r.serviceTopology()
	if err != nil {
		return result, err
	}
	podTopology, err := r.podTopology(services)
	if err != nil {
		return result, err
	}
	result.Service = result.Service.Merge(serviceTopology)
	result.Pod = result.Pod.Merge(podTopology)
	return result, nil
}

func (r *Reporter) serviceTopology() (report.Topology, []Service, error) {
	var (
		result = report.MakeTopology().
			WithMetadataTemplates(ServiceMetadataTemplates).
			WithTableTemplates(ServiceTableTemplates)
		services = []Service{}
	)
	err := r.client.WalkServices(func(s Service) error {
		result = result.AddNode(s.GetNode())
		services = append(services, s)
		return nil
	})
	return result, services, err
}

// GetNodeName return the k8s node name for the current machine.
// It is exported for testing.
var GetNodeName = func(r *Reporter) (string, error) {
	uuidBytes, err := ioutil.ReadFile("/sys/class/dmi/id/product_uuid")
	if os.IsNotExist(err) {
		uuidBytes, err = ioutil.ReadFile("/sys/hypervisor/uuid")
	}
	if err != nil {
		return "", err
	}
	uuid := strings.Trim(string(uuidBytes), "\n")
	nodeName := ""
	err = r.client.WalkNodes(func(node *api.Node) error {
		if node.Status.NodeInfo.SystemUUID == string(uuid) {
			nodeName = node.ObjectMeta.Name
		}
		return nil
	})
	return nodeName, err
}

func (r *Reporter) podTopology(services []Service) (report.Topology, error) {
	var (
		pods = report.MakeTopology().
			WithMetadataTemplates(PodMetadataTemplates).
			WithTableTemplates(PodTableTemplates)
		selectors = map[string]labels.Selector{}
	)
	pods.Controls.AddControl(report.Control{
		ID:    GetLogs,
		Human: "Get logs",
		Icon:  "fa-desktop",
		Rank:  0,
	})
	pods.Controls.AddControl(report.Control{
		ID:    DeletePod,
		Human: "Delete",
		Icon:  "fa-trash-o",
		Rank:  1,
	})
	for _, service := range services {
		selectors[service.ID()] = service.Selector()
	}

	thisNodeName, err := GetNodeName(r)
	if err != nil {
		return pods, err
	}
	err = r.client.WalkPods(func(p Pod) error {
		if p.NodeName() != thisNodeName {
			return nil
		}
		for serviceID, selector := range selectors {
			if selector.Matches(p.Labels()) {
				p.AddServiceID(serviceID)
			}
		}
		pods = pods.AddNode(p.GetNode(r.probeID))
		return nil
	})
	return pods, err
}
<|endoftext|>


<commit_before>package browse

import (
	"net/http"
	"text/template"

	"github.com/hacdias/caddy-hugo/tools/templates"
	"github.com/hacdias/caddy-hugo/tools/variables"
	"github.com/mholt/caddy/middleware"
	"github.com/mholt/caddy/middleware/browse"
)

// GET handles the GET method on browse page and shows the files listing Using
// the Browse Caddy middleware.
func GET(w http.ResponseWriter, r *http.Request) (int, error) {
	functions := template.FuncMap{
		"CanBeEdited": templates.CanBeEdited,
		"Defined":     variables.Defined,
	}

	tpl, err := templates.Get(r, functions, "browse")

	if err != nil {
		return http.StatusInternalServerError, err
	}

	// Using Caddy's Browse middleware
	b := browse.Browse{
		Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
			return 404, nil
		}),
		Root: conf.Path,
		Configs: []browse.Config{
			{
				PathScope: "/",
				Variables: conf,
				Template:  tpl,
			},
		},
		IgnoreIndexes: true,
	}

	return b.ServeHTTP(w, r)
}
<commit_msg>fix a part of #67<commit_after>package browse

import (
	"net/http"
	"text/template"

	"github.com/hacdias/caddy-hugo/tools/templates"
	"github.com/hacdias/caddy-hugo/tools/variables"
	"github.com/mholt/caddy/middleware"
	"github.com/mholt/caddy/middleware/browse"
)

// GET handles the GET method on browse page and shows the files listing Using
// the Browse Caddy middleware.
func GET(w http.ResponseWriter, r *http.Request) (int, error) {
	functions := template.FuncMap{
		"CanBeEdited": templates.CanBeEdited,
		"Defined":     variables.Defined,
	}

	tpl, err := templates.Get(r, functions, "browse")

	if err != nil {
		return http.StatusInternalServerError, err
	}

	// Using Caddy's Browse middleware
	b := browse.Browse{
		Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
			return 404, nil
		}),
		Configs: []browse.Config{
			{
				PathScope: "/",
				Root: conf.Path,
				Variables: conf,
				Template:  tpl,
			},
		},
		IgnoreIndexes: true,
	}

	return b.ServeHTTP(w, r)
}
<|endoftext|>


<commit_before>package routing

import (
	"fmt"
	"sync"

	"github.com/go-errors/errors"
	"github.com/lightningnetwork/lnd/channeldb"
	"github.com/lightningnetwork/lnd/htlcswitch"
	"github.com/lightningnetwork/lnd/lntypes"
	"github.com/lightningnetwork/lnd/lnwire"
	"github.com/lightningnetwork/lnd/routing/route"
	"github.com/lightningnetwork/lnd/zpay32"
)

type mockPaymentAttemptDispatcher struct {
	onPayment func(firstHop lnwire.ShortChannelID) ([32]byte, error)
	results   map[uint64]*htlcswitch.PaymentResult
}

var _ PaymentAttemptDispatcher = (*mockPaymentAttemptDispatcher)(nil)

func (m *mockPaymentAttemptDispatcher) SendHTLC(firstHop lnwire.ShortChannelID,
	pid uint64,
	_ *lnwire.UpdateAddHTLC) error {

	if m.onPayment == nil {
		return nil
	}

	if m.results == nil {
		m.results = make(map[uint64]*htlcswitch.PaymentResult)
	}

	var result *htlcswitch.PaymentResult
	preimage, err := m.onPayment(firstHop)
	if err != nil {
		fwdErr, ok := err.(*htlcswitch.ForwardingError)
		if !ok {
			return err
		}
		result = &htlcswitch.PaymentResult{
			Error: fwdErr,
		}
	} else {
		result = &htlcswitch.PaymentResult{Preimage: preimage}
	}

	m.results[pid] = result

	return nil
}

func (m *mockPaymentAttemptDispatcher) GetPaymentResult(paymentID uint64,
	_ lntypes.Hash, _ htlcswitch.ErrorDecrypter) (
	<-chan *htlcswitch.PaymentResult, error) {

	c := make(chan *htlcswitch.PaymentResult, 1)
	res, ok := m.results[paymentID]
	if !ok {
		return nil, htlcswitch.ErrPaymentIDNotFound
	}
	c <- res

	return c, nil

}

func (m *mockPaymentAttemptDispatcher) setPaymentResult(
	f func(firstHop lnwire.ShortChannelID) ([32]byte, error)) {

	m.onPayment = f
}

type mockPaymentSessionSource struct {
	routes []*route.Route
}

var _ PaymentSessionSource = (*mockPaymentSessionSource)(nil)

func (m *mockPaymentSessionSource) NewPaymentSession(routeHints [][]zpay32.HopHint,
	target route.Vertex) (PaymentSession, error) {

	return &mockPaymentSession{m.routes}, nil
}

func (m *mockPaymentSessionSource) NewPaymentSessionForRoute(
	preBuiltRoute *route.Route) PaymentSession {
	return nil
}

func (m *mockPaymentSessionSource) NewPaymentSessionEmpty() PaymentSession {
	return &mockPaymentSession{}
}

type mockMissionControl struct {
}

var _ MissionController = (*mockMissionControl)(nil)

func (m *mockMissionControl) ReportPaymentFail(paymentID uint64,
	rt *route.Route, failureSourceIdx *int, failure lnwire.FailureMessage) (
	bool, channeldb.FailureReason, error) {

	return false, 0, nil
}

func (m *mockMissionControl) ReportEdgeFailure(failedEdge edge,
	minPenalizeAmt lnwire.MilliSatoshi) {
}

func (m *mockMissionControl) ReportEdgePolicyFailure(failedEdge edge) {}

func (m *mockMissionControl) ReportVertexFailure(v route.Vertex) {}

func (m *mockMissionControl) GetEdgeProbability(fromNode route.Vertex, edge EdgeLocator,
	amt lnwire.MilliSatoshi) float64 {

	return 0
}

type mockPaymentSession struct {
	routes []*route.Route
}

var _ PaymentSession = (*mockPaymentSession)(nil)

func (m *mockPaymentSession) RequestRoute(payment *LightningPayment,
	height uint32, finalCltvDelta uint16) (*route.Route, error) {

	if len(m.routes) == 0 {
		return nil, fmt.Errorf("no routes")
	}

	r := m.routes[0]
	m.routes = m.routes[1:]

	return r, nil
}

func (m *mockPaymentSession) ReportVertexFailure(v route.Vertex) {}

func (m *mockPaymentSession) ReportEdgeFailure(failedEdge edge, minPenalizeAmt lnwire.MilliSatoshi) {}

func (m *mockPaymentSession) ReportEdgePolicyFailure(failedEdge edge) {}

type mockPayer struct {
	sendResult       chan error
	paymentResultErr chan error
	paymentResult    chan *htlcswitch.PaymentResult
	quit             chan struct{}
}

var _ PaymentAttemptDispatcher = (*mockPayer)(nil)

func (m *mockPayer) SendHTLC(_ lnwire.ShortChannelID,
	paymentID uint64,
	_ *lnwire.UpdateAddHTLC) error {

	select {
	case res := <-m.sendResult:
		return res
	case <-m.quit:
		return fmt.Errorf("test quitting")
	}

}

func (m *mockPayer) GetPaymentResult(paymentID uint64, _ lntypes.Hash,
	_ htlcswitch.ErrorDecrypter) (<-chan *htlcswitch.PaymentResult, error) {

	select {
	case res := <-m.paymentResult:
		resChan := make(chan *htlcswitch.PaymentResult, 1)
		resChan <- res
		return resChan, nil
	case err := <-m.paymentResultErr:
		return nil, err
	case <-m.quit:
		return nil, fmt.Errorf("test quitting")
	}
}

type initArgs struct {
	c *channeldb.PaymentCreationInfo
}

type registerArgs struct {
	a *channeldb.PaymentAttemptInfo
}

type successArgs struct {
	preimg lntypes.Preimage
}

type failArgs struct {
	reason channeldb.FailureReason
}

type mockControlTower struct {
	inflights  map[lntypes.Hash]channeldb.InFlightPayment
	successful map[lntypes.Hash]struct{}

	init          chan initArgs
	register      chan registerArgs
	success       chan successArgs
	fail          chan failArgs
	fetchInFlight chan struct{}

	sync.Mutex
}

var _ ControlTower = (*mockControlTower)(nil)

func makeMockControlTower() *mockControlTower {
	return &mockControlTower{
		inflights:  make(map[lntypes.Hash]channeldb.InFlightPayment),
		successful: make(map[lntypes.Hash]struct{}),
	}
}

func (m *mockControlTower) InitPayment(phash lntypes.Hash,
	c *channeldb.PaymentCreationInfo) error {

	m.Lock()
	defer m.Unlock()

	if m.init != nil {
		m.init <- initArgs{c}
	}

	if _, ok := m.successful[phash]; ok {
		return fmt.Errorf("already successful")
	}

	_, ok := m.inflights[phash]
	if ok {
		return fmt.Errorf("in flight")
	}

	m.inflights[phash] = channeldb.InFlightPayment{
		Info: c,
	}

	return nil
}

func (m *mockControlTower) RegisterAttempt(phash lntypes.Hash,
	a *channeldb.PaymentAttemptInfo) error {

	m.Lock()
	defer m.Unlock()

	if m.register != nil {
		m.register <- registerArgs{a}
	}

	p, ok := m.inflights[phash]
	if !ok {
		return fmt.Errorf("not in flight")
	}

	p.Attempt = a
	m.inflights[phash] = p

	return nil
}

func (m *mockControlTower) Success(phash lntypes.Hash,
	preimg lntypes.Preimage) error {

	m.Lock()
	defer m.Unlock()

	if m.success != nil {
		m.success <- successArgs{preimg}
	}

	delete(m.inflights, phash)
	m.successful[phash] = struct{}{}
	return nil
}

func (m *mockControlTower) Fail(phash lntypes.Hash,
	reason channeldb.FailureReason) error {

	m.Lock()
	defer m.Unlock()

	if m.fail != nil {
		m.fail <- failArgs{reason}
	}

	delete(m.inflights, phash)
	return nil
}

func (m *mockControlTower) FetchInFlightPayments() (
	[]*channeldb.InFlightPayment, error) {

	m.Lock()
	defer m.Unlock()

	if m.fetchInFlight != nil {
		m.fetchInFlight <- struct{}{}
	}

	var fl []*channeldb.InFlightPayment
	for _, ifl := range m.inflights {
		fl = append(fl, &ifl)
	}

	return fl, nil
}

func (m *mockControlTower) SubscribePayment(paymentHash lntypes.Hash) (
	bool, chan PaymentResult, error) {

	return false, nil, errors.New("not implemented")
}
<commit_msg>routing/test: remove unused methods from mock<commit_after>package routing

import (
	"fmt"
	"sync"

	"github.com/go-errors/errors"
	"github.com/lightningnetwork/lnd/channeldb"
	"github.com/lightningnetwork/lnd/htlcswitch"
	"github.com/lightningnetwork/lnd/lntypes"
	"github.com/lightningnetwork/lnd/lnwire"
	"github.com/lightningnetwork/lnd/routing/route"
	"github.com/lightningnetwork/lnd/zpay32"
)

type mockPaymentAttemptDispatcher struct {
	onPayment func(firstHop lnwire.ShortChannelID) ([32]byte, error)
	results   map[uint64]*htlcswitch.PaymentResult
}

var _ PaymentAttemptDispatcher = (*mockPaymentAttemptDispatcher)(nil)

func (m *mockPaymentAttemptDispatcher) SendHTLC(firstHop lnwire.ShortChannelID,
	pid uint64,
	_ *lnwire.UpdateAddHTLC) error {

	if m.onPayment == nil {
		return nil
	}

	if m.results == nil {
		m.results = make(map[uint64]*htlcswitch.PaymentResult)
	}

	var result *htlcswitch.PaymentResult
	preimage, err := m.onPayment(firstHop)
	if err != nil {
		fwdErr, ok := err.(*htlcswitch.ForwardingError)
		if !ok {
			return err
		}
		result = &htlcswitch.PaymentResult{
			Error: fwdErr,
		}
	} else {
		result = &htlcswitch.PaymentResult{Preimage: preimage}
	}

	m.results[pid] = result

	return nil
}

func (m *mockPaymentAttemptDispatcher) GetPaymentResult(paymentID uint64,
	_ lntypes.Hash, _ htlcswitch.ErrorDecrypter) (
	<-chan *htlcswitch.PaymentResult, error) {

	c := make(chan *htlcswitch.PaymentResult, 1)
	res, ok := m.results[paymentID]
	if !ok {
		return nil, htlcswitch.ErrPaymentIDNotFound
	}
	c <- res

	return c, nil

}

func (m *mockPaymentAttemptDispatcher) setPaymentResult(
	f func(firstHop lnwire.ShortChannelID) ([32]byte, error)) {

	m.onPayment = f
}

type mockPaymentSessionSource struct {
	routes []*route.Route
}

var _ PaymentSessionSource = (*mockPaymentSessionSource)(nil)

func (m *mockPaymentSessionSource) NewPaymentSession(routeHints [][]zpay32.HopHint,
	target route.Vertex) (PaymentSession, error) {

	return &mockPaymentSession{m.routes}, nil
}

func (m *mockPaymentSessionSource) NewPaymentSessionForRoute(
	preBuiltRoute *route.Route) PaymentSession {
	return nil
}

func (m *mockPaymentSessionSource) NewPaymentSessionEmpty() PaymentSession {
	return &mockPaymentSession{}
}

type mockMissionControl struct {
}

var _ MissionController = (*mockMissionControl)(nil)

func (m *mockMissionControl) ReportPaymentFail(paymentID uint64,
	rt *route.Route, failureSourceIdx *int, failure lnwire.FailureMessage) (
	bool, channeldb.FailureReason, error) {

	return false, 0, nil
}

func (m *mockMissionControl) GetEdgeProbability(fromNode route.Vertex, edge EdgeLocator,
	amt lnwire.MilliSatoshi) float64 {

	return 0
}

type mockPaymentSession struct {
	routes []*route.Route
}

var _ PaymentSession = (*mockPaymentSession)(nil)

func (m *mockPaymentSession) RequestRoute(payment *LightningPayment,
	height uint32, finalCltvDelta uint16) (*route.Route, error) {

	if len(m.routes) == 0 {
		return nil, fmt.Errorf("no routes")
	}

	r := m.routes[0]
	m.routes = m.routes[1:]

	return r, nil
}

func (m *mockPaymentSession) ReportVertexFailure(v route.Vertex) {}

func (m *mockPaymentSession) ReportEdgeFailure(failedEdge edge, minPenalizeAmt lnwire.MilliSatoshi) {}

func (m *mockPaymentSession) ReportEdgePolicyFailure(failedEdge edge) {}

type mockPayer struct {
	sendResult       chan error
	paymentResultErr chan error
	paymentResult    chan *htlcswitch.PaymentResult
	quit             chan struct{}
}

var _ PaymentAttemptDispatcher = (*mockPayer)(nil)

func (m *mockPayer) SendHTLC(_ lnwire.ShortChannelID,
	paymentID uint64,
	_ *lnwire.UpdateAddHTLC) error {

	select {
	case res := <-m.sendResult:
		return res
	case <-m.quit:
		return fmt.Errorf("test quitting")
	}

}

func (m *mockPayer) GetPaymentResult(paymentID uint64, _ lntypes.Hash,
	_ htlcswitch.ErrorDecrypter) (<-chan *htlcswitch.PaymentResult, error) {

	select {
	case res := <-m.paymentResult:
		resChan := make(chan *htlcswitch.PaymentResult, 1)
		resChan <- res
		return resChan, nil
	case err := <-m.paymentResultErr:
		return nil, err
	case <-m.quit:
		return nil, fmt.Errorf("test quitting")
	}
}

type initArgs struct {
	c *channeldb.PaymentCreationInfo
}

type registerArgs struct {
	a *channeldb.PaymentAttemptInfo
}

type successArgs struct {
	preimg lntypes.Preimage
}

type failArgs struct {
	reason channeldb.FailureReason
}

type mockControlTower struct {
	inflights  map[lntypes.Hash]channeldb.InFlightPayment
	successful map[lntypes.Hash]struct{}

	init          chan initArgs
	register      chan registerArgs
	success       chan successArgs
	fail          chan failArgs
	fetchInFlight chan struct{}

	sync.Mutex
}

var _ ControlTower = (*mockControlTower)(nil)

func makeMockControlTower() *mockControlTower {
	return &mockControlTower{
		inflights:  make(map[lntypes.Hash]channeldb.InFlightPayment),
		successful: make(map[lntypes.Hash]struct{}),
	}
}

func (m *mockControlTower) InitPayment(phash lntypes.Hash,
	c *channeldb.PaymentCreationInfo) error {

	m.Lock()
	defer m.Unlock()

	if m.init != nil {
		m.init <- initArgs{c}
	}

	if _, ok := m.successful[phash]; ok {
		return fmt.Errorf("already successful")
	}

	_, ok := m.inflights[phash]
	if ok {
		return fmt.Errorf("in flight")
	}

	m.inflights[phash] = channeldb.InFlightPayment{
		Info: c,
	}

	return nil
}

func (m *mockControlTower) RegisterAttempt(phash lntypes.Hash,
	a *channeldb.PaymentAttemptInfo) error {

	m.Lock()
	defer m.Unlock()

	if m.register != nil {
		m.register <- registerArgs{a}
	}

	p, ok := m.inflights[phash]
	if !ok {
		return fmt.Errorf("not in flight")
	}

	p.Attempt = a
	m.inflights[phash] = p

	return nil
}

func (m *mockControlTower) Success(phash lntypes.Hash,
	preimg lntypes.Preimage) error {

	m.Lock()
	defer m.Unlock()

	if m.success != nil {
		m.success <- successArgs{preimg}
	}

	delete(m.inflights, phash)
	m.successful[phash] = struct{}{}
	return nil
}

func (m *mockControlTower) Fail(phash lntypes.Hash,
	reason channeldb.FailureReason) error {

	m.Lock()
	defer m.Unlock()

	if m.fail != nil {
		m.fail <- failArgs{reason}
	}

	delete(m.inflights, phash)
	return nil
}

func (m *mockControlTower) FetchInFlightPayments() (
	[]*channeldb.InFlightPayment, error) {

	m.Lock()
	defer m.Unlock()

	if m.fetchInFlight != nil {
		m.fetchInFlight <- struct{}{}
	}

	var fl []*channeldb.InFlightPayment
	for _, ifl := range m.inflights {
		fl = append(fl, &ifl)
	}

	return fl, nil
}

func (m *mockControlTower) SubscribePayment(paymentHash lntypes.Hash) (
	bool, chan PaymentResult, error) {

	return false, nil, errors.New("not implemented")
}
<|endoftext|>


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

package genroot

import (
	"fmt"
	"go/format"
	"io"
	"io/ioutil"
	"log"
	"os"
)

func GoFmt(f *os.File) {
	fname := f.Name()
	src, err := ioutil.ReadFile(fname)
	if err != nil {
		log.Fatal(err)
	}
	src, err = format.Source(src)
	if err != nil {
		log.Fatalf("error formating sources of %q: %v\n", fname, err)
	}

	err = ioutil.WriteFile(fname, src, 0644)
	if err != nil {
		log.Fatalf("error writing back %q: %v\n", fname, err)
	}
}

func GenImports(pkg string, w io.Writer, imports ...string) {
	fmt.Fprintf(w, srcHeader, pkg)
	if len(imports) == 0 {
		return
	}

	fmt.Fprintf(w, "import (\n")
	for _, imp := range imports {
		if imp == "" {
			fmt.Fprintf(w, "\n")
			continue
		}
		fmt.Fprintf(w, "\t%q\n", imp)
	}
	fmt.Fprintf(w, ")\n\n")
}

const srcHeader = `// Copyright 2018 The go-hep Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Automatically generated. DO NOT EDIT.

package %s

`
<commit_msg>groot: 2019 is the year of the gopher<commit_after>// Copyright 2018 The go-hep Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package genroot

import (
	"fmt"
	"go/format"
	"io"
	"io/ioutil"
	"log"
	"os"
)

func GoFmt(f *os.File) {
	fname := f.Name()
	src, err := ioutil.ReadFile(fname)
	if err != nil {
		log.Fatal(err)
	}
	src, err = format.Source(src)
	if err != nil {
		log.Fatalf("error formating sources of %q: %v\n", fname, err)
	}

	err = ioutil.WriteFile(fname, src, 0644)
	if err != nil {
		log.Fatalf("error writing back %q: %v\n", fname, err)
	}
}

func GenImports(pkg string, w io.Writer, imports ...string) {
	fmt.Fprintf(w, srcHeader, pkg)
	if len(imports) == 0 {
		return
	}

	fmt.Fprintf(w, "import (\n")
	for _, imp := range imports {
		if imp == "" {
			fmt.Fprintf(w, "\n")
			continue
		}
		fmt.Fprintf(w, "\t%q\n", imp)
	}
	fmt.Fprintf(w, ")\n\n")
}

const srcHeader = `// Copyright 2019 The go-hep Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Automatically generated. DO NOT EDIT.

package %s

`
<|endoftext|>