<commit_before>// Copyright 2016 Andrew O'Neill, Nordstrom

// 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 (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"net/http/pprof"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/Nordstrom/choices"
	"github.com/foolusion/elwinprotos/elwin"
	"github.com/grpc-ecosystem/go-grpc-prometheus"
	"github.com/pkg/errors"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/spf13/viper"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/selection"
)

var (
	requestDurations = prometheus.NewHistogram(prometheus.HistogramOpts{
		Namespace: "nordstrom",
		Subsystem: "elwin",
		Name:      "request_durations_nanoseconds",
		Help:      "request latency distributions.",
		Buckets:   prometheus.ExponentialBuckets(1, 10, 10),
	})
	updateErrors = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: "nordstrom",
		Subsystem: "elwin",
		Name:      "update_errors",
		Help:      "The number of errors while updating storage.",
	})
)

const (
	cfgStorageAddr = "storage_address"
	cfgJSONAddr    = "json_address"
	cfgGRPCAddr    = "grpc_address"
	cfgUInterval   = "update_interval"
	cfgRTimeout    = "read_timeout"
	cfgWTimeout    = "write_timeout"
	cfgITimeout    = "idle_timeout"
	cfgUFTimeout   = "update_fail_timeout"
	cfgProf        = "profiler"
)

func bind(s []string) error {
	if len(s) == 0 {
		return nil
	}
	if err := viper.BindEnv(s[0]); err != nil {
		return err
	}
	return bind(s[1:])
}

func main() {
	log.Println("Starting elwin...")

	viper.SetDefault(cfgStorageAddr, "elwin-storage:80")
	viper.SetDefault(cfgJSONAddr, ":8080")
	viper.SetDefault(cfgGRPCAddr, ":8081")
	viper.SetDefault(cfgUInterval, "10s")
	viper.SetDefault(cfgRTimeout, "5s")
	viper.SetDefault(cfgWTimeout, "5s")
	viper.SetDefault(cfgITimeout, "30s")
	viper.SetDefault(cfgUFTimeout, "15m")

	viper.SetConfigName("config")
	viper.AddConfigPath(".")
	viper.AddConfigPath("/etc/elwin")
	err := viper.ReadInConfig()
	if err != nil {
		switch err.(type) {
		case viper.ConfigFileNotFoundError:
			log.Println("no config file found")
		default:
			log.Fatalf("could not read config: %v", err)
		}
	}

	viper.SetEnvPrefix("elwin")
	if err := bind([]string{
		cfgStorageAddr,
		cfgJSONAddr,
		cfgGRPCAddr,
		cfgUInterval,
		cfgRTimeout,
		cfgWTimeout,
		cfgITimeout,
		cfgUFTimeout,
		"profiler",
	}); err != nil {
		log.Fatal(err)
	}

	// create elwin config
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	var interval, failTimeout time.Duration
	if ui, err := time.ParseDuration(viper.GetString(cfgUInterval)); err != nil {
		log.Fatal(err)
	} else if muft, err := time.ParseDuration(viper.GetString(cfgUFTimeout)); err != nil {
		log.Fatal(err)
	} else {
		interval, failTimeout = ui, muft
	}

	ec, err := choices.NewChoices(
		ctx,
		choices.WithGlobalSalt("choices"),
		choices.WithStorageConfig(viper.GetString(cfgStorageAddr), interval),
		choices.WithUpdateInterval(interval),
		choices.WithMaxUpdateFailTime(failTimeout),
	)
	if err != nil {
		log.Fatal(err)
	}

	lgrpc, err := net.Listen("tcp", viper.GetString(cfgGRPCAddr))
	if err != nil {
		ec.ErrChan <- fmt.Errorf("main: failed to listen: %v", err)
		return
	}
	defer lgrpc.Close()
	log.Printf("Listening for grpc on %s", viper.GetString(cfgGRPCAddr))

	grpcServer := grpc.NewServer(
		grpc.UnaryInterceptor(grpc_prometheus.UnaryServerInterceptor),
	)
	grpc_prometheus.Register(grpcServer)
	e := &elwinServer{ec}
	elwin.RegisterElwinServer(grpcServer, e)
	go func() {
		ec.ErrChan <- grpcServer.Serve(lgrpc)
	}()

	// register prometheus metrics
	prometheus.MustRegister(updateErrors)
	prometheus.MustRegister(requestDurations)

	ljson, err := net.Listen("tcp", viper.GetString(cfgJSONAddr))
	if err != nil {
		log.Fatalf("could not listen on %s: %v", viper.GetString(cfgJSONAddr), err)
	}
	defer ljson.Close()
	log.Printf("Listening for json on %s", viper.GetString(cfgJSONAddr))

	mux := http.NewServeMux()
	mux.HandleFunc("/healthz", healthzHandler(map[string]interface{}{"storage": ec}))
	mux.HandleFunc("/readiness", healthzHandler(map[string]interface{}{"storage": ec}))
	mux.HandleFunc("/elwin/v1/experiments", e.json)
	mux.Handle("/metrics", promhttp.Handler())
	if viper.IsSet(cfgProf) {
		mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
	}
	srv := http.Server{
		Handler: mux,
	}
	if rt, err := time.ParseDuration(viper.GetString(cfgRTimeout)); err != nil {
		log.Fatal(err)
	} else if wt, err := time.ParseDuration(viper.GetString(cfgWTimeout)); err != nil {
		log.Fatal(err)
	} else if it, err := time.ParseDuration(viper.GetString(cfgITimeout)); err != nil {
		log.Fatal(err)
	} else {
		srv.ReadTimeout = rt
		srv.WriteTimeout = wt
		srv.IdleTimeout = it
	}

	go func() {
		ec.ErrChan <- srv.Serve(ljson)
	}()

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

	for {
		select {
		case err := <-ec.ErrChan:
			switch errors.Cause(err).(type) {
			case choices.ErrUpdateStorage:
				updateErrors.Inc()
			}
			log.Println(err)
		case s := <-signalChan:
			log.Printf("Captured %v. Exitting...", s)
			cancel()
			ctx, sdcancel := context.WithTimeout(context.Background(), 5*time.Second)
			defer sdcancel()
			srv.Shutdown(ctx)
			// send StatusServiceUnavailable to new requestors
			// block server from accepting new requests
			os.Exit(0)
		}
	}
}

type elwinServer struct {
	*choices.Config
}

func (e *elwinServer) Get(ctx context.Context, r *elwin.GetRequest) (*elwin.GetReply, error) {
	start := time.Now()
	defer func() {
		requestDurations.Observe(float64(time.Since(start)))
	}()
	if r == nil {
		return nil, grpc.Errorf(codes.InvalidArgument, "Get: request is nil")
	}
	selector := labels.NewSelector()
	for _, requirement := range r.Requirements {
		var op selection.Operator
		switch requirement.Op {
		case elwin.EXISTS:
			op = selection.Exists
		case elwin.EQUAL:
			op = selection.Equals
		case elwin.NOT_EQUAL:
			op = selection.NotEquals
		case elwin.IN:
			op = selection.In
		case elwin.NOT_IN:
			op = selection.NotIn
		default:
			return nil, errors.New("invalid operator in requirements")
		}
		req, err := labels.NewRequirement(requirement.Key, op, requirement.Values)
		if err != nil {
			return nil, errors.Wrap(err, "could not create requirement")
		}
		selector = selector.Add(*req)
	}

// TODO: replace this with a pool or something similar
	resp := make([]*choices.ExperimentResponse, 0, 100)
 	resp, err := e.Experiments(resp, r.UserID, selector)
	if err != nil {
		return nil, fmt.Errorf("error evaluating experiments for %s, %s: %v", r.Requirements, r.UserID, err)
	}

	if r.By != "" {
		byResp := make(map[string]*elwin.ExperimentList, 10)
		for _, v := range resp {
			if group, ok := v.Labels[r.By]; !ok {
				appendToGroup(byResp, v, "None")
			} else {
				appendToGroup(byResp, v, group)
			}
		}
		return &elwin.GetReply{
			Group: byResp,
		}, nil
	}

	exp := &elwin.GetReply{
		Experiments: make([]*elwin.Experiment, len(resp)),
	}

	for i, v := range resp {
		exp.Experiments[i] = &elwin.Experiment{
			Name:      v.Name,
			Namespace: v.Namespace,
			Labels:    v.Labels,
			Params:    make([]*elwin.Param, len(v.Params)),
		}

		for j, p := range v.Params {
			exp.Experiments[i].Params[j] = &elwin.Param{
				Name:  p.Name,
				Value: p.Value,
			}
		}
	}
	return exp, nil
}

func appendToGroup(br map[string]*elwin.ExperimentList, e *choices.ExperimentResponse, group string) {
	if br[group] == nil {
		br[group] = &elwin.ExperimentList{}
	}
	elist := br[group].Experiments
	ee := &elwin.Experiment{
		Name:      e.Name,
		Namespace: e.Namespace,
		Labels:    e.Labels,
		Params:    make([]*elwin.Param, len(e.Params)),
	}
	for i, p := range e.Params {
		ee.Params[i] = &elwin.Param{
			Name:  p.Name,
			Value: p.Value,
		}
	}
	elist = append(elist, ee)
	br[group].Experiments = elist
}

func (e *elwinServer) json(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method Not Allowed", http.StatusBadRequest)
		return
	}
	defer r.Body.Close()
	dec := json.NewDecoder(r.Body)
	data := new(elwin.GetRequest)
	if err := dec.Decode(data); err != nil {
		http.Error(w, "could not parse json", http.StatusBadRequest)
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
	defer cancel()
	resp, err := e.Get(ctx, data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	enc := json.NewEncoder(w)
	if err := enc.Encode(resp); err != nil {
		http.Error(w, "could not marshal json", http.StatusInternalServerError)
		return
	}
}

func logCloseErr(c io.Closer) {
	if err := c.Close(); err != nil {
		log.Printf("could not close response body: %s", err)
	}
}

func healthzHandler(healthChecks map[string]interface{}) http.HandlerFunc {
	type healthy interface {
		IsHealthy() error
	}

	return func(w http.ResponseWriter, r *http.Request) {
		errs := make(map[string]string, len(healthChecks))
		for key, healthChecker := range healthChecks {
			if hc, ok := healthChecker.(healthy); ok {
				err := hc.IsHealthy()
				if err != nil {
					errs[key] = err.Error()
				}
			}
		}
		if len(errs) != 0 {
			w.WriteHeader(http.StatusInternalServerError)
			w.Header().Set("Content-Type", "application/json")
			enc := json.NewEncoder(w)
			if err := enc.Encode(errs); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			return
		}
		w.WriteHeader(http.StatusOK)
		w.Header().Set("Content-Type", "text/plain")
		if _, err := w.Write([]byte("OK")); err != nil {
			log.Printf("could not write to healthz connection: %s", err)
		}
	}
}
<commit_msg>remove grpc from cmd/elwin<commit_after>// Copyright 2016 Andrew O'Neill, Nordstrom

// 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 (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"net/http/pprof"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/Nordstrom/choices"
	"github.com/foolusion/elwinprotos/elwin"
	"github.com/pkg/errors"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/spf13/viper"
	"golang.org/x/net/context"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/selection"
)

var (
	requestDurations = prometheus.NewHistogram(prometheus.HistogramOpts{
		Namespace: "nordstrom",
		Subsystem: "elwin",
		Name:      "request_durations_nanoseconds",
		Help:      "request latency distributions.",
		Buckets:   prometheus.ExponentialBuckets(1, 10, 10),
	})
	updateErrors = prometheus.NewCounter(prometheus.CounterOpts{
		Namespace: "nordstrom",
		Subsystem: "elwin",
		Name:      "update_errors",
		Help:      "The number of errors while updating storage.",
	})
)

const (
	cfgStorageAddr = "storage_address"
	cfgJSONAddr    = "json_address"
	cfgGRPCAddr    = "grpc_address"
	cfgUInterval   = "update_interval"
	cfgRTimeout    = "read_timeout"
	cfgWTimeout    = "write_timeout"
	cfgITimeout    = "idle_timeout"
	cfgUFTimeout   = "update_fail_timeout"
	cfgProf        = "profiler"
)

func bind(s []string) error {
	if len(s) == 0 {
		return nil
	}
	if err := viper.BindEnv(s[0]); err != nil {
		return err
	}
	return bind(s[1:])
}

func main() {
	log.Println("Starting elwin...")

	viper.SetDefault(cfgStorageAddr, "elwin-storage:80")
	viper.SetDefault(cfgJSONAddr, ":8080")
	viper.SetDefault(cfgUInterval, "10s")
	viper.SetDefault(cfgRTimeout, "5s")
	viper.SetDefault(cfgWTimeout, "5s")
	viper.SetDefault(cfgITimeout, "30s")
	viper.SetDefault(cfgUFTimeout, "15m")

	viper.SetConfigName("config")
	viper.AddConfigPath(".")
	viper.AddConfigPath("/etc/elwin")
	err := viper.ReadInConfig()
	if err != nil {
		switch err.(type) {
		case viper.ConfigFileNotFoundError:
			log.Println("no config file found")
		default:
			log.Fatalf("could not read config: %v", err)
		}
	}

	viper.SetEnvPrefix("elwin")
	if err := bind([]string{
		cfgStorageAddr,
		cfgJSONAddr,
		cfgUInterval,
		cfgRTimeout,
		cfgWTimeout,
		cfgITimeout,
		cfgUFTimeout,
		"profiler",
	}); err != nil {
		log.Fatal(err)
	}

	// create elwin config
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	var interval, failTimeout time.Duration
	if ui, err := time.ParseDuration(viper.GetString(cfgUInterval)); err != nil {
		log.Fatal(err)
	} else if muft, err := time.ParseDuration(viper.GetString(cfgUFTimeout)); err != nil {
		log.Fatal(err)
	} else {
		interval, failTimeout = ui, muft
	}

	ec, err := choices.NewChoices(
		ctx,
		choices.WithGlobalSalt("choices"),
		choices.WithStorageConfig(viper.GetString(cfgStorageAddr), interval),
		choices.WithUpdateInterval(interval),
		choices.WithMaxUpdateFailTime(failTimeout),
	)
	if err != nil {
		log.Fatal(err)
	}

	e := &elwinServer{ec}

	// register prometheus metrics
	prometheus.MustRegister(updateErrors)
	prometheus.MustRegister(requestDurations)

	ljson, err := net.Listen("tcp", viper.GetString(cfgJSONAddr))
	if err != nil {
		log.Fatalf("could not listen on %s: %v", viper.GetString(cfgJSONAddr), err)
	}
	defer ljson.Close()
	log.Printf("Listening for json on %s", viper.GetString(cfgJSONAddr))

	mux := http.NewServeMux()
	mux.HandleFunc("/healthz", healthzHandler(map[string]interface{}{"storage": ec}))
	mux.HandleFunc("/readiness", healthzHandler(map[string]interface{}{"storage": ec}))
	mux.HandleFunc("/elwin/v1/experiments", e.json)
	mux.Handle("/metrics", promhttp.Handler())
	if viper.IsSet(cfgProf) {
		mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
	}
	srv := http.Server{
		Handler: mux,
	}
	if rt, err := time.ParseDuration(viper.GetString(cfgRTimeout)); err != nil {
		log.Fatal(err)
	} else if wt, err := time.ParseDuration(viper.GetString(cfgWTimeout)); err != nil {
		log.Fatal(err)
	} else if it, err := time.ParseDuration(viper.GetString(cfgITimeout)); err != nil {
		log.Fatal(err)
	} else {
		srv.ReadTimeout = rt
		srv.WriteTimeout = wt
		srv.IdleTimeout = it
	}

	go func() {
		ec.ErrChan <- srv.Serve(ljson)
	}()

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

	for {
		select {
		case err := <-ec.ErrChan:
			switch errors.Cause(err).(type) {
			case choices.ErrUpdateStorage:
				updateErrors.Inc()
			}
			log.Println(err)
		case s := <-signalChan:
			log.Printf("Captured %v. Exitting...", s)
			cancel()
			ctx, sdcancel := context.WithTimeout(context.Background(), 5*time.Second)
			defer sdcancel()
			srv.Shutdown(ctx)
			// send StatusServiceUnavailable to new requestors
			// block server from accepting new requests
			os.Exit(0)
		}
	}
}

type elwinServer struct {
	*choices.Config
}

func (e *elwinServer) Get(ctx context.Context, r *elwin.GetRequest) (*elwin.GetReply, error) {
	start := time.Now()
	defer func() {
		requestDurations.Observe(float64(time.Since(start)))
	}()
	/*if r == nil {
		return nil, grpc.Errorf(codes.InvalidArgument, "Get: request is nil")
	}*/
	selector := labels.NewSelector()
	for _, requirement := range r.Requirements {
		var op selection.Operator
		switch requirement.Op {
		case elwin.EXISTS:
			op = selection.Exists
		case elwin.EQUAL:
			op = selection.Equals
		case elwin.NOT_EQUAL:
			op = selection.NotEquals
		case elwin.IN:
			op = selection.In
		case elwin.NOT_IN:
			op = selection.NotIn
		default:
			return nil, errors.New("invalid operator in requirements")
		}
		req, err := labels.NewRequirement(requirement.Key, op, requirement.Values)
		if err != nil {
			return nil, errors.Wrap(err, "could not create requirement")
		}
		selector = selector.Add(*req)
	}

	// TODO: replace this with a pool or something similar
	resp := make([]*choices.ExperimentResponse, 0, 100)
	resp, err := e.Experiments(resp, r.UserID, selector)
	if err != nil {
		return nil, fmt.Errorf("error evaluating experiments for %s, %s: %v", r.Requirements, r.UserID, err)
	}

	if r.By != "" {
		byResp := make(map[string]*elwin.ExperimentList, 10)
		for _, v := range resp {
			if group, ok := v.Labels[r.By]; !ok {
				appendToGroup(byResp, v, "None")
			} else {
				appendToGroup(byResp, v, group)
			}
		}
		return &elwin.GetReply{
			Group: byResp,
		}, nil
	}

	exp := &elwin.GetReply{
		Experiments: make([]*elwin.Experiment, len(resp)),
	}

	for i, v := range resp {
		exp.Experiments[i] = &elwin.Experiment{
			Name:      v.Name,
			Namespace: v.Namespace,
			Labels:    v.Labels,
			Params:    make([]*elwin.Param, len(v.Params)),
		}

		for j, p := range v.Params {
			exp.Experiments[i].Params[j] = &elwin.Param{
				Name:  p.Name,
				Value: p.Value,
			}
		}
	}
	return exp, nil
}

func appendToGroup(br map[string]*elwin.ExperimentList, e *choices.ExperimentResponse, group string) {
	if br[group] == nil {
		br[group] = &elwin.ExperimentList{}
	}
	elist := br[group].Experiments
	ee := &elwin.Experiment{
		Name:      e.Name,
		Namespace: e.Namespace,
		Labels:    e.Labels,
		Params:    make([]*elwin.Param, len(e.Params)),
	}
	for i, p := range e.Params {
		ee.Params[i] = &elwin.Param{
			Name:  p.Name,
			Value: p.Value,
		}
	}
	elist = append(elist, ee)
	br[group].Experiments = elist
}

func (e *elwinServer) json(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Method Not Allowed", http.StatusBadRequest)
		return
	}
	defer r.Body.Close()
	dec := json.NewDecoder(r.Body)
	data := new(elwin.GetRequest)
	if err := dec.Decode(data); err != nil {
		http.Error(w, "could not parse json", http.StatusBadRequest)
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
	defer cancel()
	resp, err := e.Get(ctx, data)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	enc := json.NewEncoder(w)
	if err := enc.Encode(resp); err != nil {
		http.Error(w, "could not marshal json", http.StatusInternalServerError)
		return
	}
}

func logCloseErr(c io.Closer) {
	if err := c.Close(); err != nil {
		log.Printf("could not close response body: %s", err)
	}
}

func healthzHandler(healthChecks map[string]interface{}) http.HandlerFunc {
	type healthy interface {
		IsHealthy() error
	}

	return func(w http.ResponseWriter, r *http.Request) {
		errs := make(map[string]string, len(healthChecks))
		for key, healthChecker := range healthChecks {
			if hc, ok := healthChecker.(healthy); ok {
				err := hc.IsHealthy()
				if err != nil {
					errs[key] = err.Error()
				}
			}
		}
		if len(errs) != 0 {
			w.WriteHeader(http.StatusInternalServerError)
			w.Header().Set("Content-Type", "application/json")
			enc := json.NewEncoder(w)
			if err := enc.Encode(errs); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			return
		}
		w.WriteHeader(http.StatusOK)
		w.Header().Set("Content-Type", "text/plain")
		if _, err := w.Write([]byte("OK")); err != nil {
			log.Printf("could not write to healthz connection: %s", err)
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright The Helm Authors.

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

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

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

package main

import (
	"flag"
	"fmt"
	"log"
	"path/filepath"
	"sort"
	"strings"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	"k8s.io/klog/v2"

	"helm.sh/helm/v3/pkg/action"
	"helm.sh/helm/v3/pkg/cli/output"
	"helm.sh/helm/v3/pkg/cli/values"
	"helm.sh/helm/v3/pkg/helmpath"
	"helm.sh/helm/v3/pkg/postrender"
	"helm.sh/helm/v3/pkg/repo"
)

const (
	outputFlag         = "output"
	postRenderFlag     = "post-renderer"
	postRenderArgsFlag = "post-renderer-args"
)

func addValueOptionsFlags(f *pflag.FlagSet, v *values.Options) {
	f.StringSliceVarP(&v.ValueFiles, "values", "f", []string{}, "specify values in a YAML file or a URL (can specify multiple)")
	f.StringArrayVar(&v.Values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
	f.StringArrayVar(&v.StringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
	f.StringArrayVar(&v.FileValues, "set-file", []string{}, "set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)")
}

func addChartPathOptionsFlags(f *pflag.FlagSet, c *action.ChartPathOptions) {
	f.StringVar(&c.Version, "version", "", "specify a version constraint for the chart version to use. This constraint can be a specific tag (e.g. 1.1.1) or it may reference a valid range (e.g. ^2.0.0). If this is not specified, the latest version is used")
	f.BoolVar(&c.Verify, "verify", false, "verify the package before using it")
	f.StringVar(&c.Keyring, "keyring", defaultKeyring(), "location of public keys used for verification")
	f.StringVar(&c.RepoURL, "repo", "", "chart repository url where to locate the requested chart")
	f.StringVar(&c.Username, "username", "", "chart repository username where to locate the requested chart")
	f.StringVar(&c.Password, "password", "", "chart repository password where to locate the requested chart")
	f.StringVar(&c.CertFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
	f.StringVar(&c.KeyFile, "key-file", "", "identify HTTPS client using this SSL key file")
	f.BoolVar(&c.InsecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the chart download")
	f.StringVar(&c.CaFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
	f.BoolVar(&c.PassCredentialsAll, "pass-credentials", false, "pass credentials to all domains")
}

// bindOutputFlag will add the output flag to the given command and bind the
// value to the given format pointer
func bindOutputFlag(cmd *cobra.Command, varRef *output.Format) {
	cmd.Flags().VarP(newOutputValue(output.Table, varRef), outputFlag, "o",
		fmt.Sprintf("prints the output in the specified format. Allowed values: %s", strings.Join(output.Formats(), ", ")))

	err := cmd.RegisterFlagCompletionFunc(outputFlag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
		var formatNames []string
		for format, desc := range output.FormatsWithDesc() {
			if strings.HasPrefix(format, toComplete) {
				formatNames = append(formatNames, fmt.Sprintf("%s\t%s", format, desc))
			}
		}

		// Sort the results to get a deterministic order for the tests
		sort.Strings(formatNames)
		return formatNames, cobra.ShellCompDirectiveNoFileComp
	})

	if err != nil {
		log.Fatal(err)
	}
}

type outputValue output.Format

func newOutputValue(defaultValue output.Format, p *output.Format) *outputValue {
	*p = defaultValue
	return (*outputValue)(p)
}

func (o *outputValue) String() string {
	// It is much cleaner looking (and technically less allocations) to just
	// convert to a string rather than type asserting to the underlying
	// output.Format
	return string(*o)
}

func (o *outputValue) Type() string {
	return "format"
}

func (o *outputValue) Set(s string) error {
	outfmt, err := output.ParseFormat(s)
	if err != nil {
		return err
	}
	*o = outputValue(outfmt)
	return nil
}

func bindPostRenderFlag(cmd *cobra.Command, varRef *postrender.PostRenderer) {
	p := &postRendererOptions{varRef, "", []string{}}
	cmd.Flags().Var(&postRendererString{p}, postRenderFlag, "the path to an executable to be used for post rendering. If it exists in $PATH, the binary will be used, otherwise it will try to look for the executable at the given path")
	cmd.Flags().Var(&postRendererArgsSlice{p}, postRenderArgsFlag, "an argument to the post-renderer (can specify multiple)")
}

type postRendererOptions struct {
	renderer   *postrender.PostRenderer
	binaryPath string
	args       []string
}

type postRendererString struct {
	options *postRendererOptions
}

func (p *postRendererString) String() string {
	return p.options.binaryPath
}

func (p *postRendererString) Type() string {
	return "postRendererString"
}

func (p *postRendererString) Set(val string) error {
	if val == "" {
		return nil
	}
	p.options.binaryPath = val
	pr, err := postrender.NewExec(p.options.binaryPath, p.options.args...)
	if err != nil {
		return err
	}
	*p.options.renderer = pr
	return nil
}

type postRendererArgsSlice struct {
	options *postRendererOptions
}

func (p *postRendererArgsSlice) String() string {
	return "[" + strings.Join(p.options.args, ",") + "]"
}

func (p *postRendererArgsSlice) Type() string {
	return "postRendererArgsSlice"
}

func (p *postRendererArgsSlice) Set(val string) error {
	if val == "" {
		return nil
	}

	p.options.args = append(p.options.args, val)

	if p.options.binaryPath == "" {
		return nil
	}
	// overwrite if already create PostRenderer by `post-renderer` flags
	pr, err := postrender.NewExec(p.options.binaryPath, p.options.args...)
	if err != nil {
		return err
	}
	*p.options.renderer = pr
	return nil
}

func (p *postRendererArgsSlice) Append(val string) error {
	p.options.args = append(p.options.args, val)
	return nil
}

func (p *postRendererArgsSlice) Replace(val []string) error {
	p.options.args = val
	return nil
}

func (p *postRendererArgsSlice) GetSlice() []string {
	return p.options.args
}

func compVersionFlag(chartRef string, toComplete string) ([]string, cobra.ShellCompDirective) {
	chartInfo := strings.Split(chartRef, "/")
	if len(chartInfo) != 2 {
		return nil, cobra.ShellCompDirectiveNoFileComp
	}

	repoName := chartInfo[0]
	chartName := chartInfo[1]

	path := filepath.Join(settings.RepositoryCache, helmpath.CacheIndexFile(repoName))

	var versions []string
	if indexFile, err := repo.LoadIndexFile(path); err == nil {
		for _, details := range indexFile.Entries[chartName] {
			version := details.Metadata.Version
			if strings.HasPrefix(version, toComplete) {
				appVersion := details.Metadata.AppVersion
				appVersionDesc := ""
				if appVersion != "" {
					appVersionDesc = fmt.Sprintf("App: %s, ", appVersion)
				}
				created := details.Created.Format("January 2, 2006")
				createdDesc := ""
				if created != "" {
					createdDesc = fmt.Sprintf("Created: %s ", created)
				}
				deprecated := ""
				if details.Metadata.Deprecated {
					deprecated = "(deprecated)"
				}
				versions = append(versions, fmt.Sprintf("%s\t%s%s%s", version, appVersionDesc, createdDesc, deprecated))
			}
		}
	}

	return versions, cobra.ShellCompDirectiveNoFileComp
}

// addKlogFlags adds flags from k8s.io/klog
// marks the flags as hidden to avoid polluting the help text
func addKlogFlags(fs *pflag.FlagSet) {
	local := flag.NewFlagSet("klog", flag.ExitOnError)
	klog.InitFlags(local)
	local.VisitAll(func(fl *flag.Flag) {
		fl.Name = normalize(fl.Name)
		if fs.Lookup(fl.Name) != nil {
			return
		}
		newflag := pflag.PFlagFromGoFlag(fl)
		newflag.Hidden = true
		fs.AddFlag(newflag)
	})
}

// normalize replaces underscores with hyphens
func normalize(s string) string {
	return strings.ReplaceAll(s, "_", "-")
}
<commit_msg>fix: support empty args with --post-renderer-args<commit_after>/*
Copyright The Helm Authors.

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

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

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

package main

import (
	"flag"
	"fmt"
	"log"
	"path/filepath"
	"sort"
	"strings"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	"k8s.io/klog/v2"

	"helm.sh/helm/v3/pkg/action"
	"helm.sh/helm/v3/pkg/cli/output"
	"helm.sh/helm/v3/pkg/cli/values"
	"helm.sh/helm/v3/pkg/helmpath"
	"helm.sh/helm/v3/pkg/postrender"
	"helm.sh/helm/v3/pkg/repo"
)

const (
	outputFlag         = "output"
	postRenderFlag     = "post-renderer"
	postRenderArgsFlag = "post-renderer-args"
)

func addValueOptionsFlags(f *pflag.FlagSet, v *values.Options) {
	f.StringSliceVarP(&v.ValueFiles, "values", "f", []string{}, "specify values in a YAML file or a URL (can specify multiple)")
	f.StringArrayVar(&v.Values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
	f.StringArrayVar(&v.StringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
	f.StringArrayVar(&v.FileValues, "set-file", []string{}, "set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)")
}

func addChartPathOptionsFlags(f *pflag.FlagSet, c *action.ChartPathOptions) {
	f.StringVar(&c.Version, "version", "", "specify a version constraint for the chart version to use. This constraint can be a specific tag (e.g. 1.1.1) or it may reference a valid range (e.g. ^2.0.0). If this is not specified, the latest version is used")
	f.BoolVar(&c.Verify, "verify", false, "verify the package before using it")
	f.StringVar(&c.Keyring, "keyring", defaultKeyring(), "location of public keys used for verification")
	f.StringVar(&c.RepoURL, "repo", "", "chart repository url where to locate the requested chart")
	f.StringVar(&c.Username, "username", "", "chart repository username where to locate the requested chart")
	f.StringVar(&c.Password, "password", "", "chart repository password where to locate the requested chart")
	f.StringVar(&c.CertFile, "cert-file", "", "identify HTTPS client using this SSL certificate file")
	f.StringVar(&c.KeyFile, "key-file", "", "identify HTTPS client using this SSL key file")
	f.BoolVar(&c.InsecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the chart download")
	f.StringVar(&c.CaFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle")
	f.BoolVar(&c.PassCredentialsAll, "pass-credentials", false, "pass credentials to all domains")
}

// bindOutputFlag will add the output flag to the given command and bind the
// value to the given format pointer
func bindOutputFlag(cmd *cobra.Command, varRef *output.Format) {
	cmd.Flags().VarP(newOutputValue(output.Table, varRef), outputFlag, "o",
		fmt.Sprintf("prints the output in the specified format. Allowed values: %s", strings.Join(output.Formats(), ", ")))

	err := cmd.RegisterFlagCompletionFunc(outputFlag, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
		var formatNames []string
		for format, desc := range output.FormatsWithDesc() {
			if strings.HasPrefix(format, toComplete) {
				formatNames = append(formatNames, fmt.Sprintf("%s\t%s", format, desc))
			}
		}

		// Sort the results to get a deterministic order for the tests
		sort.Strings(formatNames)
		return formatNames, cobra.ShellCompDirectiveNoFileComp
	})

	if err != nil {
		log.Fatal(err)
	}
}

type outputValue output.Format

func newOutputValue(defaultValue output.Format, p *output.Format) *outputValue {
	*p = defaultValue
	return (*outputValue)(p)
}

func (o *outputValue) String() string {
	// It is much cleaner looking (and technically less allocations) to just
	// convert to a string rather than type asserting to the underlying
	// output.Format
	return string(*o)
}

func (o *outputValue) Type() string {
	return "format"
}

func (o *outputValue) Set(s string) error {
	outfmt, err := output.ParseFormat(s)
	if err != nil {
		return err
	}
	*o = outputValue(outfmt)
	return nil
}

func bindPostRenderFlag(cmd *cobra.Command, varRef *postrender.PostRenderer) {
	p := &postRendererOptions{varRef, "", []string{}}
	cmd.Flags().Var(&postRendererString{p}, postRenderFlag, "the path to an executable to be used for post rendering. If it exists in $PATH, the binary will be used, otherwise it will try to look for the executable at the given path")
	cmd.Flags().Var(&postRendererArgsSlice{p}, postRenderArgsFlag, "an argument to the post-renderer (can specify multiple)")
}

type postRendererOptions struct {
	renderer   *postrender.PostRenderer
	binaryPath string
	args       []string
}

type postRendererString struct {
	options *postRendererOptions
}

func (p *postRendererString) String() string {
	return p.options.binaryPath
}

func (p *postRendererString) Type() string {
	return "postRendererString"
}

func (p *postRendererString) Set(val string) error {
	if val == "" {
		return nil
	}
	p.options.binaryPath = val
	pr, err := postrender.NewExec(p.options.binaryPath, p.options.args...)
	if err != nil {
		return err
	}
	*p.options.renderer = pr
	return nil
}

type postRendererArgsSlice struct {
	options *postRendererOptions
}

func (p *postRendererArgsSlice) String() string {
	return "[" + strings.Join(p.options.args, ",") + "]"
}

func (p *postRendererArgsSlice) Type() string {
	return "postRendererArgsSlice"
}

func (p *postRendererArgsSlice) Set(val string) error {

	// a post-renderer defined by a user may accept empty arguments
	p.options.args = append(p.options.args, val)

	if p.options.binaryPath == "" {
		return nil
	}
	// overwrite if already create PostRenderer by `post-renderer` flags
	pr, err := postrender.NewExec(p.options.binaryPath, p.options.args...)
	if err != nil {
		return err
	}
	*p.options.renderer = pr
	return nil
}

func (p *postRendererArgsSlice) Append(val string) error {
	p.options.args = append(p.options.args, val)
	return nil
}

func (p *postRendererArgsSlice) Replace(val []string) error {
	p.options.args = val
	return nil
}

func (p *postRendererArgsSlice) GetSlice() []string {
	return p.options.args
}

func compVersionFlag(chartRef string, toComplete string) ([]string, cobra.ShellCompDirective) {
	chartInfo := strings.Split(chartRef, "/")
	if len(chartInfo) != 2 {
		return nil, cobra.ShellCompDirectiveNoFileComp
	}

	repoName := chartInfo[0]
	chartName := chartInfo[1]

	path := filepath.Join(settings.RepositoryCache, helmpath.CacheIndexFile(repoName))

	var versions []string
	if indexFile, err := repo.LoadIndexFile(path); err == nil {
		for _, details := range indexFile.Entries[chartName] {
			version := details.Metadata.Version
			if strings.HasPrefix(version, toComplete) {
				appVersion := details.Metadata.AppVersion
				appVersionDesc := ""
				if appVersion != "" {
					appVersionDesc = fmt.Sprintf("App: %s, ", appVersion)
				}
				created := details.Created.Format("January 2, 2006")
				createdDesc := ""
				if created != "" {
					createdDesc = fmt.Sprintf("Created: %s ", created)
				}
				deprecated := ""
				if details.Metadata.Deprecated {
					deprecated = "(deprecated)"
				}
				versions = append(versions, fmt.Sprintf("%s\t%s%s%s", version, appVersionDesc, createdDesc, deprecated))
			}
		}
	}

	return versions, cobra.ShellCompDirectiveNoFileComp
}

// addKlogFlags adds flags from k8s.io/klog
// marks the flags as hidden to avoid polluting the help text
func addKlogFlags(fs *pflag.FlagSet) {
	local := flag.NewFlagSet("klog", flag.ExitOnError)
	klog.InitFlags(local)
	local.VisitAll(func(fl *flag.Flag) {
		fl.Name = normalize(fl.Name)
		if fs.Lookup(fl.Name) != nil {
			return
		}
		newflag := pflag.PFlagFromGoFlag(fl)
		newflag.Hidden = true
		fs.AddFlag(newflag)
	})
}

// normalize replaces underscores with hyphens
func normalize(s string) string {
	return strings.ReplaceAll(s, "_", "-")
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"math/rand"
	"time"

	"github.com/qjcg/horeb"
)

const (
	description = "horeb: Speaking in tongues via stdout"
)

func usage() {
	fmt.Printf("\n%s\n\n", description)
	flag.PrintDefaults()
	fmt.Println()
}

func main() {
	rand.Seed(time.Now().UnixNano())

	flag.Usage = usage

	dump := flag.Bool("d", false, "dump all blocks")
	list := flag.Bool("l", false, "list all blocks")
	nchars := flag.Int("n", 30, "number of runes to generate")
	ofs := flag.String("o", " ", "output field separator")
	stream := flag.Bool("s", false, "generate an endless stream of runes")
	streamDelay := flag.Duration("D", time.Millisecond*30, "stream delay")
	version := flag.Bool("v", false, "print version")
	flag.Parse()

	if *version {
		fmt.Println(horeb.Version)
		return
	}

	blocks := []string{"all"}
	if flag.NArg() > 0 {
		blocks = flag.Args()
	}
	// special value means all blocks
	if blocks[0] == "all" {
		// remove "all" value after use
		blocks = blocks[:0]
		for k := range horeb.Blocks {
			blocks = append(blocks, k)
		}
	}

	switch {
	case *list:
		horeb.PrintBlocks(false)
	case *dump:
		horeb.PrintBlocks(true)
	case len(blocks) == 1:
		b, ok := horeb.Blocks[blocks[0]]
		if !ok {
			log.Fatalf("Unknown block: %s\n", blocks[0])
		}

		if *stream {
			ticker := time.NewTicker(*streamDelay)
			for range ticker.C {
				fmt.Printf("%c%s", b.RandomRune(), *ofs)
			}
		} else {
			b.PrintRandom(*nchars, *ofs)
		}
	case len(blocks) > 1:
		bm := map[string]horeb.UnicodeBlock{}
		for _, b := range blocks {
			val, ok := horeb.Blocks[b]
			if !ok {
				log.Printf("Unknown block: %s\n", b)
				continue
			}
			bm[b] = val
		}
		if len(bm) > 0 {
			defer fmt.Println()
			if *stream {
				ticker := time.NewTicker(*streamDelay)
				for range ticker.C {

					block, err := horeb.RandomBlock(bm)
					if err != nil {
						log.Fatal(err)
					}
					fmt.Printf("%c%s", block.RandomRune(), *ofs)
				}
			} else {
				for i := 0; i < *nchars; i++ {
					block, err := horeb.RandomBlock(bm)
					if err != nil {
						log.Fatal(err)
					}
					fmt.Printf("%c%s", block.RandomRune(), *ofs)
				}
			}
		}
	}
}
<commit_msg>Fix horeb usage message printing<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"math/rand"
	"time"

	"github.com/qjcg/horeb"
)

const (
	description = "horeb: Speaking in tongues via stdout"
)

func usage() {
	fmt.Fprintf(flag.CommandLine.Output(), "\n%s\n\n", description)
	flag.PrintDefaults()
	fmt.Fprintln(flag.CommandLine.Output())
}

func main() {
	rand.Seed(time.Now().UnixNano())

	flag.Usage = usage

	dump := flag.Bool("d", false, "dump all blocks")
	list := flag.Bool("l", false, "list all blocks")
	nchars := flag.Int("n", 30, "number of runes to generate")
	ofs := flag.String("o", " ", "output field separator")
	stream := flag.Bool("s", false, "generate an endless stream of runes")
	streamDelay := flag.Duration("D", time.Millisecond*30, "stream delay")
	version := flag.Bool("v", false, "print version")
	flag.Parse()

	if *version {
		fmt.Println(horeb.Version)
		return
	}

	blocks := []string{"all"}
	if flag.NArg() > 0 {
		blocks = flag.Args()
	}
	// special value means all blocks
	if blocks[0] == "all" {
		// remove "all" value after use
		blocks = blocks[:0]
		for k := range horeb.Blocks {
			blocks = append(blocks, k)
		}
	}

	switch {
	case *list:
		horeb.PrintBlocks(false)
	case *dump:
		horeb.PrintBlocks(true)
	case len(blocks) == 1:
		b, ok := horeb.Blocks[blocks[0]]
		if !ok {
			log.Fatalf("Unknown block: %s\n", blocks[0])
		}

		if *stream {
			ticker := time.NewTicker(*streamDelay)
			for range ticker.C {
				fmt.Printf("%c%s", b.RandomRune(), *ofs)
			}
		} else {
			b.PrintRandom(*nchars, *ofs)
		}
	case len(blocks) > 1:
		bm := map[string]horeb.UnicodeBlock{}
		for _, b := range blocks {
			val, ok := horeb.Blocks[b]
			if !ok {
				log.Printf("Unknown block: %s\n", b)
				continue
			}
			bm[b] = val
		}
		if len(bm) > 0 {
			defer fmt.Println()
			if *stream {
				ticker := time.NewTicker(*streamDelay)
				for range ticker.C {

					block, err := horeb.RandomBlock(bm)
					if err != nil {
						log.Fatal(err)
					}
					fmt.Printf("%c%s", block.RandomRune(), *ofs)
				}
			} else {
				for i := 0; i < *nchars; i++ {
					block, err := horeb.RandomBlock(bm)
					if err != nil {
						log.Fatal(err)
					}
					fmt.Printf("%c%s", block.RandomRune(), *ofs)
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"os"

	"github.com/bytom/api"
	"github.com/bytom/consensus/difficulty"
	"github.com/bytom/protocol/bc"
	"github.com/bytom/protocol/bc/types"
	"github.com/bytom/util"
)

const (
	maxNonce = ^uint64(0) // 2^32 - 1
)

// do proof of work
func doWork(bh *types.BlockHeader, seed *bc.Hash) bool {
	for i := uint64(0); i <= maxNonce; i++ {
		bh.Nonce = i
		headerHash := bh.Hash()
		if difficulty.CheckProofOfWork(&headerHash, seed, bh.Bits) {
			fmt.Printf("Mining: successful-----proof hash:%v\n", headerHash.String())
			return true
		}
	}
	return false
}

func getBlockHeaderByHeight(height uint64) {
	type Req struct {
		BlockHeight uint64 `json:"block_height"`
	}

	type Resp struct {
		BlockHeader *types.BlockHeader `json:"block_header"`
		Reward      uint64             `json:"reward"`
	}

	data, _ := util.ClientCall("/get-block-header-by-height", Req{BlockHeight: height})
	rawData, err := json.Marshal(data)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	resp := &Resp{}
	if err = json.Unmarshal(rawData, resp); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	fmt.Println(resp.Reward)
}

func main() {
	data, _ := util.ClientCall("/get-work", nil)
	rawData, err := json.Marshal(data)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	resp := &api.GetWorkResp{}
	if err = json.Unmarshal(rawData, resp); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	if doWork(resp.BlockHeader, resp.Seed) {
		util.ClientCall("/submit-work", &api.SubmitWorkReq{BlockHeader: resp.BlockHeader})
	}

	getBlockHeaderByHeight(resp.BlockHeader.Height)
}
<commit_msg>fix-maxNonce-comment<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"os"

	"github.com/bytom/api"
	"github.com/bytom/consensus/difficulty"
	"github.com/bytom/protocol/bc"
	"github.com/bytom/protocol/bc/types"
	"github.com/bytom/util"
)

const (
	maxNonce = ^uint64(0) // 2^64 - 1
)

// do proof of work
func doWork(bh *types.BlockHeader, seed *bc.Hash) bool {
	for i := uint64(0); i <= maxNonce; i++ {
		bh.Nonce = i
		headerHash := bh.Hash()
		if difficulty.CheckProofOfWork(&headerHash, seed, bh.Bits) {
			fmt.Printf("Mining: successful-----proof hash:%v\n", headerHash.String())
			return true
		}
	}
	return false
}

func getBlockHeaderByHeight(height uint64) {
	type Req struct {
		BlockHeight uint64 `json:"block_height"`
	}

	type Resp struct {
		BlockHeader *types.BlockHeader `json:"block_header"`
		Reward      uint64             `json:"reward"`
	}

	data, _ := util.ClientCall("/get-block-header-by-height", Req{BlockHeight: height})
	rawData, err := json.Marshal(data)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	resp := &Resp{}
	if err = json.Unmarshal(rawData, resp); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	fmt.Println(resp.Reward)
}

func main() {
	data, _ := util.ClientCall("/get-work", nil)
	rawData, err := json.Marshal(data)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	resp := &api.GetWorkResp{}
	if err = json.Unmarshal(rawData, resp); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	if doWork(resp.BlockHeader, resp.Seed) {
		util.ClientCall("/submit-work", &api.SubmitWorkReq{BlockHeader: resp.BlockHeader})
	}

	getBlockHeaderByHeight(resp.BlockHeader.Height)
}
<|endoftext|>


<commit_before>package main

import (
    "code.google.com/p/getopt"
    "fmt"
    "io/ioutil"
    "offend.me.uk/please"
    "os"
)

var parsers map[string]func([]byte, string) (interface{}, error)
var formatters map[string]func(interface{}, string) string

func parseAuto(input []byte, path string) (interface{}, error) {
    var parsed interface{}
    var err error

    for name, parser := range(parsers) {
        fmt.Println(name)
        if name != "auto" {
            parsed, err = parser(input, path)

            if err == nil {
                break
            }
        }
    }

    return parsed, err
}

func init() {
    parsers = map[string]func([]byte, string) (interface{}, error) {
        "auto": parseAuto,
        "json": please.ParseJSON,
        "xml": please.ParseXML,
        "csv": please.ParseCSV,
        "html": please.ParseHTML,
        "mime": please.ParseMIME,
    }

    formatters = map[string]func(interface{}, string) string {
        "bash": please.FormatBash,
        "yaml": please.FormatYAML,
    }
}

func main() {
    // Flags
    in_format := getopt.String('i', "auto", "Parse the input as 'types'", "type")
    out_format := getopt.String('o', "bash", "Use 'type' as the output format", "type")
    getopt.Parse()

    // Validate parser
    if _, ok := parsers[*in_format]; !ok {
        fmt.Printf("Unknown input format: %s\n", *in_format)
        os.Exit(1)
    }

    // Validate formatter
    if _, ok := formatters[*out_format]; !ok {
        fmt.Printf("Unknown output format: %s\n", *out_format)
        os.Exit(1)
    }

    var err error

    // Read from stdin
    input, err := ioutil.ReadAll(os.Stdin)
    if err != nil {
        fmt.Println("Error reading input")
        os.Exit(1)
    }

    // Path
    var path string

    if getopt.NArgs() > 0 {
        path = getopt.Arg(0)
    }

    // Try parsing
    parsed, err := parsers[*in_format](input, path)

    if err != nil {
        fmt.Fprintln(os.Stderr, "Input could not be parsed")
        fmt.Println(err)
        os.Exit(1)
    }

    // ...and format back out :)
    fmt.Println(formatters[*out_format](parsed, path))
}
<commit_msg>Remove debugging from please-parse<commit_after>package main

import (
    "code.google.com/p/getopt"
    "fmt"
    "io/ioutil"
    "offend.me.uk/please"
    "os"
)

var parsers map[string]func([]byte, string) (interface{}, error)
var formatters map[string]func(interface{}, string) string

func parseAuto(input []byte, path string) (interface{}, error) {
    var parsed interface{}
    var err error

    for name, parser := range(parsers) {
        if name != "auto" {
            parsed, err = parser(input, path)

            if err == nil {
                break
            }
        }
    }

    return parsed, err
}

func init() {
    parsers = map[string]func([]byte, string) (interface{}, error) {
        "auto": parseAuto,
        "json": please.ParseJSON,
        "xml": please.ParseXML,
        "csv": please.ParseCSV,
        "html": please.ParseHTML,
        "mime": please.ParseMIME,
    }

    formatters = map[string]func(interface{}, string) string {
        "bash": please.FormatBash,
        "yaml": please.FormatYAML,
    }
}

func main() {
    // Flags
    in_format := getopt.String('i', "auto", "Parse the input as 'types'", "type")
    out_format := getopt.String('o', "bash", "Use 'type' as the output format", "type")
    getopt.Parse()

    // Validate parser
    if _, ok := parsers[*in_format]; !ok {
        fmt.Printf("Unknown input format: %s\n", *in_format)
        os.Exit(1)
    }

    // Validate formatter
    if _, ok := formatters[*out_format]; !ok {
        fmt.Printf("Unknown output format: %s\n", *out_format)
        os.Exit(1)
    }

    var err error

    // Read from stdin
    input, err := ioutil.ReadAll(os.Stdin)
    if err != nil {
        fmt.Println("Error reading input")
        os.Exit(1)
    }

    // Path
    var path string

    if getopt.NArgs() > 0 {
        path = getopt.Arg(0)
    }

    // Try parsing
    parsed, err := parsers[*in_format](input, path)

    if err != nil {
        fmt.Fprintln(os.Stderr, "Input could not be parsed")
        fmt.Println(err)
        os.Exit(1)
    }

    // ...and format back out :)
    fmt.Println(formatters[*out_format](parsed, path))
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Knative Authors

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

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

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

package main

import (
	"context"
	"flag"
	"fmt"
	"io"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"os/signal"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/knative/pkg/logging/logkey"
	"github.com/knative/serving/cmd/util"
	activatorutil "github.com/knative/serving/pkg/activator/util"
	"github.com/knative/serving/pkg/autoscaler"
	"github.com/knative/serving/pkg/http/h2c"
	"github.com/knative/serving/pkg/logging"
	"github.com/knative/serving/pkg/queue"
	"github.com/knative/serving/pkg/system"
	"github.com/knative/serving/pkg/websocket"
	"go.uber.org/zap"

	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
)

const (
	// Add a little buffer space between request handling and stat
	// reporting so that latency in the stat pipeline doesn't
	// interfere with request handling.
	statReportingQueueLength = 10
	// Add enough buffer to not block request serving on stats collection
	requestCountingQueueLength = 100
	// Number of seconds the /quitquitquit handler should wait before
	// returning.  The purpose is to kill the container alive a little
	// bit longer, that it doesn't go away until the pod is truly
	// removed from service.
	quitSleepSecs = 20
)

var (
	podName               string
	servingNamespace      string
	servingConfiguration  string
	servingRevision       string
	servingRevisionKey    string
	servingAutoscaler     string
	servingAutoscalerPort string
	statChan              = make(chan *autoscaler.Stat, statReportingQueueLength)
	reqChan               = make(chan queue.ReqEvent, requestCountingQueueLength)
	kubeClient            *kubernetes.Clientset
	statSink              *websocket.ManagedConnection
	logger                *zap.SugaredLogger
	breaker               *queue.Breaker

	h2cProxy  *httputil.ReverseProxy
	httpProxy *httputil.ReverseProxy

	health *healthServer = &healthServer{alive: true}

	containerConcurrency = flag.Int("containerConcurrency", 0, "")
)

func initEnv() {
	podName = util.GetRequiredEnvOrFatal("SERVING_POD", logger)
	servingNamespace = util.GetRequiredEnvOrFatal("SERVING_NAMESPACE", logger)
	servingConfiguration = util.GetRequiredEnvOrFatal("SERVING_CONFIGURATION", logger)
	servingRevision = util.GetRequiredEnvOrFatal("SERVING_REVISION", logger)
	servingAutoscaler = util.GetRequiredEnvOrFatal("SERVING_AUTOSCALER", logger)
	servingAutoscalerPort = util.GetRequiredEnvOrFatal("SERVING_AUTOSCALER_PORT", logger)

	// TODO(mattmoor): Move this key to be in terms of the KPA.
	servingRevisionKey = autoscaler.NewKpaKey(servingNamespace, servingRevision)
}

func statReporter() {
	for {
		s := <-statChan
		if statSink == nil {
			logger.Warn("Stat sink not (yet) connected.")
			continue
		}
		if !health.isAlive() {
			s.LameDuck = true
		}
		sm := autoscaler.StatMessage{
			Stat: *s,
			Key:  servingRevisionKey,
		}
		err := statSink.Send(sm)
		if err != nil {
			logger.Error("Error while sending stat", zap.Error(err))
		}
	}
}

func proxyForRequest(req *http.Request) *httputil.ReverseProxy {
	if req.ProtoMajor == 2 {
		return h2cProxy
	}

	return httpProxy
}

func isProbe(r *http.Request) bool {
	// Since K8s 1.8, prober requests have
	//   User-Agent = "kube-probe/{major-version}.{minor-version}".
	return strings.HasPrefix(r.Header.Get("User-Agent"), "kube-probe/")
}

func handler(w http.ResponseWriter, r *http.Request) {
	proxy := proxyForRequest(r)

	if isProbe(r) {
		// Do not count health checks for concurrency metrics
		proxy.ServeHTTP(w, r)
		return
	}

	// Metrics for autoscaling
	reqChan <- queue.ReqEvent{Time: time.Now(), EventType: queue.ReqIn}
	defer func() {
		reqChan <- queue.ReqEvent{Time: time.Now(), EventType: queue.ReqOut}
	}()
	// Enforce queuing and concurrency limits
	if breaker != nil {
		ok := breaker.Maybe(func() {
			proxy.ServeHTTP(w, r)
		})
		if !ok {
			http.Error(w, "overload", http.StatusServiceUnavailable)
		}
	} else {
		proxy.ServeHTTP(w, r)
	}
}

// healthServer registers whether a PreStop hook has been called.
type healthServer struct {
	alive bool
	mutex sync.RWMutex
}

// isAlive() returns true until a PreStop hook has been called.
func (h *healthServer) isAlive() bool {
	h.mutex.RLock()
	defer h.mutex.RUnlock()
	return h.alive
}

// kill() marks that a PreStop hook has been called.
func (h *healthServer) kill() {
	h.mutex.Lock()
	h.alive = false
	h.mutex.Unlock()
}

// healthHandler is used for readinessProbe/livenessCheck of
// queue-proxy.
func (h *healthServer) healthHandler(w http.ResponseWriter, r *http.Request) {
	if h.isAlive() {
		w.WriteHeader(http.StatusOK)
		io.WriteString(w, "alive: true")
	} else {
		w.WriteHeader(http.StatusBadRequest)
		io.WriteString(w, "alive: false")
	}
}

// quitHandler() is used for preStop hook of queue-proxy. It:
// - marks the service as not ready, so that requests will no longer
//   be routed to it,
// - adds a small delay, so that the container doesn't get killed at
//   the same time the pod is marked for removal.
func (h *healthServer) quitHandler(w http.ResponseWriter, r *http.Request) {
	// First, we want to mark the container as not ready, so that even
	// if the pod removal (from service) isn't yet effective, the
	// readinessCheck will still prevent traffic to be routed to this
	// pod.
	h.kill()
	// However, since both readinessCheck and pod removal from service
	// is eventually consistent, we add here a small delay to have the
	// container stay alive a little bit longer after.  We still have
	// no guarantee that container termination is done only after
	// removal from service is effective, but this has been showed to
	// alleviate the issue.
	time.Sleep(quitSleepSecs * time.Second)
	w.WriteHeader(http.StatusOK)
	io.WriteString(w, "alive: false")
}

// Sets up /health and /quitquitquit endpoints.
func setupAdminHandlers(server *http.Server) {
	mux := http.NewServeMux()
	mux.HandleFunc(fmt.Sprintf("/%s", queue.RequestQueueHealthPath), health.healthHandler)
	mux.HandleFunc(fmt.Sprintf("/%s", queue.RequestQueueQuitPath), health.quitHandler)
	server.Handler = mux
	server.ListenAndServe()
}

func main() {
	flag.Parse()
	logger, _ = logging.NewLogger(os.Getenv("SERVING_LOGGING_CONFIG"), os.Getenv("SERVING_LOGGING_LEVEL"))
	logger = logger.Named("queueproxy")
	defer logger.Sync()

	initEnv()
	logger = logger.With(
		zap.String(logkey.Key, servingRevisionKey),
		zap.String(logkey.Pod, podName))

	target, err := url.Parse("http://localhost:8080")
	if err != nil {
		logger.Fatal("Failed to parse localhost url", zap.Error(err))
	}

	httpProxy = httputil.NewSingleHostReverseProxy(target)
	h2cProxy = httputil.NewSingleHostReverseProxy(target)
	h2cProxy.Transport = h2c.DefaultTransport

	activatorutil.SetupHeaderPruning(httpProxy)
	activatorutil.SetupHeaderPruning(h2cProxy)

	// If containerConcurrency == 0 then concurrency is unlimited.
	if *containerConcurrency > 0 {
		// We set the queue depth to be equal to the container concurrency but at least 10 to
		// allow the autoscaler to get a strong enough signal.
		queueDepth := *containerConcurrency
		if queueDepth < 10 {
			queueDepth = 10
		}
		breaker = queue.NewBreaker(int32(queueDepth), int32(*containerConcurrency))
		logger.Infof("Queue container is starting with queueDepth: %d, containerConcurrency: %d", queueDepth, *containerConcurrency)
	}

	config, err := rest.InClusterConfig()
	if err != nil {
		logger.Fatal("Error getting in cluster config", zap.Error(err))
	}
	kc, err := kubernetes.NewForConfig(config)
	if err != nil {
		logger.Fatal("Error creating new config", zap.Error(err))
	}
	kubeClient = kc

	// Open a websocket connection to the autoscaler
	autoscalerEndpoint := fmt.Sprintf("ws://%s.%s:%s", servingAutoscaler, system.Namespace, servingAutoscalerPort)
	logger.Infof("Connecting to autoscaler at %s", autoscalerEndpoint)
	statSink = websocket.NewDurableSendingConnection(autoscalerEndpoint)
	go statReporter()

	reportTicker := time.NewTicker(time.Second).C
	queue.NewStats(podName, queue.Channels{
		ReqChan:    reqChan,
		ReportChan: reportTicker,
		StatChan:   statChan,
	}, time.Now())
	defer func() {
		if statSink != nil {
			statSink.Close()
		}
	}()

	adminServer := &http.Server{
		Addr:    fmt.Sprintf(":%d", queue.RequestQueueAdminPort),
		Handler: nil,
	}

	server := h2c.NewServer(
		fmt.Sprintf(":%d", queue.RequestQueuePort),
		http.HandlerFunc(handler),
	)

	// Add a SIGTERM handler to gracefully shutdown the servers during
	// pod termination.
	sigTermChan := make(chan os.Signal)
	signal.Notify(sigTermChan, syscall.SIGTERM)
	go func() {
		<-sigTermChan
		// Calling server.Shutdown() allows pending requests to
		// complete, while no new work is accepted.

		server.Shutdown(context.Background())
		adminServer.Shutdown(context.Background())
		os.Exit(0)
	}()

	go server.ListenAndServe()
	setupAdminHandlers(adminServer)
}
<commit_msg>typo in a comment (#2185)<commit_after>/*
Copyright 2018 The Knative Authors

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

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

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

package main

import (
	"context"
	"flag"
	"fmt"
	"io"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"os/signal"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/knative/pkg/logging/logkey"
	"github.com/knative/serving/cmd/util"
	activatorutil "github.com/knative/serving/pkg/activator/util"
	"github.com/knative/serving/pkg/autoscaler"
	"github.com/knative/serving/pkg/http/h2c"
	"github.com/knative/serving/pkg/logging"
	"github.com/knative/serving/pkg/queue"
	"github.com/knative/serving/pkg/system"
	"github.com/knative/serving/pkg/websocket"
	"go.uber.org/zap"

	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
)

const (
	// Add a little buffer space between request handling and stat
	// reporting so that latency in the stat pipeline doesn't
	// interfere with request handling.
	statReportingQueueLength = 10
	// Add enough buffer to not block request serving on stats collection
	requestCountingQueueLength = 100
	// Number of seconds the /quitquitquit handler should wait before
	// returning.  The purpose is to keep the container alive a little
	// bit longer, that it doesn't go away until the pod is truly
	// removed from service.
	quitSleepSecs = 20
)

var (
	podName               string
	servingNamespace      string
	servingConfiguration  string
	servingRevision       string
	servingRevisionKey    string
	servingAutoscaler     string
	servingAutoscalerPort string
	statChan              = make(chan *autoscaler.Stat, statReportingQueueLength)
	reqChan               = make(chan queue.ReqEvent, requestCountingQueueLength)
	kubeClient            *kubernetes.Clientset
	statSink              *websocket.ManagedConnection
	logger                *zap.SugaredLogger
	breaker               *queue.Breaker

	h2cProxy  *httputil.ReverseProxy
	httpProxy *httputil.ReverseProxy

	health *healthServer = &healthServer{alive: true}

	containerConcurrency = flag.Int("containerConcurrency", 0, "")
)

func initEnv() {
	podName = util.GetRequiredEnvOrFatal("SERVING_POD", logger)
	servingNamespace = util.GetRequiredEnvOrFatal("SERVING_NAMESPACE", logger)
	servingConfiguration = util.GetRequiredEnvOrFatal("SERVING_CONFIGURATION", logger)
	servingRevision = util.GetRequiredEnvOrFatal("SERVING_REVISION", logger)
	servingAutoscaler = util.GetRequiredEnvOrFatal("SERVING_AUTOSCALER", logger)
	servingAutoscalerPort = util.GetRequiredEnvOrFatal("SERVING_AUTOSCALER_PORT", logger)

	// TODO(mattmoor): Move this key to be in terms of the KPA.
	servingRevisionKey = autoscaler.NewKpaKey(servingNamespace, servingRevision)
}

func statReporter() {
	for {
		s := <-statChan
		if statSink == nil {
			logger.Warn("Stat sink not (yet) connected.")
			continue
		}
		if !health.isAlive() {
			s.LameDuck = true
		}
		sm := autoscaler.StatMessage{
			Stat: *s,
			Key:  servingRevisionKey,
		}
		err := statSink.Send(sm)
		if err != nil {
			logger.Error("Error while sending stat", zap.Error(err))
		}
	}
}

func proxyForRequest(req *http.Request) *httputil.ReverseProxy {
	if req.ProtoMajor == 2 {
		return h2cProxy
	}

	return httpProxy
}

func isProbe(r *http.Request) bool {
	// Since K8s 1.8, prober requests have
	//   User-Agent = "kube-probe/{major-version}.{minor-version}".
	return strings.HasPrefix(r.Header.Get("User-Agent"), "kube-probe/")
}

func handler(w http.ResponseWriter, r *http.Request) {
	proxy := proxyForRequest(r)

	if isProbe(r) {
		// Do not count health checks for concurrency metrics
		proxy.ServeHTTP(w, r)
		return
	}

	// Metrics for autoscaling
	reqChan <- queue.ReqEvent{Time: time.Now(), EventType: queue.ReqIn}
	defer func() {
		reqChan <- queue.ReqEvent{Time: time.Now(), EventType: queue.ReqOut}
	}()
	// Enforce queuing and concurrency limits
	if breaker != nil {
		ok := breaker.Maybe(func() {
			proxy.ServeHTTP(w, r)
		})
		if !ok {
			http.Error(w, "overload", http.StatusServiceUnavailable)
		}
	} else {
		proxy.ServeHTTP(w, r)
	}
}

// healthServer registers whether a PreStop hook has been called.
type healthServer struct {
	alive bool
	mutex sync.RWMutex
}

// isAlive() returns true until a PreStop hook has been called.
func (h *healthServer) isAlive() bool {
	h.mutex.RLock()
	defer h.mutex.RUnlock()
	return h.alive
}

// kill() marks that a PreStop hook has been called.
func (h *healthServer) kill() {
	h.mutex.Lock()
	h.alive = false
	h.mutex.Unlock()
}

// healthHandler is used for readinessProbe/livenessCheck of
// queue-proxy.
func (h *healthServer) healthHandler(w http.ResponseWriter, r *http.Request) {
	if h.isAlive() {
		w.WriteHeader(http.StatusOK)
		io.WriteString(w, "alive: true")
	} else {
		w.WriteHeader(http.StatusBadRequest)
		io.WriteString(w, "alive: false")
	}
}

// quitHandler() is used for preStop hook of queue-proxy. It:
// - marks the service as not ready, so that requests will no longer
//   be routed to it,
// - adds a small delay, so that the container doesn't get killed at
//   the same time the pod is marked for removal.
func (h *healthServer) quitHandler(w http.ResponseWriter, r *http.Request) {
	// First, we want to mark the container as not ready, so that even
	// if the pod removal (from service) isn't yet effective, the
	// readinessCheck will still prevent traffic to be routed to this
	// pod.
	h.kill()
	// However, since both readinessCheck and pod removal from service
	// is eventually consistent, we add here a small delay to have the
	// container stay alive a little bit longer after.  We still have
	// no guarantee that container termination is done only after
	// removal from service is effective, but this has been showed to
	// alleviate the issue.
	time.Sleep(quitSleepSecs * time.Second)
	w.WriteHeader(http.StatusOK)
	io.WriteString(w, "alive: false")
}

// Sets up /health and /quitquitquit endpoints.
func setupAdminHandlers(server *http.Server) {
	mux := http.NewServeMux()
	mux.HandleFunc(fmt.Sprintf("/%s", queue.RequestQueueHealthPath), health.healthHandler)
	mux.HandleFunc(fmt.Sprintf("/%s", queue.RequestQueueQuitPath), health.quitHandler)
	server.Handler = mux
	server.ListenAndServe()
}

func main() {
	flag.Parse()
	logger, _ = logging.NewLogger(os.Getenv("SERVING_LOGGING_CONFIG"), os.Getenv("SERVING_LOGGING_LEVEL"))
	logger = logger.Named("queueproxy")
	defer logger.Sync()

	initEnv()
	logger = logger.With(
		zap.String(logkey.Key, servingRevisionKey),
		zap.String(logkey.Pod, podName))

	target, err := url.Parse("http://localhost:8080")
	if err != nil {
		logger.Fatal("Failed to parse localhost url", zap.Error(err))
	}

	httpProxy = httputil.NewSingleHostReverseProxy(target)
	h2cProxy = httputil.NewSingleHostReverseProxy(target)
	h2cProxy.Transport = h2c.DefaultTransport

	activatorutil.SetupHeaderPruning(httpProxy)
	activatorutil.SetupHeaderPruning(h2cProxy)

	// If containerConcurrency == 0 then concurrency is unlimited.
	if *containerConcurrency > 0 {
		// We set the queue depth to be equal to the container concurrency but at least 10 to
		// allow the autoscaler to get a strong enough signal.
		queueDepth := *containerConcurrency
		if queueDepth < 10 {
			queueDepth = 10
		}
		breaker = queue.NewBreaker(int32(queueDepth), int32(*containerConcurrency))
		logger.Infof("Queue container is starting with queueDepth: %d, containerConcurrency: %d", queueDepth, *containerConcurrency)
	}

	config, err := rest.InClusterConfig()
	if err != nil {
		logger.Fatal("Error getting in cluster config", zap.Error(err))
	}
	kc, err := kubernetes.NewForConfig(config)
	if err != nil {
		logger.Fatal("Error creating new config", zap.Error(err))
	}
	kubeClient = kc

	// Open a websocket connection to the autoscaler
	autoscalerEndpoint := fmt.Sprintf("ws://%s.%s:%s", servingAutoscaler, system.Namespace, servingAutoscalerPort)
	logger.Infof("Connecting to autoscaler at %s", autoscalerEndpoint)
	statSink = websocket.NewDurableSendingConnection(autoscalerEndpoint)
	go statReporter()

	reportTicker := time.NewTicker(time.Second).C
	queue.NewStats(podName, queue.Channels{
		ReqChan:    reqChan,
		ReportChan: reportTicker,
		StatChan:   statChan,
	}, time.Now())
	defer func() {
		if statSink != nil {
			statSink.Close()
		}
	}()

	adminServer := &http.Server{
		Addr:    fmt.Sprintf(":%d", queue.RequestQueueAdminPort),
		Handler: nil,
	}

	server := h2c.NewServer(
		fmt.Sprintf(":%d", queue.RequestQueuePort),
		http.HandlerFunc(handler),
	)

	// Add a SIGTERM handler to gracefully shutdown the servers during
	// pod termination.
	sigTermChan := make(chan os.Signal)
	signal.Notify(sigTermChan, syscall.SIGTERM)
	go func() {
		<-sigTermChan
		// Calling server.Shutdown() allows pending requests to
		// complete, while no new work is accepted.

		server.Shutdown(context.Background())
		adminServer.Shutdown(context.Background())
		os.Exit(0)
	}()

	go server.ListenAndServe()
	setupAdminHandlers(adminServer)
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"github.com/nu7hatch/gouuid"
)

func CreateSession(username string, password string) (string, error) {
	var id int

	err := _db.QueryRow("SELECT id FROM neb_users WHERE username = ? AND password = ?", username, password).Scan(&id)

	if err != nil && err.Error() == "sql: no rows in result set" && _cfg["autoRegister"] == "true" { //If user are registered on connection
		err = RegisterUser(username, password)

		if err != nil{
			return "", err
		}

		return CreateSession(username, password)
	} else if err != nil {
		log.Println("Could not Query DB for user", username, " : ", err)
		return "", err
	}

	sessionid := GenerateSessionId(username)

	stmt, err := _db.Prepare("REPLACE INTO neb_sessions (userid,lastAlive,sessionId,sessionStart) VALUES (?,NOW(),?,NOW())")
	_, err = stmt.Exec(id, sessionid)
	if err != nil {
		log.Println("Could not insert session :", err)
		return "", err
	}

	return sessionid, nil
}
func GenerateSessionId(username string) string{
	u4, err := uuid.NewV4()
	if err != nil {
	    log.Println("Failed to generate uuid:", err)
	    return ""
	}
	return u4.String()
}<commit_msg>Changed sql no rows detection from error string to sql.ErrNoRows<commit_after>package main

import (
	"database/sql"
	"log"
	"github.com/nu7hatch/gouuid"
)

func CreateSession(username string, password string) (string, error) {
	var id int

	err := _db.QueryRow("SELECT id FROM neb_users WHERE username = ? AND password = ?", username, password).Scan(&id)

	if err != nil && err == sql.ErrNoRows && _cfg["autoRegister"] == "true" { //If user are registered on connection
		err = RegisterUser(username, password)

		if err != nil{
			return "", err
		}

		return CreateSession(username, password)
	} else if err != nil {
		log.Println("Could not Query DB for user", username, " : ", err)
		return "", err
	}

	sessionid := GenerateSessionId(username)

	stmt, err := _db.Prepare("REPLACE INTO neb_sessions (userid,lastAlive,sessionId,sessionStart) VALUES (?,NOW(),?,NOW())")
	_, err = stmt.Exec(id, sessionid)
	if err != nil {
		log.Println("Could not insert session :", err)
		return "", err
	}

	return sessionid, nil
}
func GenerateSessionId(username string) string{
	u4, err := uuid.NewV4()
	if err != nil {
	    log.Println("Failed to generate uuid:", err)
	    return ""
	}
	return u4.String()
}<|endoftext|>


<commit_before>package api

// Cluster represents high-level information about a LXD cluster.
//
// API extension: clustering
type Cluster struct {
	ServerName string `json:"server_name" yaml:"server_name"`
	Enabled    bool   `json:"enabled" yaml:"enabled"`

	// API extension: clustering_join
	MemberConfig []ClusterMemberConfigKey `json:"member_config" yaml:"member_config"`
}

// ClusterMemberConfigKey represents a single config key that a new member of
// the cluster is required to provide when joining.
//
// The Value field is empty when getting clustering information with GET
// /1.0/cluster, and should be filled by the joining node when performing a PUT
// /1.0/cluster join request.
//
// API extension: clustering_join
type ClusterMemberConfigKey struct {
	Entity      string `json:"entity" yaml:"entity"`
	Name        string `json:"name" yaml:"name"`
	Key         string `json:"key" yaml:"key"`
	Value       string `json:"value" yaml:"value"`
	Description string `json:"description" yaml:"description"`
}

// ClusterPut represents the fields required to bootstrap or join a LXD
// cluster.
//
// API extension: clustering
type ClusterPut struct {
	Cluster            `yaml:",inline"`
	ClusterAddress     string `json:"cluster_address" yaml:"cluster_address"`
	ClusterCertificate string `json:"cluster_certificate" yaml:"cluster_certificate"`

	// API extension: clustering_join
	ServerAddress   string `json:"server_address" yaml:"server_address"`
	ClusterPassword string `json:"cluster_password" yaml:"cluster_password"`
}

// ClusterMemberPost represents the fields required to rename a LXD node.
//
// API extension: clustering
type ClusterMemberPost struct {
	ServerName string `json:"server_name" yaml:"server_name"`
}

// ClusterMember represents the a LXD node in the cluster.
//
// API extension: clustering
type ClusterMember struct {
	ServerName string `json:"server_name" yaml:"server_name"`
	URL        string `json:"url" yaml:"url"`
	Database   bool   `json:"database" yaml:"database"`
	Status     string `json:"status" yaml:"status"`
	Message    string `json:"message" yaml:"message"`
}
<commit_msg>shared/api: Add clustering roles<commit_after>package api

// Cluster represents high-level information about a LXD cluster.
//
// API extension: clustering
type Cluster struct {
	ServerName string `json:"server_name" yaml:"server_name"`
	Enabled    bool   `json:"enabled" yaml:"enabled"`

	// API extension: clustering_join
	MemberConfig []ClusterMemberConfigKey `json:"member_config" yaml:"member_config"`
}

// ClusterMemberConfigKey represents a single config key that a new member of
// the cluster is required to provide when joining.
//
// The Value field is empty when getting clustering information with GET
// /1.0/cluster, and should be filled by the joining node when performing a PUT
// /1.0/cluster join request.
//
// API extension: clustering_join
type ClusterMemberConfigKey struct {
	Entity      string `json:"entity" yaml:"entity"`
	Name        string `json:"name" yaml:"name"`
	Key         string `json:"key" yaml:"key"`
	Value       string `json:"value" yaml:"value"`
	Description string `json:"description" yaml:"description"`
}

// ClusterPut represents the fields required to bootstrap or join a LXD
// cluster.
//
// API extension: clustering
type ClusterPut struct {
	Cluster            `yaml:",inline"`
	ClusterAddress     string `json:"cluster_address" yaml:"cluster_address"`
	ClusterCertificate string `json:"cluster_certificate" yaml:"cluster_certificate"`

	// API extension: clustering_join
	ServerAddress   string `json:"server_address" yaml:"server_address"`
	ClusterPassword string `json:"cluster_password" yaml:"cluster_password"`
}

// ClusterMemberPost represents the fields required to rename a LXD node.
//
// API extension: clustering
type ClusterMemberPost struct {
	ServerName string `json:"server_name" yaml:"server_name"`
}

// ClusterMember represents the a LXD node in the cluster.
//
// API extension: clustering
type ClusterMember struct {
	ServerName string `json:"server_name" yaml:"server_name"`
	URL        string `json:"url" yaml:"url"`
	Database   bool   `json:"database" yaml:"database"`
	Status     string `json:"status" yaml:"status"`
	Message    string `json:"message" yaml:"message"`

	// API extension: clustering_roles
	Roles []string `json:"roles" yaml:"roles"`
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Kubernetes Authors.

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

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

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

package node

import (
	"sort"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestDeleteEdges_locked(t *testing.T) {
	cases := []struct {
		desc        string
		fromType    vertexType
		toType      vertexType
		toNamespace string
		toName      string
		start       *Graph
		expect      *Graph
	}{
		{
			// single edge from a configmap to a node, will delete edge and orphaned configmap
			desc:        "edges and source orphans are deleted, destination orphans are preserved",
			fromType:    configMapVertexType,
			toType:      nodeVertexType,
			toNamespace: "",
			toName:      "node1",
			start: func() *Graph {
				g := NewGraph()
				nodeVertex := g.getOrCreateVertex_locked(nodeVertexType, "", "node1")
				configmapVertex := g.getOrCreateVertex_locked(configMapVertexType, "namespace1", "configmap1")
				g.graph.SetEdge(newDestinationEdge(configmapVertex, nodeVertex, nodeVertex))
				return g
			}(),
			expect: func() *Graph {
				g := NewGraph()
				g.getOrCreateVertex_locked(nodeVertexType, "", "node1")
				return g
			}(),
		},
		{
			// two edges from the same configmap to distinct nodes, will delete one of the edges
			desc:        "edges are deleted, non-orphans and destination orphans are preserved",
			fromType:    configMapVertexType,
			toType:      nodeVertexType,
			toNamespace: "",
			toName:      "node2",
			start: func() *Graph {
				g := NewGraph()
				nodeVertex1 := g.getOrCreateVertex_locked(nodeVertexType, "", "node1")
				nodeVertex2 := g.getOrCreateVertex_locked(nodeVertexType, "", "node2")
				configmapVertex := g.getOrCreateVertex_locked(configMapVertexType, "namespace1", "configmap1")
				g.graph.SetEdge(newDestinationEdge(configmapVertex, nodeVertex1, nodeVertex1))
				g.graph.SetEdge(newDestinationEdge(configmapVertex, nodeVertex2, nodeVertex2))
				return g
			}(),
			expect: func() *Graph {
				g := NewGraph()
				nodeVertex1 := g.getOrCreateVertex_locked(nodeVertexType, "", "node1")
				g.getOrCreateVertex_locked(nodeVertexType, "", "node2")
				configmapVertex := g.getOrCreateVertex_locked(configMapVertexType, "namespace1", "configmap1")
				g.graph.SetEdge(newDestinationEdge(configmapVertex, nodeVertex1, nodeVertex1))
				return g
			}(),
		},
		{
			desc:        "no edges to delete",
			fromType:    configMapVertexType,
			toType:      nodeVertexType,
			toNamespace: "",
			toName:      "node1",
			start: func() *Graph {
				g := NewGraph()
				g.getOrCreateVertex_locked(nodeVertexType, "", "node1")
				g.getOrCreateVertex_locked(configMapVertexType, "namespace1", "configmap1")
				return g
			}(),
			expect: func() *Graph {
				g := NewGraph()
				g.getOrCreateVertex_locked(nodeVertexType, "", "node1")
				g.getOrCreateVertex_locked(configMapVertexType, "namespace1", "configmap1")
				return g
			}(),
		},
		{
			desc:        "destination vertex does not exist",
			fromType:    configMapVertexType,
			toType:      nodeVertexType,
			toNamespace: "",
			toName:      "node1",
			start: func() *Graph {
				g := NewGraph()
				g.getOrCreateVertex_locked(configMapVertexType, "namespace1", "configmap1")
				return g
			}(),
			expect: func() *Graph {
				g := NewGraph()
				g.getOrCreateVertex_locked(configMapVertexType, "namespace1", "configmap1")
				return g
			}(),
		},
		{
			desc:        "source vertex type doesn't exist",
			fromType:    configMapVertexType,
			toType:      nodeVertexType,
			toNamespace: "",
			toName:      "node1",
			start: func() *Graph {
				g := NewGraph()
				g.getOrCreateVertex_locked(nodeVertexType, "", "node1")
				return g
			}(),
			expect: func() *Graph {
				g := NewGraph()
				g.getOrCreateVertex_locked(nodeVertexType, "", "node1")
				return g
			}(),
		},
	}
	for _, c := range cases {
		t.Run(c.desc, func(t *testing.T) {
			c.start.deleteEdges_locked(c.fromType, c.toType, c.toNamespace, c.toName)

			// Note: We assert on substructures (graph.Nodes(), graph.Edges()) because the graph tracks
			// freed IDs for reuse, which results in an irrelevant inequality between start and expect.

			// sort the nodes by ID
			// (the slices we get back are from map iteration, where order is not guaranteed)
			expectNodes := c.expect.graph.Nodes()
			sort.Slice(expectNodes, func(i, j int) bool {
				return expectNodes[i].ID() < expectNodes[j].ID()
			})
			startNodes := c.start.graph.Nodes()
			sort.Slice(expectNodes, func(i, j int) bool {
				return startNodes[i].ID() < startNodes[j].ID()
			})
			assert.Equal(t, expectNodes, startNodes)

			// sort the edges by from ID, then to ID
			// (the slices we get back are from map iteration, where order is not guaranteed)
			expectEdges := c.expect.graph.Edges()
			sort.Slice(expectEdges, func(i, j int) bool {
				if expectEdges[i].From().ID() == expectEdges[j].From().ID() {
					return expectEdges[i].To().ID() < expectEdges[j].To().ID()
				}
				return expectEdges[i].From().ID() < expectEdges[j].From().ID()
			})
			startEdges := c.start.graph.Edges()
			sort.Slice(expectEdges, func(i, j int) bool {
				if startEdges[i].From().ID() == startEdges[j].From().ID() {
					return startEdges[i].To().ID() < startEdges[j].To().ID()
				}
				return startEdges[i].From().ID() < startEdges[j].From().ID()
			})
			assert.Equal(t, expectEdges, startEdges)

			// vertices is a recursive map, no need to sort
			assert.Equal(t, c.expect.vertices, c.start.vertices)
		})
	}
}
<commit_msg>fix graph test sorting<commit_after>/*
Copyright 2018 The Kubernetes Authors.

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

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

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

package node

import (
	"sort"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestDeleteEdges_locked(t *testing.T) {
	cases := []struct {
		desc        string
		fromType    vertexType
		toType      vertexType
		toNamespace string
		toName      string
		start       *Graph
		expect      *Graph
	}{
		{
			// single edge from a configmap to a node, will delete edge and orphaned configmap
			desc:        "edges and source orphans are deleted, destination orphans are preserved",
			fromType:    configMapVertexType,
			toType:      nodeVertexType,
			toNamespace: "",
			toName:      "node1",
			start: func() *Graph {
				g := NewGraph()
				nodeVertex := g.getOrCreateVertex_locked(nodeVertexType, "", "node1")
				configmapVertex := g.getOrCreateVertex_locked(configMapVertexType, "namespace1", "configmap1")
				g.graph.SetEdge(newDestinationEdge(configmapVertex, nodeVertex, nodeVertex))
				return g
			}(),
			expect: func() *Graph {
				g := NewGraph()
				g.getOrCreateVertex_locked(nodeVertexType, "", "node1")
				return g
			}(),
		},
		{
			// two edges from the same configmap to distinct nodes, will delete one of the edges
			desc:        "edges are deleted, non-orphans and destination orphans are preserved",
			fromType:    configMapVertexType,
			toType:      nodeVertexType,
			toNamespace: "",
			toName:      "node2",
			start: func() *Graph {
				g := NewGraph()
				nodeVertex1 := g.getOrCreateVertex_locked(nodeVertexType, "", "node1")
				nodeVertex2 := g.getOrCreateVertex_locked(nodeVertexType, "", "node2")
				configmapVertex := g.getOrCreateVertex_locked(configMapVertexType, "namespace1", "configmap1")
				g.graph.SetEdge(newDestinationEdge(configmapVertex, nodeVertex1, nodeVertex1))
				g.graph.SetEdge(newDestinationEdge(configmapVertex, nodeVertex2, nodeVertex2))
				return g
			}(),
			expect: func() *Graph {
				g := NewGraph()
				nodeVertex1 := g.getOrCreateVertex_locked(nodeVertexType, "", "node1")
				g.getOrCreateVertex_locked(nodeVertexType, "", "node2")
				configmapVertex := g.getOrCreateVertex_locked(configMapVertexType, "namespace1", "configmap1")
				g.graph.SetEdge(newDestinationEdge(configmapVertex, nodeVertex1, nodeVertex1))
				return g
			}(),
		},
		{
			desc:        "no edges to delete",
			fromType:    configMapVertexType,
			toType:      nodeVertexType,
			toNamespace: "",
			toName:      "node1",
			start: func() *Graph {
				g := NewGraph()
				g.getOrCreateVertex_locked(nodeVertexType, "", "node1")
				g.getOrCreateVertex_locked(configMapVertexType, "namespace1", "configmap1")
				return g
			}(),
			expect: func() *Graph {
				g := NewGraph()
				g.getOrCreateVertex_locked(nodeVertexType, "", "node1")
				g.getOrCreateVertex_locked(configMapVertexType, "namespace1", "configmap1")
				return g
			}(),
		},
		{
			desc:        "destination vertex does not exist",
			fromType:    configMapVertexType,
			toType:      nodeVertexType,
			toNamespace: "",
			toName:      "node1",
			start: func() *Graph {
				g := NewGraph()
				g.getOrCreateVertex_locked(configMapVertexType, "namespace1", "configmap1")
				return g
			}(),
			expect: func() *Graph {
				g := NewGraph()
				g.getOrCreateVertex_locked(configMapVertexType, "namespace1", "configmap1")
				return g
			}(),
		},
		{
			desc:        "source vertex type doesn't exist",
			fromType:    configMapVertexType,
			toType:      nodeVertexType,
			toNamespace: "",
			toName:      "node1",
			start: func() *Graph {
				g := NewGraph()
				g.getOrCreateVertex_locked(nodeVertexType, "", "node1")
				return g
			}(),
			expect: func() *Graph {
				g := NewGraph()
				g.getOrCreateVertex_locked(nodeVertexType, "", "node1")
				return g
			}(),
		},
	}
	for _, c := range cases {
		t.Run(c.desc, func(t *testing.T) {
			c.start.deleteEdges_locked(c.fromType, c.toType, c.toNamespace, c.toName)

			// Note: We assert on substructures (graph.Nodes(), graph.Edges()) because the graph tracks
			// freed IDs for reuse, which results in an irrelevant inequality between start and expect.

			// sort the nodes by ID
			// (the slices we get back are from map iteration, where order is not guaranteed)
			expectNodes := c.expect.graph.Nodes()
			sort.Slice(expectNodes, func(i, j int) bool {
				return expectNodes[i].ID() < expectNodes[j].ID()
			})
			startNodes := c.start.graph.Nodes()
			sort.Slice(startNodes, func(i, j int) bool {
				return startNodes[i].ID() < startNodes[j].ID()
			})
			assert.Equal(t, expectNodes, startNodes)

			// sort the edges by from ID, then to ID
			// (the slices we get back are from map iteration, where order is not guaranteed)
			expectEdges := c.expect.graph.Edges()
			sort.Slice(expectEdges, func(i, j int) bool {
				if expectEdges[i].From().ID() == expectEdges[j].From().ID() {
					return expectEdges[i].To().ID() < expectEdges[j].To().ID()
				}
				return expectEdges[i].From().ID() < expectEdges[j].From().ID()
			})
			startEdges := c.start.graph.Edges()
			sort.Slice(startEdges, func(i, j int) bool {
				if startEdges[i].From().ID() == startEdges[j].From().ID() {
					return startEdges[i].To().ID() < startEdges[j].To().ID()
				}
				return startEdges[i].From().ID() < startEdges[j].From().ID()
			})
			assert.Equal(t, expectEdges, startEdges)

			// vertices is a recursive map, no need to sort
			assert.Equal(t, c.expect.vertices, c.start.vertices)
		})
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
 *
 * 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.
 *
 * @author		Aeneas Rekkas <aeneas+oss@aeneas.io>
 * @copyright 	2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
 * @license 	Apache-2.0
 */

package x

import (
	"net/http"

	"github.com/ory/fosite"
	"github.com/ory/x/logrusx"
)

var (
	ErrNotFound = &fosite.RFC6749Error{
		CodeField:        http.StatusNotFound,
		ErrorField:       http.StatusText(http.StatusNotFound),
		DescriptionField: "Unable to located the requested resource",
	}
	ErrConflict = &fosite.RFC6749Error{
		CodeField:        http.StatusConflict,
		ErrorField:       http.StatusText(http.StatusConflict),
		DescriptionField: "Unable to process the requested resource because of conflict in the current state",
	}
)

func LogError(r *http.Request, err error, logger *logrusx.Logger) {
	if logger == nil {
		logger = logrusx.New("", "")
	}

	logger.WithRequest(r).
		WithError(err).Errorln("An error occurred")
}
<commit_msg>fix: typo in errors.go (#2699)<commit_after>/*
 * Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
 *
 * 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.
 *
 * @author		Aeneas Rekkas <aeneas+oss@aeneas.io>
 * @copyright 	2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
 * @license 	Apache-2.0
 */

package x

import (
	"net/http"

	"github.com/ory/fosite"
	"github.com/ory/x/logrusx"
)

var (
	ErrNotFound = &fosite.RFC6749Error{
		CodeField:        http.StatusNotFound,
		ErrorField:       http.StatusText(http.StatusNotFound),
		DescriptionField: "Unable to locate the requested resource",
	}
	ErrConflict = &fosite.RFC6749Error{
		CodeField:        http.StatusConflict,
		ErrorField:       http.StatusText(http.StatusConflict),
		DescriptionField: "Unable to process the requested resource because of conflict in the current state",
	}
)

func LogError(r *http.Request, err error, logger *logrusx.Logger) {
	if logger == nil {
		logger = logrusx.New("", "")
	}

	logger.WithRequest(r).
		WithError(err).Errorln("An error occurred")
}
<|endoftext|>


<commit_before><commit_msg>server: rewrote call order tests as subtests<commit_after><|endoftext|>