<commit_before>package server

import (
	"path"
	"sync"

	"github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/pkg/shard"
	ppsclient "github.com/pachyderm/pachyderm/src/client/pps"
	col "github.com/pachyderm/pachyderm/src/server/pkg/collection"
	"github.com/pachyderm/pachyderm/src/server/pkg/metrics"
	ppsserver "github.com/pachyderm/pachyderm/src/server/pps"

	etcd "github.com/coreos/etcd/clientv3"
	"go.pedge.io/proto/rpclog"
	"golang.org/x/net/context"
	kube "k8s.io/kubernetes/pkg/client/unversioned"
)

// APIServer represents an api server.
type APIServer interface {
	ppsclient.APIServer
	shard.Frontend
	shard.Server
}

const (
	pipelinesPrefix = "/pipelines"
	jobsPrefix      = "/jobs"
)

var (
	// Index mapping pipeline to jobs started by the pipeline
	jobsPipelineIndex = col.Index{"Pipeline", false}

	// Index mapping job inputs (repos + pipeline version) to output commit. This
	// is how we know if we need to start a job
	jobsInputIndex = col.Index{"Input", false}

	// Index of pipelines and jobs that have been stopped (state is "success" or
	// "failure" for jobs, or "stopped" or "failure" for pipelines). See
	// (Job|Pipeline)StateToStopped in s/s/pps/server/api_server.go
	stoppedIndex = col.Index{"Stopped", false}
)

// NewAPIServer creates an APIServer.
func NewAPIServer(
	etcdAddress string,
	etcdPrefix string,
	hasher *ppsserver.Hasher,
	address string,
	kubeClient *kube.Client,
	namespace string,
	workerImage string,
	workerImagePullPolicy string,
	reporter *metrics.Reporter,
) (APIServer, error) {
	etcdClient, err := etcd.New(etcd.Config{
		Endpoints:   []string{etcdAddress},
		DialOptions: client.EtcdDialOptions(),
	})
	if err != nil {
		return nil, err
	}

	apiServer := &apiServer{
		Logger:                protorpclog.NewLogger("pps.API"),
		etcdPrefix:            etcdPrefix,
		hasher:                hasher,
		address:               address,
		etcdClient:            etcdClient,
		pachConnOnce:          sync.Once{},
		kubeClient:            kubeClient,
		version:               shard.InvalidVersion,
		shardCtxs:             make(map[uint64]*ctxAndCancel),
		pipelineCancels:       make(map[string]context.CancelFunc),
		jobCancels:            make(map[string]context.CancelFunc),
		namespace:             namespace,
		workerImage:           workerImage,
		workerImagePullPolicy: workerImagePullPolicy,
		reporter:              reporter,
		pipelines: col.NewCollection(
			etcdClient,
			path.Join(etcdPrefix, pipelinesPrefix),
			[]col.Index{stoppedIndex},
			&ppsclient.PipelineInfo{},
		),
		jobs: col.NewCollection(
			etcdClient,
			path.Join(etcdPrefix, jobsPrefix),
			[]col.Index{jobsPipelineIndex, stoppedIndex, jobsInputIndex},
			&ppsclient.JobInfo{},
		),
	}
	return apiServer, nil
}
<commit_msg>Adds back in 1.4.5 input index.<commit_after>package server

import (
	"path"
	"sync"

	"github.com/pachyderm/pachyderm/src/client"
	"github.com/pachyderm/pachyderm/src/client/pkg/shard"
	ppsclient "github.com/pachyderm/pachyderm/src/client/pps"
	col "github.com/pachyderm/pachyderm/src/server/pkg/collection"
	"github.com/pachyderm/pachyderm/src/server/pkg/metrics"
	ppsserver "github.com/pachyderm/pachyderm/src/server/pps"

	etcd "github.com/coreos/etcd/clientv3"
	"go.pedge.io/proto/rpclog"
	"golang.org/x/net/context"
	kube "k8s.io/kubernetes/pkg/client/unversioned"
)

// APIServer represents an api server.
type APIServer interface {
	ppsclient.APIServer
	shard.Frontend
	shard.Server
}

const (
	pipelinesPrefix = "/pipelines"
	jobsPrefix      = "/jobs"
)

var (
	// Index mapping pipeline to jobs started by the pipeline
	jobsPipelineIndex = col.Index{"Pipeline", false}

	// Index mapping job inputs (repos + pipeline version) to output commit. This
	// is how we know if we need to start a job
	jobsInputIndex = col.Index{"Input", false}

	// Index mapping 1.4.5 and earlier style job inputs (repos + pipeline
	// version) to output commit. This is how we know if we need to start a job
	// Needed for legacy compatibility.
	jobsInputsIndex = col.Index{"Inputs", false}

	// Index of pipelines and jobs that have been stopped (state is "success" or
	// "failure" for jobs, or "stopped" or "failure" for pipelines). See
	// (Job|Pipeline)StateToStopped in s/s/pps/server/api_server.go
	stoppedIndex = col.Index{"Stopped", false}
)

// NewAPIServer creates an APIServer.
func NewAPIServer(
	etcdAddress string,
	etcdPrefix string,
	hasher *ppsserver.Hasher,
	address string,
	kubeClient *kube.Client,
	namespace string,
	workerImage string,
	workerImagePullPolicy string,
	reporter *metrics.Reporter,
) (APIServer, error) {
	etcdClient, err := etcd.New(etcd.Config{
		Endpoints:   []string{etcdAddress},
		DialOptions: client.EtcdDialOptions(),
	})
	if err != nil {
		return nil, err
	}

	apiServer := &apiServer{
		Logger:                protorpclog.NewLogger("pps.API"),
		etcdPrefix:            etcdPrefix,
		hasher:                hasher,
		address:               address,
		etcdClient:            etcdClient,
		pachConnOnce:          sync.Once{},
		kubeClient:            kubeClient,
		version:               shard.InvalidVersion,
		shardCtxs:             make(map[uint64]*ctxAndCancel),
		pipelineCancels:       make(map[string]context.CancelFunc),
		jobCancels:            make(map[string]context.CancelFunc),
		namespace:             namespace,
		workerImage:           workerImage,
		workerImagePullPolicy: workerImagePullPolicy,
		reporter:              reporter,
		pipelines: col.NewCollection(
			etcdClient,
			path.Join(etcdPrefix, pipelinesPrefix),
			[]col.Index{stoppedIndex},
			&ppsclient.PipelineInfo{},
		),
		jobs: col.NewCollection(
			etcdClient,
			path.Join(etcdPrefix, jobsPrefix),
			[]col.Index{jobsPipelineIndex, stoppedIndex, jobsInputIndex},
			&ppsclient.JobInfo{},
		),
	}
	return apiServer, nil
}
<|endoftext|>


<commit_before>/*
 Copyright 2016 Padduck, LLC

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

 	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 main

import (
	"flag"
	"io/ioutil"
	"os"
	"path/filepath"

	"fmt"

	"net/http"
	"strings"

	"github.com/braintree/manners"
	"github.com/gin-gonic/gin"
	"github.com/pufferpanel/apufferi/config"
	"github.com/pufferpanel/apufferi/logging"
	"github.com/pufferpanel/pufferd/data"
	"github.com/pufferpanel/pufferd/data/templates"
	"github.com/pufferpanel/pufferd/install"
	"github.com/pufferpanel/pufferd/migration"
	"github.com/pufferpanel/pufferd/programs"
	"github.com/pufferpanel/pufferd/routing"
	"github.com/pufferpanel/pufferd/sftp"
	"github.com/pufferpanel/pufferd/shutdown"
	"github.com/pufferpanel/pufferd/uninstaller"
)

var (
	VERSION      = "nightly"
	MAJORVERSION = "nightly"
	BUILDDATE    = "unknown"
	GITHASH      = "unknown"
)

func main() {
	var loggingLevel string
	var authRoot string
	var authToken string
	var runInstaller bool
	var version bool
	var license bool
	var regenerate bool
	var migrate bool
	var uninstall bool
	var configPath string
	var pid int
	var installService bool
	flag.StringVar(&loggingLevel, "logging", "INFO", "Lowest logging level to display")
	flag.StringVar(&authRoot, "auth", "", "Base URL to the authorization server")
	flag.StringVar(&authToken, "token", "", "Authorization token")
	flag.BoolVar(&runInstaller, "install", false, "If installing instead of running")
	flag.BoolVar(&version, "version", false, "Get the version")
	flag.BoolVar(&license, "license", false, "View license")
	flag.BoolVar(&regenerate, "regenerate", false, "Regenerate pufferd templates")
	flag.BoolVar(&migrate, "migrate", false, "Migrate Scales data to pufferd")
	flag.BoolVar(&uninstall, "uninstall", false, "Uninstall pufferd")
	flag.StringVar(&configPath, "config", "config.json", "Path to pufferd config.json")
	flag.IntVar(&pid, "shutdown", 0, "PID to shut down")
	flag.BoolVar(&installService, "installService", false, "Installs the pufferd service file")
	flag.Parse()

	versionString := fmt.Sprintf("pufferd %s (%s %s)", VERSION, BUILDDATE, GITHASH)

	if pid != 0 {
		logging.Info("Shutting down")
		shutdown.Command(pid)
	}

	if _, err := os.Stat(configPath); os.IsNotExist(err) {
		if _, err := os.Stat("/etc/pufferd/config.json"); err == nil {
			logging.Info("No config passed, defaulting to /etc/pufferd/config.json")
			configPath = "/etc/pufferd/config.json"
		} else {
			logging.Error("Cannot find a config file!")
			logging.Warn("pufferd could be unstable")
		}
	}

	if uninstall {
		fmt.Println("This option will UNINSTALL pufferd, are you sure? Please enter \"yes\" to proceed [no]")
		var response string
		fmt.Scanln(&response)
		if strings.ToLower(response) == "yes" || strings.ToLower(response) == "y" {
			if os.Geteuid() != 0 {
				logging.Error("To uninstall pufferd you need to have sudo or root privileges")
			} else {
				config.Load(configPath)
				uninstaller.StartProcess()
				logging.Info("pufferd is now uninstalled.")
			}
		} else {
			logging.Info("Uninstall process aborted")
			logging.Info("Exiting")
		}
		return
	}

	if version {
		os.Stdout.WriteString(versionString + "\r\n")
	}

	if license {
		os.Stdout.WriteString(data.LICENSE + "\r\n")
	}

	if regenerate {
		config.Load(configPath)
		programs.Initialize()

		if _, err := os.Stat(programs.TemplateFolder); os.IsNotExist(err) {
			logging.Info("No template directory found, creating")
			err = os.MkdirAll(programs.TemplateFolder, 0755)
			if err != nil {
				logging.Error("Error creating template folder", err)
			}
		}
		// Overwrite existing templates
		templates.CopyTemplates()
		logging.Info("Templates regenerated")
	}

	if migrate {
		config.Load(configPath)
		migration.MigrateFromScales()
	}

	if installService {
		install.InstallService()
	}

	if license || version || regenerate || migrate || pid != 0 {
		return
	}

	config.Load(configPath)

	logging.SetLevelByString(loggingLevel)
	logging.Init()
	gin.SetMode(gin.ReleaseMode)

	logging.Info(versionString)
	logging.Info("Logging set to " + loggingLevel)

	if runInstaller {
		install.Install(configPath, authRoot, authToken)
	}

	if runInstaller || installService {
		return
	}

	programs.Initialize()

	if _, err := os.Stat(programs.TemplateFolder); os.IsNotExist(err) {
		logging.Info("No template directory found, creating")
		err = os.MkdirAll(programs.TemplateFolder, 0755)
		if err != nil {
			logging.Error("Error creating template folder", err)
		}

	}
	if files, _ := ioutil.ReadDir(programs.TemplateFolder); len(files) == 0 {
		logging.Info("Templates being copied to " + programs.TemplateFolder)
		templates.CopyTemplates()
	}

	if _, err := os.Stat(programs.ServerFolder); os.IsNotExist(err) {
		logging.Info("No server directory found, creating")
		os.MkdirAll(programs.ServerFolder, 0755)
	}

	programs.LoadFromFolder()

	for _, element := range programs.GetAll() {
		if element.IsEnabled() && element.IsAutoStart() {
			logging.Info("Starting server " + element.Id())
			element.Start()
		}
	}

	r := routing.ConfigureWeb()

	var useHttps bool
	useHttps = false

	dataFolder := config.GetOrDefault("datafolder", "data")
	httpsPem := filepath.Join(dataFolder, "https.pem")
	httpsKey := filepath.Join(dataFolder, "https.key")

	if _, err := os.Stat(httpsPem); os.IsNotExist(err) {
		logging.Warn("No HTTPS.PEM found in data folder, will use http instead")
	} else if _, err := os.Stat(httpsKey); os.IsNotExist(err) {
		logging.Warn("No HTTPS.KEY found in data folder, will use http instead")
	} else {
		useHttps = true
	}

	sftp.Run()

	//check if there's an update
	if config.GetOrDefault("update-check", "true") == "true" {
		go func() {
			url := "https://dl.pufferpanel.com/pufferd/" + MAJORVERSION + "/version.txt"
			logging.Debug("Checking for updates using " + url)
			resp, err := http.Get(url)
			if err != nil {
				return
			}
			defer resp.Body.Close()
			onlineVersion, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				return
			}
			if string(onlineVersion) != GITHASH {
				logging.Infof("DL server reports a different hash than this version, an update may be available")
				logging.Infof("Installed: %s", GITHASH)
				logging.Infof("Online: %s", onlineVersion)
			}
		}()
	}

	web := config.GetOrDefault("web", config.GetOrDefault("webhost", "0.0.0.0")+":"+config.GetOrDefault("webport", "5656"))

	shutdown.CreateHook()

	logging.Infof("Starting web access on %s", web)
	var err error
	if useHttps {
		err = manners.ListenAndServeTLS(web, httpsPem, httpsKey, r)
	} else {
		err = manners.ListenAndServe(web, r)
	}
	if err != nil {
		logging.Error("Error starting web service", err)
	}
	shutdown.Shutdown()
}
<commit_msg>Remove date from version string With new build server on the way, printing the date has no real value. We cannot remove the variable though until we have changed build servers.<commit_after>/*
 Copyright 2016 Padduck, LLC

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

 	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 main

import (
	"flag"
	"io/ioutil"
	"os"
	"path/filepath"

	"fmt"

	"net/http"
	"strings"

	"github.com/braintree/manners"
	"github.com/gin-gonic/gin"
	"github.com/pufferpanel/apufferi/config"
	"github.com/pufferpanel/apufferi/logging"
	"github.com/pufferpanel/pufferd/data"
	"github.com/pufferpanel/pufferd/data/templates"
	"github.com/pufferpanel/pufferd/install"
	"github.com/pufferpanel/pufferd/migration"
	"github.com/pufferpanel/pufferd/programs"
	"github.com/pufferpanel/pufferd/routing"
	"github.com/pufferpanel/pufferd/sftp"
	"github.com/pufferpanel/pufferd/shutdown"
	"github.com/pufferpanel/pufferd/uninstaller"
)

var (
	VERSION      = "nightly"
	MAJORVERSION = "nightly"
	BUILDDATE    = "unknown"
	GITHASH      = "unknown"
)

func main() {
	var loggingLevel string
	var authRoot string
	var authToken string
	var runInstaller bool
	var version bool
	var license bool
	var regenerate bool
	var migrate bool
	var uninstall bool
	var configPath string
	var pid int
	var installService bool
	flag.StringVar(&loggingLevel, "logging", "INFO", "Lowest logging level to display")
	flag.StringVar(&authRoot, "auth", "", "Base URL to the authorization server")
	flag.StringVar(&authToken, "token", "", "Authorization token")
	flag.BoolVar(&runInstaller, "install", false, "If installing instead of running")
	flag.BoolVar(&version, "version", false, "Get the version")
	flag.BoolVar(&license, "license", false, "View license")
	flag.BoolVar(&regenerate, "regenerate", false, "Regenerate pufferd templates")
	flag.BoolVar(&migrate, "migrate", false, "Migrate Scales data to pufferd")
	flag.BoolVar(&uninstall, "uninstall", false, "Uninstall pufferd")
	flag.StringVar(&configPath, "config", "config.json", "Path to pufferd config.json")
	flag.IntVar(&pid, "shutdown", 0, "PID to shut down")
	flag.BoolVar(&installService, "installService", false, "Installs the pufferd service file")
	flag.Parse()

	versionString := fmt.Sprintf("pufferd %s (%s)", VERSION, GITHASH)

	if pid != 0 {
		logging.Info("Shutting down")
		shutdown.Command(pid)
	}

	if _, err := os.Stat(configPath); os.IsNotExist(err) {
		if _, err := os.Stat("/etc/pufferd/config.json"); err == nil {
			logging.Info("No config passed, defaulting to /etc/pufferd/config.json")
			configPath = "/etc/pufferd/config.json"
		} else {
			logging.Error("Cannot find a config file!")
			logging.Warn("pufferd could be unstable")
		}
	}

	if uninstall {
		fmt.Println("This option will UNINSTALL pufferd, are you sure? Please enter \"yes\" to proceed [no]")
		var response string
		fmt.Scanln(&response)
		if strings.ToLower(response) == "yes" || strings.ToLower(response) == "y" {
			if os.Geteuid() != 0 {
				logging.Error("To uninstall pufferd you need to have sudo or root privileges")
			} else {
				config.Load(configPath)
				uninstaller.StartProcess()
				logging.Info("pufferd is now uninstalled.")
			}
		} else {
			logging.Info("Uninstall process aborted")
			logging.Info("Exiting")
		}
		return
	}

	if version {
		os.Stdout.WriteString(versionString + "\r\n")
	}

	if license {
		os.Stdout.WriteString(data.LICENSE + "\r\n")
	}

	if regenerate {
		config.Load(configPath)
		programs.Initialize()

		if _, err := os.Stat(programs.TemplateFolder); os.IsNotExist(err) {
			logging.Info("No template directory found, creating")
			err = os.MkdirAll(programs.TemplateFolder, 0755)
			if err != nil {
				logging.Error("Error creating template folder", err)
			}
		}
		// Overwrite existing templates
		templates.CopyTemplates()
		logging.Info("Templates regenerated")
	}

	if migrate {
		config.Load(configPath)
		migration.MigrateFromScales()
	}

	if installService {
		install.InstallService()
	}

	if license || version || regenerate || migrate || pid != 0 {
		return
	}

	config.Load(configPath)

	logging.SetLevelByString(loggingLevel)
	logging.Init()
	gin.SetMode(gin.ReleaseMode)

	logging.Info(versionString)
	logging.Info("Logging set to " + loggingLevel)

	if runInstaller {
		install.Install(configPath, authRoot, authToken)
	}

	if runInstaller || installService {
		return
	}

	programs.Initialize()

	if _, err := os.Stat(programs.TemplateFolder); os.IsNotExist(err) {
		logging.Info("No template directory found, creating")
		err = os.MkdirAll(programs.TemplateFolder, 0755)
		if err != nil {
			logging.Error("Error creating template folder", err)
		}

	}
	if files, _ := ioutil.ReadDir(programs.TemplateFolder); len(files) == 0 {
		logging.Info("Templates being copied to " + programs.TemplateFolder)
		templates.CopyTemplates()
	}

	if _, err := os.Stat(programs.ServerFolder); os.IsNotExist(err) {
		logging.Info("No server directory found, creating")
		os.MkdirAll(programs.ServerFolder, 0755)
	}

	programs.LoadFromFolder()

	for _, element := range programs.GetAll() {
		if element.IsEnabled() && element.IsAutoStart() {
			logging.Info("Starting server " + element.Id())
			element.Start()
		}
	}

	r := routing.ConfigureWeb()

	var useHttps bool
	useHttps = false

	dataFolder := config.GetOrDefault("datafolder", "data")
	httpsPem := filepath.Join(dataFolder, "https.pem")
	httpsKey := filepath.Join(dataFolder, "https.key")

	if _, err := os.Stat(httpsPem); os.IsNotExist(err) {
		logging.Warn("No HTTPS.PEM found in data folder, will use http instead")
	} else if _, err := os.Stat(httpsKey); os.IsNotExist(err) {
		logging.Warn("No HTTPS.KEY found in data folder, will use http instead")
	} else {
		useHttps = true
	}

	sftp.Run()

	//check if there's an update
	if config.GetOrDefault("update-check", "true") == "true" {
		go func() {
			url := "https://dl.pufferpanel.com/pufferd/" + MAJORVERSION + "/version.txt"
			logging.Debug("Checking for updates using " + url)
			resp, err := http.Get(url)
			if err != nil {
				return
			}
			defer resp.Body.Close()
			onlineVersion, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				return
			}
			if string(onlineVersion) != GITHASH {
				logging.Infof("DL server reports a different hash than this version, an update may be available")
				logging.Infof("Installed: %s", GITHASH)
				logging.Infof("Online: %s", onlineVersion)
			}
		}()
	}

	web := config.GetOrDefault("web", config.GetOrDefault("webhost", "0.0.0.0")+":"+config.GetOrDefault("webport", "5656"))

	shutdown.CreateHook()

	logging.Infof("Starting web access on %s", web)
	var err error
	if useHttps {
		err = manners.ListenAndServeTLS(web, httpsPem, httpsKey, r)
	} else {
		err = manners.ListenAndServe(web, r)
	}
	if err != nil {
		logging.Error("Error starting web service", err)
	}
	shutdown.Shutdown()
}
<|endoftext|>


<commit_before>package qparser

import (
    "net/url"
    "strings"
    "strconv"
)

// ListOptions specifies the optional parameters for requests with pagination support
type ListOptions struct {
    // Page of results to retrieve
    Page  int
    // Max number of results to retrieve on single page
    Limit int
}

// ExpandParams
type ExpandParams map[string]ListOptions

type Fields []string

type SearchValue struct {
    Value   string      `json:"value"`
    Keys    []string    `json:"keys"`
}

type QueryValues struct {
    Search *SearchValue         `json:"search"`
    Filter map[string][]string  `json:"filter"`
}

type ParseResult struct {
    Pagination  *ListOptions    `json:"pagination"`
    Expand      *ExpandParams   `json:"expand"`
    Fields      *Fields         `json:"fields"`
    Values      *QueryValues    `json:"values"`
}

type ParserOptions struct {
    LimitValue   int
    PageValue    int
    LimitString  string
    PageString   string
    ExpandString string
    FieldsString string
    QueryString  string
    ParamString  string
    LeftBracket  rune
    RightBracket rune
    Separator    rune
    KVSeparator  rune
}

type Parser struct {
    options *ParserOptions
}

const (
    DefaultLimitValue   int    = 25
    DefaultPageValue    int    = 1
    DefaultLimitString  string = "limit"
    DefaultPageString   string = "page"
    DefaultExpandString string = "expand"
    DefaultFieldsString string = "fields"
    DefaultQueryString  string = "q"
    DefaultParamString  string = "p"
    DefaultLeftBracket  rune   = '('
    DefaultRightBracket rune   = ')'
    DefaultSeparator    rune   = ','
    DefaultKVSeparator  rune   = ':'
)

func ifEmptyStringAssign(s *string, val string) {
    if *s == "" {
        *s = val
    }
}

func ifEmptyRuneAssign(s *rune, val rune) {
    if *s == 0 {
        *s = val
    }
}
func ifEmptyIntAssign(s *int, val int) {
    if *s == 0 {
        *s = val
    }
}

func NewParser(opts *ParserOptions) *Parser {
    if opts == nil {
        opts = &ParserOptions{}
    }

    ifEmptyIntAssign(&opts.LimitValue, DefaultLimitValue)
    ifEmptyIntAssign(&opts.PageValue, DefaultPageValue)
    ifEmptyStringAssign(&opts.LimitString, DefaultLimitString)
    ifEmptyStringAssign(&opts.PageString, DefaultPageString)
    ifEmptyStringAssign(&opts.ExpandString, DefaultExpandString)
    ifEmptyStringAssign(&opts.FieldsString, DefaultFieldsString)
    ifEmptyStringAssign(&opts.QueryString, DefaultQueryString)
    ifEmptyStringAssign(&opts.ParamString, DefaultParamString)
    ifEmptyRuneAssign(&opts.LeftBracket, DefaultLeftBracket)
    ifEmptyRuneAssign(&opts.RightBracket, DefaultRightBracket)
    ifEmptyRuneAssign(&opts.Separator, DefaultSeparator)
    ifEmptyRuneAssign(&opts.KVSeparator, DefaultKVSeparator)

    return &Parser{
        options: opts,
    }
}

func (e *ExpandParams) Get(key string) (*ListOptions) {
    if v, ok := (*e)[key]; ok {
        return &v
    }

    return nil
}

func (e *QueryValues) Get(key string) ([]string) {
    if v, ok := e.Filter[key]; ok {
        return v
    }

    return nil
}

func (qp *Parser) Parse(u *url.URL) (*ParseResult, error) {
    result := &ParseResult{
        Pagination:  &ListOptions{},
        Expand:      &ExpandParams{},
        Fields:      &Fields{},
        Values:      &QueryValues{
            Search: &SearchValue{},
        },
    }
    values := u.Query()
    err := result.Pagination.parse(values, qp.options)
    if err != nil {
        return nil, err
    }
    err = result.Expand.parse(values, qp.options)
    if err != nil {
        return nil, err
    }
    err = result.Values.parse(values, qp.options)
    if err != nil {
        return nil, err
    }
    err = result.Fields.parse(values, qp.options)
    if err != nil {
        return nil, err
    }
    return result, nil
}

func (qp *Parser) ParseString(rawurl string) (*ParseResult, error) {
    u, err := url.Parse(rawurl)
    if err != nil {
        return nil, err
    }
    return qp.Parse(u)
}

func (lo *ListOptions) parse(val url.Values, opts *ParserOptions) error {
    var err error
    if l := val.Get(opts.LimitString); l != "" {
        lo.Limit, err = strconv.Atoi(l)
        if err != nil {
            return err
        }
    } else {
        lo.Limit = opts.LimitValue
    }
    if p := val.Get(opts.PageString); p != "" {
        lo.Page, err = strconv.Atoi(p)
        if err != nil {
            return err
        }
    } else {
        lo.Page = opts.PageValue
    }
    return nil
}

func (ep *ExpandParams) parse(val url.Values, opts *ParserOptions) error {
    params := map[string][]string(val)
    expStr := make([]string, 0)
    for _, str := range params[opts.ExpandString] {
        open := false
        position := 0
        for i, char := range str {
            if char == opts.LeftBracket {
                open = true
            } else if char == opts.RightBracket {
                open = false
            } else if char == opts.Separator && !open {
                expStr = append(expStr, str[position:i])
                position = i
            }
            if i == (len(str) - 1) {
                if position > 0 {
                    position++
                }
                expStr = append(expStr, str[position:])
            }
        }
    }
    for _, char := range expStr {
        splitted := strings.FieldsFunc(char, func(r rune) bool {
            return r == opts.LeftBracket || r == opts.RightBracket || r == opts.Separator
        })
        bcp := ListOptions{
            Limit: opts.LimitValue,
            Page: opts.PageValue,
        }
        if len(splitted) > 1 {
            var err error
            params := strings.Split(splitted[1], string(opts.KVSeparator))
            if params[0] == opts.LimitString {
                bcp.Limit, err = strconv.Atoi(params[1])
            } else if params[0] == opts.PageString {
                bcp.Page, err = strconv.Atoi(params[1])
            }
            if err != nil {
                return err
            }
            if len(splitted) > 2 {
                params := strings.Split(splitted[2], string(opts.KVSeparator))
                if params[0] == opts.LimitString {
                    bcp.Limit, err = strconv.Atoi(params[1])
                } else if params[0] == opts.PageString {
                    bcp.Page, err = strconv.Atoi(params[1])
                }
                if err != nil {
                    return err
                }
            }
        }
        if *ep == nil {
            (*ep) = make(map[string]ListOptions)
        }
        (*ep)[splitted[0]] = bcp
    }
    return nil
}

func (qv *QueryValues) parse(val url.Values, opts *ParserOptions) error {
    params := map[string][]string(val)
    if v, ok := params[opts.QueryString]; ok {
        qv.Search.Value = v[0]
        for _, str := range params[opts.ParamString] {
            qv.Search.Keys = append(qv.Search.Keys, strings.Split(str, string(opts.Separator))...)
        }
    }
    qv.Filter = make(map[string][]string)
    for k, v := range params {
        if k != opts.LimitString && k != opts.PageString &&
        k != opts.ParamString && k != opts.QueryString &&
        k != opts.ExpandString && k != opts.FieldsString {
            for _, s := range v {
                qv.Filter[k] = append(qv.Filter[k], strings.Split(s, string(opts.Separator))...)
            }
        }
    }
    return nil
}

func (f *Fields) parse(val url.Values, opts *ParserOptions) error {
    params := map[string][]string(val)
    if _, ok := params[opts.FieldsString]; ok {
        for _, str := range params[opts.ParamString] {
            *f = append(*f, strings.Split(str, string(opts.Separator))...)
        }
    }
    return nil
}<commit_msg>hotfix: wrong field check<commit_after>package qparser

import (
    "net/url"
    "strings"
    "strconv"
)

// ListOptions specifies the optional parameters for requests with pagination support
type ListOptions struct {
    // Page of results to retrieve
    Page  int
    // Max number of results to retrieve on single page
    Limit int
}

// ExpandParams
type ExpandParams map[string]ListOptions

type Fields []string

type SearchValue struct {
    Value   string      `json:"value"`
    Keys    []string    `json:"keys"`
}

type QueryValues struct {
    Search *SearchValue         `json:"search"`
    Filter map[string][]string  `json:"filter"`
}

type ParseResult struct {
    Pagination  *ListOptions    `json:"pagination"`
    Expand      *ExpandParams   `json:"expand"`
    Fields      *Fields         `json:"fields"`
    Values      *QueryValues    `json:"values"`
}

type ParserOptions struct {
    LimitValue   int
    PageValue    int
    LimitString  string
    PageString   string
    ExpandString string
    FieldsString string
    QueryString  string
    ParamString  string
    LeftBracket  rune
    RightBracket rune
    Separator    rune
    KVSeparator  rune
}

type Parser struct {
    options *ParserOptions
}

const (
    DefaultLimitValue   int    = 25
    DefaultPageValue    int    = 1
    DefaultLimitString  string = "limit"
    DefaultPageString   string = "page"
    DefaultExpandString string = "expand"
    DefaultFieldsString string = "fields"
    DefaultQueryString  string = "q"
    DefaultParamString  string = "p"
    DefaultLeftBracket  rune   = '('
    DefaultRightBracket rune   = ')'
    DefaultSeparator    rune   = ','
    DefaultKVSeparator  rune   = ':'
)

func ifEmptyStringAssign(s *string, val string) {
    if *s == "" {
        *s = val
    }
}

func ifEmptyRuneAssign(s *rune, val rune) {
    if *s == 0 {
        *s = val
    }
}
func ifEmptyIntAssign(s *int, val int) {
    if *s == 0 {
        *s = val
    }
}

func NewParser(opts *ParserOptions) *Parser {
    if opts == nil {
        opts = &ParserOptions{}
    }

    ifEmptyIntAssign(&opts.LimitValue, DefaultLimitValue)
    ifEmptyIntAssign(&opts.PageValue, DefaultPageValue)
    ifEmptyStringAssign(&opts.LimitString, DefaultLimitString)
    ifEmptyStringAssign(&opts.PageString, DefaultPageString)
    ifEmptyStringAssign(&opts.ExpandString, DefaultExpandString)
    ifEmptyStringAssign(&opts.FieldsString, DefaultFieldsString)
    ifEmptyStringAssign(&opts.QueryString, DefaultQueryString)
    ifEmptyStringAssign(&opts.ParamString, DefaultParamString)
    ifEmptyRuneAssign(&opts.LeftBracket, DefaultLeftBracket)
    ifEmptyRuneAssign(&opts.RightBracket, DefaultRightBracket)
    ifEmptyRuneAssign(&opts.Separator, DefaultSeparator)
    ifEmptyRuneAssign(&opts.KVSeparator, DefaultKVSeparator)

    return &Parser{
        options: opts,
    }
}

func (e *ExpandParams) Get(key string) (*ListOptions) {
    if v, ok := (*e)[key]; ok {
        return &v
    }

    return nil
}

func (e *QueryValues) Get(key string) ([]string) {
    if v, ok := e.Filter[key]; ok {
        return v
    }

    return nil
}

func (qp *Parser) Parse(u *url.URL) (*ParseResult, error) {
    result := &ParseResult{
        Pagination:  &ListOptions{},
        Expand:      &ExpandParams{},
        Fields:      &Fields{},
        Values:      &QueryValues{
            Search: &SearchValue{},
        },
    }
    values := u.Query()
    err := result.Pagination.parse(values, qp.options)
    if err != nil {
        return nil, err
    }
    err = result.Expand.parse(values, qp.options)
    if err != nil {
        return nil, err
    }
    err = result.Values.parse(values, qp.options)
    if err != nil {
        return nil, err
    }
    err = result.Fields.parse(values, qp.options)
    if err != nil {
        return nil, err
    }
    return result, nil
}

func (qp *Parser) ParseString(rawurl string) (*ParseResult, error) {
    u, err := url.Parse(rawurl)
    if err != nil {
        return nil, err
    }
    return qp.Parse(u)
}

func (lo *ListOptions) parse(val url.Values, opts *ParserOptions) error {
    var err error
    if l := val.Get(opts.LimitString); l != "" {
        lo.Limit, err = strconv.Atoi(l)
        if err != nil {
            return err
        }
    } else {
        lo.Limit = opts.LimitValue
    }
    if p := val.Get(opts.PageString); p != "" {
        lo.Page, err = strconv.Atoi(p)
        if err != nil {
            return err
        }
    } else {
        lo.Page = opts.PageValue
    }
    return nil
}

func (ep *ExpandParams) parse(val url.Values, opts *ParserOptions) error {
    params := map[string][]string(val)
    expStr := make([]string, 0)
    for _, str := range params[opts.ExpandString] {
        open := false
        position := 0
        for i, char := range str {
            if char == opts.LeftBracket {
                open = true
            } else if char == opts.RightBracket {
                open = false
            } else if char == opts.Separator && !open {
                expStr = append(expStr, str[position:i])
                position = i
            }
            if i == (len(str) - 1) {
                if position > 0 {
                    position++
                }
                expStr = append(expStr, str[position:])
            }
        }
    }
    for _, char := range expStr {
        splitted := strings.FieldsFunc(char, func(r rune) bool {
            return r == opts.LeftBracket || r == opts.RightBracket || r == opts.Separator
        })
        bcp := ListOptions{
            Limit: opts.LimitValue,
            Page: opts.PageValue,
        }
        if len(splitted) > 1 {
            var err error
            params := strings.Split(splitted[1], string(opts.KVSeparator))
            if params[0] == opts.LimitString {
                bcp.Limit, err = strconv.Atoi(params[1])
            } else if params[0] == opts.PageString {
                bcp.Page, err = strconv.Atoi(params[1])
            }
            if err != nil {
                return err
            }
            if len(splitted) > 2 {
                params := strings.Split(splitted[2], string(opts.KVSeparator))
                if params[0] == opts.LimitString {
                    bcp.Limit, err = strconv.Atoi(params[1])
                } else if params[0] == opts.PageString {
                    bcp.Page, err = strconv.Atoi(params[1])
                }
                if err != nil {
                    return err
                }
            }
        }
        if *ep == nil {
            (*ep) = make(map[string]ListOptions)
        }
        (*ep)[splitted[0]] = bcp
    }
    return nil
}

func (qv *QueryValues) parse(val url.Values, opts *ParserOptions) error {
    params := map[string][]string(val)
    if v, ok := params[opts.QueryString]; ok {
        qv.Search.Value = v[0]
        for _, str := range params[opts.ParamString] {
            qv.Search.Keys = append(qv.Search.Keys, strings.Split(str, string(opts.Separator))...)
        }
    }
    qv.Filter = make(map[string][]string)
    for k, v := range params {
        if k != opts.LimitString && k != opts.PageString &&
        k != opts.ParamString && k != opts.QueryString &&
        k != opts.ExpandString && k != opts.FieldsString {
            for _, s := range v {
                qv.Filter[k] = append(qv.Filter[k], strings.Split(s, string(opts.Separator))...)
            }
        }
    }
    return nil
}

func (f *Fields) parse(val url.Values, opts *ParserOptions) error {
    params := map[string][]string(val)
    if _, ok := params[opts.FieldsString]; ok {
        for _, str := range params[opts.FieldsString] {
            *f = append(*f, strings.Split(str, string(opts.Separator))...)
        }
    }
    return nil
}<|endoftext|>


<commit_before><commit_msg>cmd/cue/cmd: fix description for --show-optional flag<commit_after><|endoftext|>


<commit_before><commit_msg>Minor comment improvement<commit_after><|endoftext|>


<commit_before><commit_msg>test for package cmdutil<commit_after><|endoftext|>


<commit_before>package client_fakes

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"path/filepath"

	services "github.com/maximilien/softlayer-go/services"
	softlayer "github.com/maximilien/softlayer-go/softlayer"
)

const (
	SOFTLAYER_API_URL  = "api.softlayer.com/rest/v3"
	TEMPLATE_ROOT_PATH = "templates"
)

type FakeSoftLayerClient struct {
	Username string
	ApiKey   string

	TemplatePath string

	SoftLayerServices map[string]softlayer.Service

	DoRawHttpRequestResponse       []byte
	DoRawHttpRequestResponses      [][]byte
	DoRawHttpRequestResponsesIndex int
	DoRawHttpRequestError          error

	GenerateRequestBodyBuffer *bytes.Buffer
	GenerateRequestBodyError  error

	HasErrorsError, CheckForHttpResponseError error
}

func NewFakeSoftLayerClient(username, apiKey string) *FakeSoftLayerClient {
	pwd, _ := os.Getwd()
	fslc := &FakeSoftLayerClient{
		Username: username,
		ApiKey:   apiKey,

		TemplatePath: filepath.Join(pwd, TEMPLATE_ROOT_PATH),

		SoftLayerServices: map[string]softlayer.Service{},

		DoRawHttpRequestResponse:       nil,
		DoRawHttpRequestResponses:      [][]byte{},
		DoRawHttpRequestResponsesIndex: 0,
		DoRawHttpRequestError:          nil,

		GenerateRequestBodyBuffer: new(bytes.Buffer),
		GenerateRequestBodyError:  nil,

		HasErrorsError:            nil,
		CheckForHttpResponseError: nil,
	}

	fslc.initSoftLayerServices()

	return fslc
}

//softlayer.Client interface methods

func (fslc *FakeSoftLayerClient) GetService(serviceName string) (softlayer.Service, error) {
	slService, ok := fslc.SoftLayerServices[serviceName]
	if !ok {
		return nil, errors.New(fmt.Sprintf("softlayer-go does not support service '%s'", serviceName))
	}

	return slService, nil
}

func (fslc *FakeSoftLayerClient) GetSoftLayer_Account_Service() (softlayer.SoftLayer_Account_Service, error) {
	slService, err := fslc.GetService("SoftLayer_Account")
	if err != nil {
		return nil, err
	}

	return slService.(softlayer.SoftLayer_Account_Service), nil
}

func (fslc *FakeSoftLayerClient) GetSoftLayer_Virtual_Guest_Service() (softlayer.SoftLayer_Virtual_Guest_Service, error) {
	slService, err := fslc.GetService("SoftLayer_Virtual_Guest")
	if err != nil {
		return nil, err
	}

	return slService.(softlayer.SoftLayer_Virtual_Guest_Service), nil
}

func (fslc *FakeSoftLayerClient) GetSoftLayer_Virtual_Disk_Image_Service() (softlayer.SoftLayer_Virtual_Disk_Image_Service, error) {
	slService, err := fslc.GetService("SoftLayer_Virtual_Disk_Image")
	if err != nil {
		return nil, err
	}

	return slService.(softlayer.SoftLayer_Virtual_Disk_Image_Service), nil
}

func (fslc *FakeSoftLayerClient) GetSoftLayer_Security_Ssh_Key_Service() (softlayer.SoftLayer_Security_Ssh_Key_Service, error) {
	slService, err := fslc.GetService("SoftLayer_Security_Ssh_Key")
	if err != nil {
		return nil, err
	}

	return slService.(softlayer.SoftLayer_Security_Ssh_Key_Service), nil
}

func (fslc *FakeSoftLayerClient) GetSoftLayer_Network_Storage_Service() (softlayer.SoftLayer_Network_Storage_Service, error) {
	slService, err := fslc.GetService("SoftLayer_Network_Storage")
	if err != nil {
		return nil, err
	}

	return slService.(softlayer.SoftLayer_Network_Storage_Service), nil
}

func (fslc *FakeSoftLayerClient) GetSoftLayer_Product_Order_Service() (softlayer.SoftLayer_Product_Order_Service, error) {
	slService, err := fslc.GetService("SoftLayer_Product_Order")
	if err != nil {
		return nil, err
	}

	return slService.(softlayer.SoftLayer_Product_Order_Service), nil
}

func (fslc *FakeSoftLayerClient) GetSoftLayer_Product_Package_Service() (softlayer.SoftLayer_Product_Package_Service, error) {
	slService, err := fslc.GetService("SoftLayer_Product_Package")
	if err != nil {
		return nil, err
	}

	return slService.(softlayer.SoftLayer_Product_Package_Service), nil
}

func (fslc *FakeSoftLayerClient) GetSoftLayer_Billing_Item_Cancellation_Request_Service() (softlayer.SoftLayer_Billing_Item_Cancellation_Request_Service, error) {
	slService, err := fslc.GetService("SoftLayer_Billing_Item_Cancellation_Request")
	if err != nil {
		return nil, err
	}

	return slService.(softlayer.SoftLayer_Billing_Item_Cancellation_Request_Service), nil
}

func (fslc *FakeSoftLayerClient) GetSoftLayer_Virtual_Guest_Block_Device_Template_Group_Service() (softlayer.SoftLayer_Virtual_Guest_Block_Device_Template_Group_Service, error) {
	slService, err := fslc.GetService("SoftLayer_Virtual_Guest_Block_Device_Template_Group")
	if err != nil {
		return nil, err
	}

	return slService.(softlayer.SoftLayer_Virtual_Guest_Block_Device_Template_Group_Service), nil
}

func (fslc *FakeSoftLayerClient) GetSoftLayer_Hardware_Service() (softlayer.SoftLayer_Hardware_Service, error) {
	slService, err := fslc.GetService("SoftLayer_Hardware")
	if err != nil {
		return nil, err
	}

	return slService.(softlayer.SoftLayer_Hardware_Service), nil
}

//Public methods
func (fslc *FakeSoftLayerClient) DoRawHttpRequestWithObjectMask(path string, masks []string, requestType string, requestBody *bytes.Buffer) ([]byte, error) {
	if fslc.DoRawHttpRequestError != nil {
		return []byte{}, fslc.DoRawHttpRequestError
	}

	if fslc.DoRawHttpRequestResponse != nil {
		return fslc.DoRawHttpRequestResponse, fslc.DoRawHttpRequestError
	} else {
		fslc.DoRawHttpRequestResponsesIndex = fslc.DoRawHttpRequestResponsesIndex + 1
		return fslc.DoRawHttpRequestResponses[fslc.DoRawHttpRequestResponsesIndex-1], fslc.DoRawHttpRequestError
	}
}

func (fslc *FakeSoftLayerClient) DoRawHttpRequest(path string, requestType string, requestBody *bytes.Buffer) ([]byte, error) {
	if fslc.DoRawHttpRequestError != nil {
		return []byte{}, fslc.DoRawHttpRequestError
	}

	if fslc.DoRawHttpRequestResponse != nil {
		return fslc.DoRawHttpRequestResponse, fslc.DoRawHttpRequestError
	} else {
		fslc.DoRawHttpRequestResponsesIndex = fslc.DoRawHttpRequestResponsesIndex + 1
		return fslc.DoRawHttpRequestResponses[fslc.DoRawHttpRequestResponsesIndex-1], fslc.DoRawHttpRequestError
	}
}

func (fslc *FakeSoftLayerClient) GenerateRequestBody(templateData interface{}) (*bytes.Buffer, error) {
	return fslc.GenerateRequestBodyBuffer, fslc.GenerateRequestBodyError
}

func (fslc *FakeSoftLayerClient) HasErrors(body map[string]interface{}) error {
	return fslc.HasErrorsError
}

func (fslc *FakeSoftLayerClient) CheckForHttpResponseErrors(data []byte) error {
	return fslc.CheckForHttpResponseError
}

//Private methods

func (fslc *FakeSoftLayerClient) initSoftLayerServices() {
	fslc.SoftLayerServices["SoftLayer_Account"] = services.NewSoftLayer_Account_Service(fslc)
	fslc.SoftLayerServices["SoftLayer_Virtual_Guest"] = services.NewSoftLayer_Virtual_Guest_Service(fslc)
	fslc.SoftLayerServices["SoftLayer_Virtual_Disk_Image"] = services.NewSoftLayer_Virtual_Disk_Image_Service(fslc)
	fslc.SoftLayerServices["SoftLayer_Security_Ssh_Key"] = services.NewSoftLayer_Security_Ssh_Key_Service(fslc)
	fslc.SoftLayerServices["SoftLayer_Network_Storage"] = services.NewSoftLayer_Network_Storage_Service(fslc)
	fslc.SoftLayerServices["SoftLayer_Product_Order"] = services.NewSoftLayer_Product_Order_Service(fslc)
	fslc.SoftLayerServices["SoftLayer_Product_Package"] = services.NewSoftLayer_Product_Package_Service(fslc)
	fslc.SoftLayerServices["SoftLayer_Billing_Item_Cancellation_Request"] = services.NewSoftLayer_Billing_Item_Cancellation_Request_Service(fslc)
	fslc.SoftLayerServices["SoftLayer_Virtual_Guest_Block_Device_Template_Group"] = services.NewSoftLayer_Virtual_Guest_Block_Device_Template_Group_Service(fslc)
	fslc.SoftLayerServices["SoftLayer_Hardware"] = services.NewSoftLayer_Hardware_Service(fslc)
}
<commit_msg>added DoRawHttpRequestResponseCount to fake client<commit_after>package client_fakes

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"path/filepath"

	services "github.com/maximilien/softlayer-go/services"
	softlayer "github.com/maximilien/softlayer-go/softlayer"
)

const (
	SOFTLAYER_API_URL  = "api.softlayer.com/rest/v3"
	TEMPLATE_ROOT_PATH = "templates"
)

type FakeSoftLayerClient struct {
	Username string
	ApiKey   string

	TemplatePath string

	SoftLayerServices map[string]softlayer.Service

	DoRawHttpRequestResponseCount int

	DoRawHttpRequestResponse       []byte
	DoRawHttpRequestResponses      [][]byte
	DoRawHttpRequestResponsesIndex int
	DoRawHttpRequestError          error

	GenerateRequestBodyBuffer *bytes.Buffer
	GenerateRequestBodyError  error

	HasErrorsError, CheckForHttpResponseError error
}

func NewFakeSoftLayerClient(username, apiKey string) *FakeSoftLayerClient {
	pwd, _ := os.Getwd()
	fslc := &FakeSoftLayerClient{
		Username: username,
		ApiKey:   apiKey,

		TemplatePath: filepath.Join(pwd, TEMPLATE_ROOT_PATH),

		SoftLayerServices: map[string]softlayer.Service{},

		DoRawHttpRequestResponseCount: 0,

		DoRawHttpRequestResponse:       nil,
		DoRawHttpRequestResponses:      [][]byte{},
		DoRawHttpRequestResponsesIndex: 0,
		DoRawHttpRequestError:          nil,

		GenerateRequestBodyBuffer: new(bytes.Buffer),
		GenerateRequestBodyError:  nil,

		HasErrorsError:            nil,
		CheckForHttpResponseError: nil,
	}

	fslc.initSoftLayerServices()

	return fslc
}

//softlayer.Client interface methods

func (fslc *FakeSoftLayerClient) GetService(serviceName string) (softlayer.Service, error) {
	slService, ok := fslc.SoftLayerServices[serviceName]
	if !ok {
		return nil, errors.New(fmt.Sprintf("softlayer-go does not support service '%s'", serviceName))
	}

	return slService, nil
}

func (fslc *FakeSoftLayerClient) GetSoftLayer_Account_Service() (softlayer.SoftLayer_Account_Service, error) {
	slService, err := fslc.GetService("SoftLayer_Account")
	if err != nil {
		return nil, err
	}

	return slService.(softlayer.SoftLayer_Account_Service), nil
}

func (fslc *FakeSoftLayerClient) GetSoftLayer_Virtual_Guest_Service() (softlayer.SoftLayer_Virtual_Guest_Service, error) {
	slService, err := fslc.GetService("SoftLayer_Virtual_Guest")
	if err != nil {
		return nil, err
	}

	return slService.(softlayer.SoftLayer_Virtual_Guest_Service), nil
}

func (fslc *FakeSoftLayerClient) GetSoftLayer_Virtual_Disk_Image_Service() (softlayer.SoftLayer_Virtual_Disk_Image_Service, error) {
	slService, err := fslc.GetService("SoftLayer_Virtual_Disk_Image")
	if err != nil {
		return nil, err
	}

	return slService.(softlayer.SoftLayer_Virtual_Disk_Image_Service), nil
}

func (fslc *FakeSoftLayerClient) GetSoftLayer_Security_Ssh_Key_Service() (softlayer.SoftLayer_Security_Ssh_Key_Service, error) {
	slService, err := fslc.GetService("SoftLayer_Security_Ssh_Key")
	if err != nil {
		return nil, err
	}

	return slService.(softlayer.SoftLayer_Security_Ssh_Key_Service), nil
}

func (fslc *FakeSoftLayerClient) GetSoftLayer_Network_Storage_Service() (softlayer.SoftLayer_Network_Storage_Service, error) {
	slService, err := fslc.GetService("SoftLayer_Network_Storage")
	if err != nil {
		return nil, err
	}

	return slService.(softlayer.SoftLayer_Network_Storage_Service), nil
}

func (fslc *FakeSoftLayerClient) GetSoftLayer_Product_Order_Service() (softlayer.SoftLayer_Product_Order_Service, error) {
	slService, err := fslc.GetService("SoftLayer_Product_Order")
	if err != nil {
		return nil, err
	}

	return slService.(softlayer.SoftLayer_Product_Order_Service), nil
}

func (fslc *FakeSoftLayerClient) GetSoftLayer_Product_Package_Service() (softlayer.SoftLayer_Product_Package_Service, error) {
	slService, err := fslc.GetService("SoftLayer_Product_Package")
	if err != nil {
		return nil, err
	}

	return slService.(softlayer.SoftLayer_Product_Package_Service), nil
}

func (fslc *FakeSoftLayerClient) GetSoftLayer_Billing_Item_Cancellation_Request_Service() (softlayer.SoftLayer_Billing_Item_Cancellation_Request_Service, error) {
	slService, err := fslc.GetService("SoftLayer_Billing_Item_Cancellation_Request")
	if err != nil {
		return nil, err
	}

	return slService.(softlayer.SoftLayer_Billing_Item_Cancellation_Request_Service), nil
}

func (fslc *FakeSoftLayerClient) GetSoftLayer_Virtual_Guest_Block_Device_Template_Group_Service() (softlayer.SoftLayer_Virtual_Guest_Block_Device_Template_Group_Service, error) {
	slService, err := fslc.GetService("SoftLayer_Virtual_Guest_Block_Device_Template_Group")
	if err != nil {
		return nil, err
	}

	return slService.(softlayer.SoftLayer_Virtual_Guest_Block_Device_Template_Group_Service), nil
}

func (fslc *FakeSoftLayerClient) GetSoftLayer_Hardware_Service() (softlayer.SoftLayer_Hardware_Service, error) {
	slService, err := fslc.GetService("SoftLayer_Hardware")
	if err != nil {
		return nil, err
	}

	return slService.(softlayer.SoftLayer_Hardware_Service), nil
}

//Public methods
func (fslc *FakeSoftLayerClient) DoRawHttpRequestWithObjectMask(path string, masks []string, requestType string, requestBody *bytes.Buffer) ([]byte, error) {
	fslc.DoRawHttpRequestResponseCount += 1

	if fslc.DoRawHttpRequestError != nil {
		return []byte{}, fslc.DoRawHttpRequestError
	}

	if fslc.DoRawHttpRequestResponse != nil {
		return fslc.DoRawHttpRequestResponse, fslc.DoRawHttpRequestError
	} else {
		fslc.DoRawHttpRequestResponsesIndex = fslc.DoRawHttpRequestResponsesIndex + 1
		return fslc.DoRawHttpRequestResponses[fslc.DoRawHttpRequestResponsesIndex-1], fslc.DoRawHttpRequestError
	}
}

func (fslc *FakeSoftLayerClient) DoRawHttpRequest(path string, requestType string, requestBody *bytes.Buffer) ([]byte, error) {
	fslc.DoRawHttpRequestResponseCount += 1

	if fslc.DoRawHttpRequestError != nil {
		return []byte{}, fslc.DoRawHttpRequestError
	}

	if fslc.DoRawHttpRequestResponse != nil {
		return fslc.DoRawHttpRequestResponse, fslc.DoRawHttpRequestError
	} else {
		fslc.DoRawHttpRequestResponsesIndex = fslc.DoRawHttpRequestResponsesIndex + 1
		return fslc.DoRawHttpRequestResponses[fslc.DoRawHttpRequestResponsesIndex-1], fslc.DoRawHttpRequestError
	}
}

func (fslc *FakeSoftLayerClient) GenerateRequestBody(templateData interface{}) (*bytes.Buffer, error) {
	return fslc.GenerateRequestBodyBuffer, fslc.GenerateRequestBodyError
}

func (fslc *FakeSoftLayerClient) HasErrors(body map[string]interface{}) error {
	return fslc.HasErrorsError
}

func (fslc *FakeSoftLayerClient) CheckForHttpResponseErrors(data []byte) error {
	return fslc.CheckForHttpResponseError
}

//Private methods

func (fslc *FakeSoftLayerClient) initSoftLayerServices() {
	fslc.SoftLayerServices["SoftLayer_Account"] = services.NewSoftLayer_Account_Service(fslc)
	fslc.SoftLayerServices["SoftLayer_Virtual_Guest"] = services.NewSoftLayer_Virtual_Guest_Service(fslc)
	fslc.SoftLayerServices["SoftLayer_Virtual_Disk_Image"] = services.NewSoftLayer_Virtual_Disk_Image_Service(fslc)
	fslc.SoftLayerServices["SoftLayer_Security_Ssh_Key"] = services.NewSoftLayer_Security_Ssh_Key_Service(fslc)
	fslc.SoftLayerServices["SoftLayer_Network_Storage"] = services.NewSoftLayer_Network_Storage_Service(fslc)
	fslc.SoftLayerServices["SoftLayer_Product_Order"] = services.NewSoftLayer_Product_Order_Service(fslc)
	fslc.SoftLayerServices["SoftLayer_Product_Package"] = services.NewSoftLayer_Product_Package_Service(fslc)
	fslc.SoftLayerServices["SoftLayer_Billing_Item_Cancellation_Request"] = services.NewSoftLayer_Billing_Item_Cancellation_Request_Service(fslc)
	fslc.SoftLayerServices["SoftLayer_Virtual_Guest_Block_Device_Template_Group"] = services.NewSoftLayer_Virtual_Guest_Block_Device_Template_Group_Service(fslc)
	fslc.SoftLayerServices["SoftLayer_Hardware"] = services.NewSoftLayer_Hardware_Service(fslc)
}
<|endoftext|>


<commit_before>package isolated

import (
	"code.cloudfoundry.org/cli/integration/helpers"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("set-health-check command", func() {
	Describe("help", func() {
		Context("when --help flag is set", func() {
			It("Displays command usage to output", func() {
				session := helpers.CF("set-health-check", "--help")
				Eventually(session).Should(Say("NAME:"))
				Eventually(session).Should(Say("set-health-check - Set health_check_type flag to either 'port' or 'none'"))
				Eventually(session).Should(Say("USAGE:"))
				Eventually(session).Should(Say("cf set-health-check APP_NAME \\('port' \\| 'none'\\)"))
				Eventually(session).Should(Exit(0))
			})
		})
	})

	Context("when the environment is not setup correctly", func() {
		Context("when no API endpoint is set", func() {
			BeforeEach(func() {
				helpers.UnsetAPI()
			})

			It("fails with no API endpoint set message", func() {
				session := helpers.CF("set-health-check", "some-app", "port")
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No API endpoint set. Use 'cf login' or 'cf api' to target an endpoint."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when not logged in", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
			})

			It("fails with not logged in message", func() {
				session := helpers.CF("set-health-check", "some-app", "port")
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("Not logged in. Use 'cf login' to log in."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when there is no org and space set", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
				helpers.LoginCF()
			})

			It("fails with no targeted org error message", func() {
				session := helpers.CF("set-health-check", "some-app", "port")
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No org targeted, use 'cf target -o ORG' to target an org."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when there is no space set", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
				helpers.LoginCF()
				helpers.TargetOrg(ReadOnlyOrg)
			})

			It("fails with no targeted space error message", func() {
				session := helpers.CF("set-health-check", "some-app", "port")
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No space targeted, use 'cf target -s SPACE' to target a space."))
				Eventually(session).Should(Exit(1))
			})
		})
	})

	Context("when app-name and health-check-type are not passed in", func() {
		It("fails with incorrect ussage error message and displays help", func() {
			session := helpers.CF("set-health-check")
			Eventually(session.Err).Should(Say("Incorrect Usage: the required arguments `APP_NAME` and `HEALTH_CHECK_TYPE` were not provided"))
			Eventually(session).Should(Say("NAME:"))
			Eventually(session).Should(Say("set-health-check - Set health_check_type flag to either 'port' or 'none'"))
			Eventually(session).Should(Say("USAGE:"))
			Eventually(session).Should(Say("cf set-health-check APP_NAME \\('port' \\| 'none'\\)"))
			Eventually(session).Should(Exit(1))
		})
	})

	Context("when health-check-type is not passed in", func() {
		It("fails with incorrect usage error message and displays help", func() {
			session := helpers.CF("set-health-check", "some-app")
			Eventually(session.Err).Should(Say("Incorrect Usage: the required argument `HEALTH_CHECK_TYPE` was not provided"))
			Eventually(session).Should(Say("NAME:"))
			Eventually(session).Should(Say("set-health-check - Set health_check_type flag to either 'port' or 'none'"))
			Eventually(session).Should(Say("USAGE:"))
			Eventually(session).Should(Say("cf set-health-check APP_NAME \\('port' \\| 'none'\\)"))
			Eventually(session).Should(Exit(1))
		})
	})

	Context("when health-check-type is invalid", func() {
		It("fails with incorrect usage error message and displays help", func() {
			session := helpers.CF("set-health-check", "some-app", "wut")
			Eventually(session.Err).Should(Say(`Incorrect Usage: HEALTH_CHECK_TYPE must be "port" or "none"`))
			Eventually(session).Should(Say("NAME:"))
			Eventually(session).Should(Say("set-health-check - Set health_check_type flag to either 'port' or 'none'"))
			Eventually(session).Should(Say("USAGE:"))
			Eventually(session).Should(Say("cf set-health-check APP_NAME \\('port' \\| 'none'\\)"))
			Eventually(session).Should(Exit(1))
		})
	})

	Context("when the environment is set up correctly", func() {
		var (
			orgName   string
			spaceName string
		)

		BeforeEach(func() {
			orgName = helpers.NewOrgName()
			spaceName = helpers.PrefixedRandomName("SPACE")

			setupCF(orgName, spaceName)
		})

		Context("when the app does not exist", func() {
			It("tells the user that the app is not found and exits 1", func() {
				appName := helpers.PrefixedRandomName("app")
				session := helpers.CF("set-health-check", appName, "port")

				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("App %s not found", appName))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when the app exists", func() {
			var (
				appName string
			)

			BeforeEach(func() {
				appName = helpers.PrefixedRandomName("app")
				helpers.WithHelloWorldApp(func(appDir string) {
					Eventually(helpers.CF("push", appName, "-p", appDir, "-b", "staticfile_buildpack")).Should(Exit(0))
				})
			})

			Context("when setting the health-check-type to 'none'", func() {
				BeforeEach(func() {
					Eventually(helpers.CF("set-health-check", appName, "port")).Should(Exit(0))
				})

				It("updates the new health-check-type and exits 0", func() {
					session := helpers.CF("set-health-check", appName, "none")

					username, _ := helpers.GetCredentials()
					Eventually(session).Should(Say("Updating health check type to 'none' for app %s in org %s / space %s as %s", appName, orgName, spaceName, username))
					Eventually(session).Should(Say("OK"))
					Eventually(session).Should(Exit(0))
				})
			})

			Context("when setting the health-check-type to 'port'", func() {
				BeforeEach(func() {
					Eventually(helpers.CF("set-health-check", appName, "none")).Should(Exit(0))
				})

				It("updates the new health-check-type and exits 0", func() {
					session := helpers.CF("set-health-check", appName, "port")

					username, _ := helpers.GetCredentials()
					Eventually(session).Should(Say("Updating health check type to 'port' for app %s in org %s / space %s as %s", appName, orgName, spaceName, username))
					Eventually(session).Should(Say("OK"))
					Eventually(session).Should(Exit(0))
				})
			})
		})
	})
})
<commit_msg>add get-health-check after setting in integration tests<commit_after>package isolated

import (
	"code.cloudfoundry.org/cli/integration/helpers"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("set-health-check command", func() {
	Describe("help", func() {
		Context("when --help flag is set", func() {
			It("Displays command usage to output", func() {
				session := helpers.CF("set-health-check", "--help")
				Eventually(session).Should(Say("NAME:"))
				Eventually(session).Should(Say("set-health-check - Set health_check_type flag to either 'port' or 'none'"))
				Eventually(session).Should(Say("USAGE:"))
				Eventually(session).Should(Say("cf set-health-check APP_NAME \\('port' \\| 'none'\\)"))
				Eventually(session).Should(Exit(0))
			})
		})
	})

	Context("when the environment is not setup correctly", func() {
		Context("when no API endpoint is set", func() {
			BeforeEach(func() {
				helpers.UnsetAPI()
			})

			It("fails with no API endpoint set message", func() {
				session := helpers.CF("set-health-check", "some-app", "port")
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No API endpoint set. Use 'cf login' or 'cf api' to target an endpoint."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when not logged in", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
			})

			It("fails with not logged in message", func() {
				session := helpers.CF("set-health-check", "some-app", "port")
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("Not logged in. Use 'cf login' to log in."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when there is no org and space set", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
				helpers.LoginCF()
			})

			It("fails with no targeted org error message", func() {
				session := helpers.CF("set-health-check", "some-app", "port")
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No org targeted, use 'cf target -o ORG' to target an org."))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when there is no space set", func() {
			BeforeEach(func() {
				helpers.LogoutCF()
				helpers.LoginCF()
				helpers.TargetOrg(ReadOnlyOrg)
			})

			It("fails with no targeted space error message", func() {
				session := helpers.CF("set-health-check", "some-app", "port")
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("No space targeted, use 'cf target -s SPACE' to target a space."))
				Eventually(session).Should(Exit(1))
			})
		})
	})

	Context("when app-name and health-check-type are not passed in", func() {
		It("fails with incorrect ussage error message and displays help", func() {
			session := helpers.CF("set-health-check")
			Eventually(session.Err).Should(Say("Incorrect Usage: the required arguments `APP_NAME` and `HEALTH_CHECK_TYPE` were not provided"))
			Eventually(session).Should(Say("NAME:"))
			Eventually(session).Should(Say("set-health-check - Set health_check_type flag to either 'port' or 'none'"))
			Eventually(session).Should(Say("USAGE:"))
			Eventually(session).Should(Say("cf set-health-check APP_NAME \\('port' \\| 'none'\\)"))
			Eventually(session).Should(Exit(1))
		})
	})

	Context("when health-check-type is not passed in", func() {
		It("fails with incorrect usage error message and displays help", func() {
			session := helpers.CF("set-health-check", "some-app")
			Eventually(session.Err).Should(Say("Incorrect Usage: the required argument `HEALTH_CHECK_TYPE` was not provided"))
			Eventually(session).Should(Say("NAME:"))
			Eventually(session).Should(Say("set-health-check - Set health_check_type flag to either 'port' or 'none'"))
			Eventually(session).Should(Say("USAGE:"))
			Eventually(session).Should(Say("cf set-health-check APP_NAME \\('port' \\| 'none'\\)"))
			Eventually(session).Should(Exit(1))
		})
	})

	Context("when health-check-type is invalid", func() {
		It("fails with incorrect usage error message and displays help", func() {
			session := helpers.CF("set-health-check", "some-app", "wut")
			Eventually(session.Err).Should(Say(`Incorrect Usage: HEALTH_CHECK_TYPE must be "port" or "none"`))
			Eventually(session).Should(Say("NAME:"))
			Eventually(session).Should(Say("set-health-check - Set health_check_type flag to either 'port' or 'none'"))
			Eventually(session).Should(Say("USAGE:"))
			Eventually(session).Should(Say("cf set-health-check APP_NAME \\('port' \\| 'none'\\)"))
			Eventually(session).Should(Exit(1))
		})
	})

	Context("when the environment is set up correctly", func() {
		var (
			orgName   string
			spaceName string
		)

		BeforeEach(func() {
			orgName = helpers.NewOrgName()
			spaceName = helpers.PrefixedRandomName("SPACE")

			setupCF(orgName, spaceName)
		})

		Context("when the app does not exist", func() {
			It("tells the user that the app is not found and exits 1", func() {
				appName := helpers.PrefixedRandomName("app")
				session := helpers.CF("set-health-check", appName, "port")

				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say("App %s not found", appName))
				Eventually(session).Should(Exit(1))
			})
		})

		Context("when the app exists", func() {
			var (
				appName string
			)

			BeforeEach(func() {
				appName = helpers.PrefixedRandomName("app")
				helpers.WithHelloWorldApp(func(appDir string) {
					Eventually(helpers.CF("push", appName, "-p", appDir, "-b", "staticfile_buildpack")).Should(Exit(0))
				})
			})

			Context("when setting the health-check-type to 'none'", func() {
				BeforeEach(func() {
					Eventually(helpers.CF("set-health-check", appName, "port")).Should(Exit(0))
				})

				It("updates the new health-check-type and exits 0", func() {
					session := helpers.CF("set-health-check", appName, "none")

					username, _ := helpers.GetCredentials()
					Eventually(session).Should(Say("Updating health check type to 'none' for app %s in org %s / space %s as %s", appName, orgName, spaceName, username))
					Eventually(session).Should(Say("OK"))
					Eventually(session).Should(Exit(0))

					getSession := helpers.CF("get-health-check", appName)
					Eventually(getSession).Should(Say("health_check_type is none"))
					Eventually(getSession).Should(Exit(0))
				})
			})

			Context("when setting the health-check-type to 'port'", func() {
				BeforeEach(func() {
					Eventually(helpers.CF("set-health-check", appName, "none")).Should(Exit(0))
				})

				It("updates the new health-check-type and exits 0", func() {
					session := helpers.CF("set-health-check", appName, "port")

					username, _ := helpers.GetCredentials()
					Eventually(session).Should(Say("Updating health check type to 'port' for app %s in org %s / space %s as %s", appName, orgName, spaceName, username))
					Eventually(session).Should(Say("OK"))
					Eventually(session).Should(Exit(0))

					getSession := helpers.CF("get-health-check", appName)
					Eventually(getSession).Should(Say("health_check_type is port"))
					Eventually(getSession).Should(Exit(0))
				})
			})
		})
	})
})
<|endoftext|>


<commit_before>package main_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"

	"testing"
)

func TestConcourse(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Concourse Suite")
}

var concoursePath string

var _ = BeforeSuite(func() {
	var err error
	concoursePath, err = gexec.Build("github.com/concourse/concourse/cmd/concourse")
	Expect(err).NotTo(HaveOccurred())
})

var _ = AfterSuite(func() {
	gexec.CleanupBuildArtifacts()
})
<commit_msg>Only build concourse binary once<commit_after>package main_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"

	"testing"
)

func TestConcourse(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Concourse Suite")
}

var concoursePath string

var _ = SynchronizedBeforeSuite(func() []byte {
	buildPath, err := gexec.Build("github.com/concourse/concourse/cmd/concourse")
	Expect(err).NotTo(HaveOccurred())
	return []byte(buildPath)
}, func(data []byte) {
	concoursePath = string(data)
})

var _ = SynchronizedAfterSuite(func() {
	// other nodes don't need to do any clean up, as it's already taken care of by the first node
}, func() {
	gexec.CleanupBuildArtifacts()
})
<|endoftext|>


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

package main

import (
	"context"
	"flag"
	"fmt"
	"os"
	"time"

	"github.com/golang/glog"
	"github.com/golang/protobuf/proto"
	"github.com/google/trillian"
	"github.com/google/trillian/crypto/keys/der"
	"github.com/google/trillian/crypto/keyspb"
	"github.com/google/trillian/monitoring/prometheus"
	"github.com/google/trillian/util/election2"
	"github.com/google/trillian/util/etcd"
	"golang.org/x/sync/errgroup"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"

	"github.com/google/keytransparency/cmd/serverutil"
	"github.com/google/keytransparency/core/adminserver"
	"github.com/google/keytransparency/core/sequencer"
	"github.com/google/keytransparency/core/sequencer/election"
	"github.com/google/keytransparency/impl/sql/directory"
	"github.com/google/keytransparency/impl/sql/mutationstorage"

	pb "github.com/google/keytransparency/core/api/v1/keytransparency_go_proto"
	dir "github.com/google/keytransparency/core/directory"
	spb "github.com/google/keytransparency/core/sequencer/sequencer_go_proto"
	ktsql "github.com/google/keytransparency/impl/sql"
	etcdelect "github.com/google/trillian/util/election2/etcd"
	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"

	_ "github.com/google/trillian/crypto/keys/der/proto"
	_ "github.com/google/trillian/merkle/coniks"  // Register hasher
	_ "github.com/google/trillian/merkle/rfc6962" // Register hasher
)

var (
	keyFile     = flag.String("tls-key", "genfiles/server.key", "TLS private key file")
	certFile    = flag.String("tls-cert", "genfiles/server.crt", "TLS cert file")
	addr        = flag.String("addr", ":8080", "The ip:port to serve on")
	metricsAddr = flag.String("metrics-addr", ":8081", "The ip:port to publish metrics on")

	forceMaster = flag.Bool("force_master", false, "If true, assume master for all directories")
	etcdServers = flag.String("etcd_servers", "", "A comma-separated list of etcd servers; no etcd registration if empty")
	lockDir     = flag.String("lock_file_path", "/keytransparency/master", "etcd lock file directory path")

	serverDBPath = flag.String("db", "db", "Database connection string")

	// Info to connect to the trillian map and log.
	mapURL = flag.String("map-url", "", "URL of Trillian Map Server")
	logURL = flag.String("log-url", "", "URL of Trillian Log Server for Signed Map Heads")

	dirRefresh = flag.Duration("directory-refresh", 5*time.Second, "Time to detect new directory")
	refresh    = flag.Duration("refresh", 5*time.Second, "Time between map revision construction runs")
	batchSize  = flag.Int("batch-size", 100, "Maximum number of mutations to process per map revision")
)

// getElectionFactory returns an election factory based on flags, and a
// function which releases the resources associated with the factory.
func getElectionFactory() (election2.Factory, func()) {
	if *forceMaster {
		glog.Warning("Acting as master for all directories")
		return election2.NoopFactory{}, func() {}
	}
	if len(*etcdServers) == 0 {
		glog.Exit("Either --force_master or --etcd_servers must be supplied")
	}

	cli, err := etcd.NewClientFromString(*etcdServers)
	if err != nil || cli == nil {
		glog.Exitf("Failed to create etcd client: %v", err)
	}
	closeFn := func() {
		if err := cli.Close(); err != nil {
			glog.Warningf("etcd client Close(): %v", err)
		}
	}

	hostname, _ := os.Hostname()
	instanceID := fmt.Sprintf("%s.%d", hostname, os.Getpid())
	factory := etcdelect.NewFactory(instanceID, cli, *lockDir)

	return factory, closeFn
}

func main() {
	flag.Parse()
	ctx := context.Background()
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	// Connect to trillian log and map backends.
	mconn, err := grpc.DialContext(ctx, *mapURL, grpc.WithInsecure())
	if err != nil {
		glog.Exitf("grpc.Dial(%v): %v", *mapURL, err)
	}
	lconn, err := grpc.DialContext(ctx, *logURL, grpc.WithInsecure())
	if err != nil {
		glog.Exitf("Failed to connect to %v: %v", *logURL, err)
	}

	// Database tables
	sqldb, err := ktsql.Open(*serverDBPath)
	if err != nil {
		glog.Exit(err)
	}
	defer sqldb.Close()

	mutations, err := mutationstorage.New(sqldb)
	if err != nil {
		glog.Exitf("Failed to create mutations object: %v", err)
	}
	directoryStorage, err := directory.NewStorage(sqldb)
	if err != nil {
		glog.Exitf("Failed to create directory storage object: %v", err)
	}

	grpcServer := grpc.NewServer(
		grpc.StreamInterceptor(grpc_prometheus.StreamServerInterceptor),
		grpc.UnaryInterceptor(grpc_prometheus.UnaryServerInterceptor),
	)

	// Listen and create empty grpc client connection.
	lis, conn, done, err := serverutil.ListenTLS(ctx, *addr, *certFile, *keyFile)
	if err != nil {
		glog.Fatalf("Listen(%v): %v", *addr, err)
	}
	defer done()

	spb.RegisterKeyTransparencySequencerServer(grpcServer, sequencer.NewServer(
		directoryStorage,
		trillian.NewTrillianLogClient(lconn),
		trillian.NewTrillianMapClient(mconn),
		trillian.NewTrillianMapWriteClient(mconn),
		mutations, mutations,
		spb.NewKeyTransparencySequencerClient(conn),
		prometheus.MetricFactory{}))

	pb.RegisterKeyTransparencyAdminServer(grpcServer, adminserver.New(
		trillian.NewTrillianLogClient(lconn),
		trillian.NewTrillianMapClient(mconn),
		trillian.NewTrillianAdminClient(lconn),
		trillian.NewTrillianAdminClient(mconn),
		directoryStorage,
		mutations,
		mutations,
		func(ctx context.Context, spec *keyspb.Specification) (proto.Message, error) {
			return der.NewProtoFromSpec(spec)
		}))

	reflection.Register(grpcServer)
	grpc_prometheus.Register(grpcServer)
	grpc_prometheus.EnableHandlingTimeHistogram()

	// Run servers
	g, gctx := errgroup.WithContext(ctx)
	g.Go(func() error { return serverutil.ServeHTTPMetrics(*metricsAddr, serverutil.Readyz(sqldb)) })
	g.Go(func() error {
		return serverutil.ServeHTTPAPIAndGRPC(gctx, lis, grpcServer, conn,
			pb.RegisterKeyTransparencyAdminHandler)
	})
	go runSequencer(gctx, conn, directoryStorage)

	glog.Errorf("Signer exiting: %v", g.Wait())
}

func runSequencer(ctx context.Context, conn *grpc.ClientConn, directoryStorage dir.Storage) {
	glog.Infof("Sequencer starting")
	electionFactory, closeFactory := getElectionFactory()
	defer closeFactory()
	signer := sequencer.New(
		spb.NewKeyTransparencySequencerClient(conn),
		directoryStorage,
		election.NewTracker(electionFactory, 1*time.Hour, prometheus.MetricFactory{}),
	)

	go signer.TrackMasterships(ctx)

	go sequencer.PeriodicallyRun(ctx, time.Tick(*refresh), func(ctx context.Context) {
		if err := signer.ForAllMasterships(ctx, func(ctx context.Context, dirID string) error {
			_, err := spb.NewKeyTransparencySequencerClient(conn).
				EstimateBacklog(ctx, &spb.EstimateBacklogRequest{
					DirectoryId:       dirID,
					MaxUnappliedCount: 100000,
				})
			return err
		}); err != nil {
			glog.Errorf("UpdateMetrics(): %v", err)
		}
	})

	if err := signer.AddAllDirectories(ctx); err != nil {
		glog.Errorf("runSequencer(AddAllDirectories): %v", err)
	}
	go sequencer.PeriodicallyRun(ctx, time.Tick(*dirRefresh), func(ctx context.Context) {
		if err := signer.AddAllDirectories(ctx); err != nil {
			glog.Errorf("PeriodicallyRun(AddAllDirectories): %v", err)
		}
	})

	go sequencer.PeriodicallyRun(ctx, time.Tick(*refresh), func(ctx context.Context) {
		if err := signer.DefineRevisionsForAllMasterships(ctx, int32(*batchSize)); err != nil {
			glog.Errorf("PeriodicallyRun(DefineRevisionsForAllMasterships): %v", err)
		}
	})
	go sequencer.PeriodicallyRun(ctx, time.Tick(*refresh), func(ctx context.Context) {
		if err := signer.ApplyRevisionsForAllMasterships(ctx); err != nil {
			glog.Errorf("PeriodicallyRun(ApplyRevisionsForAllMasterships): %v", err)
		}
	})

	sequencer.PeriodicallyRun(ctx, time.Tick(*refresh), func(ctx context.Context) {
		if err := signer.PublishLogForAllMasterships(ctx); err != nil {
			glog.Errorf("PeriodicallyRun(PublishRevisionsForAllMasterships): %v", err)
		}
	})
}
<commit_msg>Explicitly block until server exit<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"context"
	"flag"
	"fmt"
	"os"
	"time"

	"github.com/golang/glog"
	"github.com/golang/protobuf/proto"
	"github.com/google/trillian"
	"github.com/google/trillian/crypto/keys/der"
	"github.com/google/trillian/crypto/keyspb"
	"github.com/google/trillian/monitoring/prometheus"
	"github.com/google/trillian/util/election2"
	"github.com/google/trillian/util/etcd"
	"golang.org/x/sync/errgroup"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"

	"github.com/google/keytransparency/cmd/serverutil"
	"github.com/google/keytransparency/core/adminserver"
	"github.com/google/keytransparency/core/sequencer"
	"github.com/google/keytransparency/core/sequencer/election"
	"github.com/google/keytransparency/impl/sql/directory"
	"github.com/google/keytransparency/impl/sql/mutationstorage"

	pb "github.com/google/keytransparency/core/api/v1/keytransparency_go_proto"
	dir "github.com/google/keytransparency/core/directory"
	spb "github.com/google/keytransparency/core/sequencer/sequencer_go_proto"
	ktsql "github.com/google/keytransparency/impl/sql"
	etcdelect "github.com/google/trillian/util/election2/etcd"
	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"

	_ "github.com/google/trillian/crypto/keys/der/proto"
	_ "github.com/google/trillian/merkle/coniks"  // Register hasher
	_ "github.com/google/trillian/merkle/rfc6962" // Register hasher
)

var (
	keyFile     = flag.String("tls-key", "genfiles/server.key", "TLS private key file")
	certFile    = flag.String("tls-cert", "genfiles/server.crt", "TLS cert file")
	addr        = flag.String("addr", ":8080", "The ip:port to serve on")
	metricsAddr = flag.String("metrics-addr", ":8081", "The ip:port to publish metrics on")

	forceMaster = flag.Bool("force_master", false, "If true, assume master for all directories")
	etcdServers = flag.String("etcd_servers", "", "A comma-separated list of etcd servers; no etcd registration if empty")
	lockDir     = flag.String("lock_file_path", "/keytransparency/master", "etcd lock file directory path")

	serverDBPath = flag.String("db", "db", "Database connection string")

	// Info to connect to the trillian map and log.
	mapURL = flag.String("map-url", "", "URL of Trillian Map Server")
	logURL = flag.String("log-url", "", "URL of Trillian Log Server for Signed Map Heads")

	dirRefresh = flag.Duration("directory-refresh", 5*time.Second, "Time to detect new directory")
	refresh    = flag.Duration("refresh", 5*time.Second, "Time between map revision construction runs")
	batchSize  = flag.Int("batch-size", 100, "Maximum number of mutations to process per map revision")
)

// getElectionFactory returns an election factory based on flags, and a
// function which releases the resources associated with the factory.
func getElectionFactory() (election2.Factory, func()) {
	if *forceMaster {
		glog.Warning("Acting as master for all directories")
		return election2.NoopFactory{}, func() {}
	}
	if len(*etcdServers) == 0 {
		glog.Exit("Either --force_master or --etcd_servers must be supplied")
	}

	cli, err := etcd.NewClientFromString(*etcdServers)
	if err != nil || cli == nil {
		glog.Exitf("Failed to create etcd client: %v", err)
	}
	closeFn := func() {
		if err := cli.Close(); err != nil {
			glog.Warningf("etcd client Close(): %v", err)
		}
	}

	hostname, _ := os.Hostname()
	instanceID := fmt.Sprintf("%s.%d", hostname, os.Getpid())
	factory := etcdelect.NewFactory(instanceID, cli, *lockDir)

	return factory, closeFn
}

func main() {
	flag.Parse()
	ctx := context.Background()
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	// Connect to trillian log and map backends.
	mconn, err := grpc.DialContext(ctx, *mapURL, grpc.WithInsecure())
	if err != nil {
		glog.Exitf("grpc.Dial(%v): %v", *mapURL, err)
	}
	lconn, err := grpc.DialContext(ctx, *logURL, grpc.WithInsecure())
	if err != nil {
		glog.Exitf("Failed to connect to %v: %v", *logURL, err)
	}

	// Database tables
	sqldb, err := ktsql.Open(*serverDBPath)
	if err != nil {
		glog.Exit(err)
	}
	defer sqldb.Close()

	mutations, err := mutationstorage.New(sqldb)
	if err != nil {
		glog.Exitf("Failed to create mutations object: %v", err)
	}
	directoryStorage, err := directory.NewStorage(sqldb)
	if err != nil {
		glog.Exitf("Failed to create directory storage object: %v", err)
	}

	grpcServer := grpc.NewServer(
		grpc.StreamInterceptor(grpc_prometheus.StreamServerInterceptor),
		grpc.UnaryInterceptor(grpc_prometheus.UnaryServerInterceptor),
	)

	// Listen and create empty grpc client connection.
	lis, conn, done, err := serverutil.ListenTLS(ctx, *addr, *certFile, *keyFile)
	if err != nil {
		glog.Fatalf("Listen(%v): %v", *addr, err)
	}
	defer done()

	spb.RegisterKeyTransparencySequencerServer(grpcServer, sequencer.NewServer(
		directoryStorage,
		trillian.NewTrillianLogClient(lconn),
		trillian.NewTrillianMapClient(mconn),
		trillian.NewTrillianMapWriteClient(mconn),
		mutations, mutations,
		spb.NewKeyTransparencySequencerClient(conn),
		prometheus.MetricFactory{}))

	pb.RegisterKeyTransparencyAdminServer(grpcServer, adminserver.New(
		trillian.NewTrillianLogClient(lconn),
		trillian.NewTrillianMapClient(mconn),
		trillian.NewTrillianAdminClient(lconn),
		trillian.NewTrillianAdminClient(mconn),
		directoryStorage,
		mutations,
		mutations,
		func(ctx context.Context, spec *keyspb.Specification) (proto.Message, error) {
			return der.NewProtoFromSpec(spec)
		}))

	reflection.Register(grpcServer)
	grpc_prometheus.Register(grpcServer)
	grpc_prometheus.EnableHandlingTimeHistogram()

	// Run servers
	g, gctx := errgroup.WithContext(ctx)
	g.Go(func() error { return serverutil.ServeHTTPMetrics(*metricsAddr, serverutil.Readyz(sqldb)) })
	g.Go(func() error {
		return serverutil.ServeHTTPAPIAndGRPC(gctx, lis, grpcServer, conn,
			pb.RegisterKeyTransparencyAdminHandler)
	})
	go runSequencer(gctx, conn, directoryStorage)

	glog.Errorf("Signer exiting: %v", g.Wait())
}

func runSequencer(ctx context.Context, conn *grpc.ClientConn, directoryStorage dir.Storage) {
	glog.Infof("Sequencer starting")
	electionFactory, closeFactory := getElectionFactory()
	defer closeFactory()
	signer := sequencer.New(
		spb.NewKeyTransparencySequencerClient(conn),
		directoryStorage,
		election.NewTracker(electionFactory, 1*time.Hour, prometheus.MetricFactory{}),
	)

	go signer.TrackMasterships(ctx)

	go sequencer.PeriodicallyRun(ctx, time.Tick(*refresh), func(ctx context.Context) {
		if err := signer.ForAllMasterships(ctx, func(ctx context.Context, dirID string) error {
			_, err := spb.NewKeyTransparencySequencerClient(conn).
				EstimateBacklog(ctx, &spb.EstimateBacklogRequest{
					DirectoryId:       dirID,
					MaxUnappliedCount: 100000,
				})
			return err
		}); err != nil {
			glog.Errorf("UpdateMetrics(): %v", err)
		}
	})

	if err := signer.AddAllDirectories(ctx); err != nil {
		glog.Errorf("runSequencer(AddAllDirectories): %v", err)
	}
	go sequencer.PeriodicallyRun(ctx, time.Tick(*dirRefresh), func(ctx context.Context) {
		if err := signer.AddAllDirectories(ctx); err != nil {
			glog.Errorf("PeriodicallyRun(AddAllDirectories): %v", err)
		}
	})

	go sequencer.PeriodicallyRun(ctx, time.Tick(*refresh), func(ctx context.Context) {
		if err := signer.DefineRevisionsForAllMasterships(ctx, int32(*batchSize)); err != nil {
			glog.Errorf("PeriodicallyRun(DefineRevisionsForAllMasterships): %v", err)
		}
	})
	go sequencer.PeriodicallyRun(ctx, time.Tick(*refresh), func(ctx context.Context) {
		if err := signer.ApplyRevisionsForAllMasterships(ctx); err != nil {
			glog.Errorf("PeriodicallyRun(ApplyRevisionsForAllMasterships): %v", err)
		}
	})

	go sequencer.PeriodicallyRun(ctx, time.Tick(*refresh), func(ctx context.Context) {
		if err := signer.PublishLogForAllMasterships(ctx); err != nil {
			glog.Errorf("PeriodicallyRun(PublishRevisionsForAllMasterships): %v", err)
		}
	})

	<-ctx.Done() // Block until server exit.
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math/big"
	"net/url"
	"os"
	"strconv"
	"strings"
	"text/tabwriter"

	ethcommon "github.com/ethereum/go-ethereum/common"
	"github.com/golang/glog"
	lpcommon "github.com/livepeer/go-livepeer/common"
	"github.com/livepeer/go-livepeer/eth/types"
)

const defaultRPCPort = "8935"

func (w *wizard) isOrchestrator() bool {
	isT := httpGet(fmt.Sprintf("http://%v:%v/IsOrchestrator", w.host, w.httpPort))
	return isT == "true"
}

func myHostPort() string {
	// TODO Fall back to try other services if this one fails. Ask a peer?
	// 	http://myexternalip.com
	// 	http://api.ident.me
	// 	http://whatismyipaddress.com/api
	// 	http://ipinfo.io/ip
	ip := strings.TrimSpace(httpGet("https://api.ipify.org/?format=text"))
	return ip + ":" + defaultRPCPort
}

func (w *wizard) promptOrchestratorConfig() (float64, float64, int, int, string) {
	var (
		blockRewardCut float64
		feeShare       float64
	)

	fmt.Printf("Enter block reward cut percentage (default: 10) - ")
	blockRewardCut = w.readDefaultFloat(10.0)

	fmt.Printf("Enter fee share percentage (default: 5) - ")
	feeShare = w.readDefaultFloat(5.0)

	fmt.Println("Enter a transcoding base price in wei per pixels")
	fmt.Println("eg. 1 wei / 10 pixels = 0,1 wei per pixel")
	fmt.Println()
	fmt.Printf("Enter amount of pixels that make up a single unit (default: 1 pixel) ")
	pixelsPerUnit := w.readDefaultInt(1)
	fmt.Printf("Enter the price for %d pixels in Wei (required) ", pixelsPerUnit)
	pricePerUnit := w.readDefaultInt(0)

	addr := myHostPort()
	fmt.Printf("Enter the public host:port of node (default: %v)", addr)
	serviceURI := w.readStringAndValidate(func(in string) (string, error) {
		if "" == in {
			in = addr
		}
		in = "https://" + in
		uri, err := url.ParseRequestURI(in)
		if err != nil {
			return "", err
		}
		if uri.Port() == "" {
			return "", fmt.Errorf("Missing Port")
		}
		return in, nil
	})

	return blockRewardCut, feeShare, pricePerUnit, pixelsPerUnit, serviceURI
}

func (w *wizard) activateOrchestrator() {
	d, err := w.getDelegatorInfo()
	if err != nil {
		glog.Errorf("Error getting delegator info: %v", err)
		return
	}

	fmt.Printf("Current token balance: %v\n", w.getTokenBalance())
	fmt.Printf("Current bonded amount: %v\n", d.BondedAmount.String())

	val := w.getOrchestratorConfigFormValues()

	if d.BondedAmount.Cmp(big.NewInt(0)) <= 0 || d.DelegateAddress != d.Address {
		fmt.Printf("You must bond to yourself in order to become a orchestrator\n")

		rebond := false

		unbondingLockIDs := w.unbondingLockStats(false)
		if unbondingLockIDs != nil && len(unbondingLockIDs) > 0 {
			fmt.Printf("You have some unbonding locks. Would you like to use one to rebond to yourself? (y/n) - ")

			input := ""
			for {
				input = w.readString()
				if input == "y" || input == "n" {
					break
				}
				fmt.Printf("Enter (y)es or (n)o\n")
			}

			if input == "y" {
				rebond = true

				unbondingLockID := int64(-1)

				for {
					fmt.Printf("Enter the identifier of the unbonding lock you would like to rebond to yourself with - ")
					unbondingLockID = int64(w.readInt())
					if _, ok := unbondingLockIDs[unbondingLockID]; ok {
						break
					}
					fmt.Printf("Must enter a valid unbonding lock ID\n")
				}

				val["unbondingLockId"] = []string{fmt.Sprintf("%v", strconv.FormatInt(unbondingLockID, 10))}
			}
		}

		if !rebond {
			balBigInt, err := lpcommon.ParseBigInt(w.getTokenBalance())
			if err != nil {
				fmt.Printf("Cannot read token balance: %v", w.getTokenBalance())
				return
			}

			amount := big.NewInt(0)
			for amount.Cmp(big.NewInt(0)) == 0 || balBigInt.Cmp(amount) < 0 {
				fmt.Printf("Enter bond amount - ")
				amount = w.readBigInt()
				if balBigInt.Cmp(amount) < 0 {
					fmt.Printf("Must enter an amount smaller than the current balance. ")
				}
				if amount.Cmp(big.NewInt(0)) == 0 && d.BondedAmount.Cmp(big.NewInt(0)) > 0 {
					break
				}
			}

			val["amount"] = []string{fmt.Sprintf("%v", amount.String())}
		}
	}

	httpPostWithParams(fmt.Sprintf("http://%v:%v/activateOrchestrator", w.host, w.httpPort), val)
	// TODO we should confirm if the transaction was actually sent
	fmt.Println("\nTransaction sent. Once confirmed, please restart your node.")
}

func (w *wizard) setOrchestratorConfig() {
	fmt.Printf("Current token balance: %v\n", w.getTokenBalance())

	val := w.getOrchestratorConfigFormValues()

	httpPostWithParams(fmt.Sprintf("http://%v:%v/setOrchestratorConfig", w.host, w.httpPort), val)
	// TODO we should confirm if the transaction was actually sent
	fmt.Println("\nTransaction sent. Once confirmed, please restart your node if the ServiceURI has been reset")
}

func (w *wizard) getOrchestratorConfigFormValues() url.Values {
	blockRewardCut, feeShare, pricePerUnit, pixelsPerUnit, serviceURI := w.promptOrchestratorConfig()

	return url.Values{
		"blockRewardCut": {fmt.Sprintf("%v", blockRewardCut)},
		"feeShare":       {fmt.Sprintf("%v", feeShare)},
		"pricePerUnit":   {fmt.Sprintf("%v", strconv.Itoa(pricePerUnit))},
		"pixelsPerUnit":  {fmt.Sprintf("%v", strconv.Itoa(pixelsPerUnit))},
		"serviceURI":     {fmt.Sprintf("%v", serviceURI)},
	}
}

func (w *wizard) callReward() {
	t, _, err := w.getOrchestratorInfo()
	if err != nil {
		fmt.Printf("Error getting orchestrator info: %v\n", err)
		return
	}
	c, err := w.currentRound()
	if err != nil {
		fmt.Printf("Error converting current round: %v\n", c)
	}

	if c.Cmp(t.LastRewardRound) == 0 {
		fmt.Printf("Reward for current round %v already called\n", c)
		return
	}

	fmt.Printf("Calling reward for round %v\n", c)
	httpGet(fmt.Sprintf("http://%v:%v/reward", w.host, w.httpPort))
}

func (w *wizard) vote() {
	if w.offchain {
		glog.Error("Can not vote in 'offchain' mode")
		return
	}

	fmt.Print("Enter the contract address for the poll you want to vote in -")
	poll := w.readStringAndValidate(func(in string) (string, error) {
		if !ethcommon.IsHexAddress(in) {
			return "", fmt.Errorf("invalid hex address address=%v", in)
		}
		return in, nil
	})

	var (
		confirm = "n"
		choice  = types.VoteChoice(-1)
	)

	for confirm == "n" {
		choice = types.VoteChoice(-1)
		w.showVoteChoices()

		for {
			fmt.Printf("Enter the ID of the choice you want to vote for -")
			choice = types.VoteChoice(w.readInt())
			if choice.IsValid() {
				break
			}
			fmt.Println("Must enter a valid ID")
		}

		fmt.Printf("Are you sure you want to vote \"%v\"? (y/n) -", choice.String())
		confirm = w.readStringYesOrNo()
	}

	data := url.Values{
		"poll":     {poll},
		"choiceID": {fmt.Sprintf("%v", int(choice))},
	}

	result := httpPostWithParams(fmt.Sprintf("http://%v:%v/vote", w.host, w.httpPort), data)

	if result == "" {
		fmt.Println("vote failed")
		return
	}

	fmt.Printf("\nVote success tx=0x%x\n", []byte(result))
}

func (w *wizard) showVoteChoices() {
	wtr := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
	fmt.Fprintln(wtr, "Identifier\tVoting Choices")
	for _, choice := range types.VoteChoices {
		fmt.Fprintf(wtr, "%v\t%v\n", int(choice), choice.String())
	}
	wtr.Flush()
}
<commit_msg>cmd: show current feeshare and rewardcut when setting orch config<commit_after>package main

import (
	"fmt"
	"math/big"
	"net/url"
	"os"
	"strconv"
	"strings"
	"text/tabwriter"

	ethcommon "github.com/ethereum/go-ethereum/common"
	"github.com/golang/glog"
	lpcommon "github.com/livepeer/go-livepeer/common"
	"github.com/livepeer/go-livepeer/eth"
	"github.com/livepeer/go-livepeer/eth/types"
)

const defaultRPCPort = "8935"

func (w *wizard) isOrchestrator() bool {
	isT := httpGet(fmt.Sprintf("http://%v:%v/IsOrchestrator", w.host, w.httpPort))
	return isT == "true"
}

func myHostPort() string {
	// TODO Fall back to try other services if this one fails. Ask a peer?
	// 	http://myexternalip.com
	// 	http://api.ident.me
	// 	http://whatismyipaddress.com/api
	// 	http://ipinfo.io/ip
	ip := strings.TrimSpace(httpGet("https://api.ipify.org/?format=text"))
	return ip + ":" + defaultRPCPort
}

func (w *wizard) promptOrchestratorConfig() (float64, float64, int, int, string) {
	var (
		blockRewardCut float64
		feeShare       float64
	)

	orch, _, err := w.getOrchestratorInfo()
	if err != nil || orch == nil {
		fmt.Println("unable to get current reward cut and fee share")
		blockRewardCut = 0
		feeShare = 0
	}

	blockRewardCut = eth.ToPerc(orch.RewardCut)
	feeShare = eth.ToPerc(orch.FeeShare)

	fmt.Printf("Enter block reward cut percentage (current=%v default=10) - ", blockRewardCut)
	blockRewardCut = w.readDefaultFloat(blockRewardCut)

	fmt.Printf("Enter fee share percentage (current=%v default=5) - ", feeShare)
	feeShare = w.readDefaultFloat(eth.ToPerc(orch.FeeShare))

	fmt.Println("Enter a transcoding base price in wei per pixels")
	fmt.Println("eg. 1 wei / 10 pixels = 0,1 wei per pixel")
	fmt.Println()
	fmt.Printf("Enter amount of pixels that make up a single unit (default: 1 pixel) ")
	pixelsPerUnit := w.readDefaultInt(1)
	fmt.Printf("Enter the price for %d pixels in Wei (required) ", pixelsPerUnit)
	pricePerUnit := w.readDefaultInt(0)

	addr := myHostPort()
	fmt.Printf("Enter the public host:port of node (default: %v)", addr)
	serviceURI := w.readStringAndValidate(func(in string) (string, error) {
		if "" == in {
			in = addr
		}
		in = "https://" + in
		uri, err := url.ParseRequestURI(in)
		if err != nil {
			return "", err
		}
		if uri.Port() == "" {
			return "", fmt.Errorf("Missing Port")
		}
		return in, nil
	})

	return blockRewardCut, feeShare, pricePerUnit, pixelsPerUnit, serviceURI
}

func (w *wizard) activateOrchestrator() {
	d, err := w.getDelegatorInfo()
	if err != nil {
		glog.Errorf("Error getting delegator info: %v", err)
		return
	}

	fmt.Printf("Current token balance: %v\n", w.getTokenBalance())
	fmt.Printf("Current bonded amount: %v\n", d.BondedAmount.String())

	val := w.getOrchestratorConfigFormValues()

	if d.BondedAmount.Cmp(big.NewInt(0)) <= 0 || d.DelegateAddress != d.Address {
		fmt.Printf("You must bond to yourself in order to become a orchestrator\n")

		rebond := false

		unbondingLockIDs := w.unbondingLockStats(false)
		if unbondingLockIDs != nil && len(unbondingLockIDs) > 0 {
			fmt.Printf("You have some unbonding locks. Would you like to use one to rebond to yourself? (y/n) - ")

			input := ""
			for {
				input = w.readString()
				if input == "y" || input == "n" {
					break
				}
				fmt.Printf("Enter (y)es or (n)o\n")
			}

			if input == "y" {
				rebond = true

				unbondingLockID := int64(-1)

				for {
					fmt.Printf("Enter the identifier of the unbonding lock you would like to rebond to yourself with - ")
					unbondingLockID = int64(w.readInt())
					if _, ok := unbondingLockIDs[unbondingLockID]; ok {
						break
					}
					fmt.Printf("Must enter a valid unbonding lock ID\n")
				}

				val["unbondingLockId"] = []string{fmt.Sprintf("%v", strconv.FormatInt(unbondingLockID, 10))}
			}
		}

		if !rebond {
			balBigInt, err := lpcommon.ParseBigInt(w.getTokenBalance())
			if err != nil {
				fmt.Printf("Cannot read token balance: %v", w.getTokenBalance())
				return
			}

			amount := big.NewInt(0)
			for amount.Cmp(big.NewInt(0)) == 0 || balBigInt.Cmp(amount) < 0 {
				fmt.Printf("Enter bond amount - ")
				amount = w.readBigInt()
				if balBigInt.Cmp(amount) < 0 {
					fmt.Printf("Must enter an amount smaller than the current balance. ")
				}
				if amount.Cmp(big.NewInt(0)) == 0 && d.BondedAmount.Cmp(big.NewInt(0)) > 0 {
					break
				}
			}

			val["amount"] = []string{fmt.Sprintf("%v", amount.String())}
		}
	}

	httpPostWithParams(fmt.Sprintf("http://%v:%v/activateOrchestrator", w.host, w.httpPort), val)
	// TODO we should confirm if the transaction was actually sent
	fmt.Println("\nTransaction sent. Once confirmed, please restart your node.")
}

func (w *wizard) setOrchestratorConfig() {
	fmt.Printf("Current token balance: %v\n", w.getTokenBalance())

	val := w.getOrchestratorConfigFormValues()

	httpPostWithParams(fmt.Sprintf("http://%v:%v/setOrchestratorConfig", w.host, w.httpPort), val)
	// TODO we should confirm if the transaction was actually sent
	fmt.Println("\nTransaction sent. Once confirmed, please restart your node if the ServiceURI has been reset")
}

func (w *wizard) getOrchestratorConfigFormValues() url.Values {
	blockRewardCut, feeShare, pricePerUnit, pixelsPerUnit, serviceURI := w.promptOrchestratorConfig()

	return url.Values{
		"blockRewardCut": {fmt.Sprintf("%v", blockRewardCut)},
		"feeShare":       {fmt.Sprintf("%v", feeShare)},
		"pricePerUnit":   {fmt.Sprintf("%v", strconv.Itoa(pricePerUnit))},
		"pixelsPerUnit":  {fmt.Sprintf("%v", strconv.Itoa(pixelsPerUnit))},
		"serviceURI":     {fmt.Sprintf("%v", serviceURI)},
	}
}

func (w *wizard) callReward() {
	t, _, err := w.getOrchestratorInfo()
	if err != nil {
		fmt.Printf("Error getting orchestrator info: %v\n", err)
		return
	}
	c, err := w.currentRound()
	if err != nil {
		fmt.Printf("Error converting current round: %v\n", c)
	}

	if c.Cmp(t.LastRewardRound) == 0 {
		fmt.Printf("Reward for current round %v already called\n", c)
		return
	}

	fmt.Printf("Calling reward for round %v\n", c)
	httpGet(fmt.Sprintf("http://%v:%v/reward", w.host, w.httpPort))
}

func (w *wizard) vote() {
	if w.offchain {
		glog.Error("Can not vote in 'offchain' mode")
		return
	}

	fmt.Print("Enter the contract address for the poll you want to vote in -")
	poll := w.readStringAndValidate(func(in string) (string, error) {
		if !ethcommon.IsHexAddress(in) {
			return "", fmt.Errorf("invalid hex address address=%v", in)
		}
		return in, nil
	})

	var (
		confirm = "n"
		choice  = types.VoteChoice(-1)
	)

	for confirm == "n" {
		choice = types.VoteChoice(-1)
		w.showVoteChoices()

		for {
			fmt.Printf("Enter the ID of the choice you want to vote for -")
			choice = types.VoteChoice(w.readInt())
			if choice.IsValid() {
				break
			}
			fmt.Println("Must enter a valid ID")
		}

		fmt.Printf("Are you sure you want to vote \"%v\"? (y/n) -", choice.String())
		confirm = w.readStringYesOrNo()
	}

	data := url.Values{
		"poll":     {poll},
		"choiceID": {fmt.Sprintf("%v", int(choice))},
	}

	result := httpPostWithParams(fmt.Sprintf("http://%v:%v/vote", w.host, w.httpPort), data)

	if result == "" {
		fmt.Println("vote failed")
		return
	}

	fmt.Printf("\nVote success tx=0x%x\n", []byte(result))
}

func (w *wizard) showVoteChoices() {
	wtr := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
	fmt.Fprintln(wtr, "Identifier\tVoting Choices")
	for _, choice := range types.VoteChoices {
		fmt.Fprintf(wtr, "%v\t%v\n", int(choice), choice.String())
	}
	wtr.Flush()
}
<|endoftext|>