<commit_before>package operator

import "connectordb/streamdb/operator/interfaces"

//Operator defines extension functions which work with any BaseOperatorInterface, adding extra functionality.
//In particular, Operator makes querying stuff by name easier
type Operator interfaces.Operator

//
// struct {
// 	interfaces.Operator
// }
//
// //SetAdmin does exactly what it claims. It works on both users and devices
// func (o *Operator) SetAdmin(path string, isadmin bool) error {
// 	switch strings.Count(path, "/") {
// 	default:
// 		return util.ErrBadPath
// 	case 0:
// 		u, err := o.ReadUser(path)
// 		if err != nil {
// 			return err
// 		}
// 		u.Admin = isadmin
// 		return o.UpdateUser(u)
// 	case 1:
// 		dev, err := o.ReadDevice(path)
// 		if err != nil {
// 			return err
// 		}
// 		dev.IsAdmin = isadmin
// 		return o.UpdateDevice(dev)
// 	}
// }
//
// //Subscribe given a path, attempts to subscribe to it and its childrens
// func (o *Operator) Subscribe(path string, chn chan messenger.Message) (*nats.Subscription, error) {
// 	switch strings.Count(path, "/") {
// 	default:
// 		return o.SubscribeStream(path, chn)
// 	case 0:
// 		return o.SubscribeUser(path, chn)
// 	case 1:
// 		return o.SubscribeDevice(path, chn)
// 	}
// }
//
// //ChangeUserPassword changes the password for the given user
// func (o *Operator) ChangeUserPassword(username, newpass string) error {
// 	u, err := o.ReadUser(username)
// 	if err != nil {
// 		return err
// 	}
// 	u.SetNewPassword(newpass)
// 	return o.UpdateUser(u)
// }
//
// //DeleteUser deletes a user given the user's name
// func (o *Operator) DeleteUser(username string) error {
// 	u, err := o.ReadUser(username)
// 	if err != nil {
// 		return err
// 	}
// 	return o.DeleteUserByID(u.UserId)
// }
//
// //ReadAllDevices for the given user
// func (o *Operator) ReadAllDevices(username string) ([]users.Device, error) {
// 	u, err := o.ReadUser(username)
// 	if err != nil {
// 		return nil, err
// 	}
// 	return o.ReadAllDevicesByUserID(u.UserId)
// }
//
// // ReadDevice reads the given device
// func (o *Operator) ReadDevice(devicepath string) (*users.Device, error) {
// 	//Apparently not. Get the device from userdb
// 	usrname, devname, err := util.SplitDevicePath(devicepath)
// 	if err != nil {
// 		return nil, err
// 	}
// 	u, err := o.ReadUser(usrname)
// 	if err != nil {
// 		return nil, err
// 	}
// 	dev, err := o.ReadDeviceByUserID(u.UserId, devname)
// 	return dev, err
// }
//
// //ReadStream reads the given stream
// func (o *Operator) ReadStream(streampath string) (*users.Stream, error) {
// 	//Make sure that substreams are stripped from read
// 	_, devicepath, streampath, streamname, _, err := util.SplitStreamPath(streampath)
// 	if err != nil {
// 		return nil, err
// 	}
//
// 	dev, err := o.ReadDevice(devicepath)
// 	if err != nil {
// 		return nil, err
// 	}
// 	return o.Userdb.ReadStreamByDeviceIdAndName(dev.DeviceId, streamname)
// }
//
// //CreateDevice creates a new device at the given path
// func (o *Operator) CreateDevice(devicepath string) error {
// 	userName, deviceName, err := util.SplitDevicePath(devicepath)
// 	if err != nil {
// 		return err
// 	}
// 	u, err := o.ReadUser(userName)
// 	if err != nil {
// 		return err
// 	}
//
// 	return o.CreateDeviceByUserID(u.UserId, deviceName)
// }
//
// //ChangeDeviceAPIKey generates a new api key for the given device, and returns the key
// func (o *Operator) ChangeDeviceAPIKey(devicepath string) (apikey string, err error) {
// 	dev, err := o.ReadDevice(devicepath)
// 	if err != nil {
// 		return "", err
// 	}
// 	newkey, err := uuid.NewV4()
// 	if err != nil {
// 		return "", err
// 	}
// 	dev.ApiKey = newkey.String()
// 	return dev.ApiKey, o.UpdateDevice(dev)
// }
//
// //DeleteDevice deletes an existing device
// func (o *Operator) DeleteDevice(devicepath string) error {
// 	dev, err := o.ReadDevice(devicepath)
// 	if err != nil {
// 		return err //Workaround for #81
// 	}
// 	return o.DeleteDeviceByID(dev.DeviceId)
// }
//
// //ReadAllStreams reads all the streams for the given device
// func (o *Operator) ReadAllStreams(devicepath string) ([]users.Stream, error) {
// 	dev, err := o.ReadDevice(devicepath)
// 	if err != nil {
// 		return nil, err
// 	}
// 	return o.ReadAllStreamsByDeviceID(dev.DeviceId)
// }
//
// //CreateStream makes a new stream
// func (o *Operator) CreateStream(streampath, jsonschema string) error {
// 	_, devicepath, _, streamname, _, err := util.SplitStreamPath(streampath)
// 	if err != nil {
// 		return err
// 	}
// 	dev, err := o.ReadDevice(devicepath)
// 	if err != nil {
// 		return err
// 	}
// 	return o.CreateStreamByDeviceID(dev.DeviceId, streamname, jsonschema)
// }
//
// //DeleteStream deletes the given stream given its path
// func (o *Operator) DeleteStream(streampath string) error {
// 	_, _, streampath, _, substream, err := util.SplitStreamPath(streampath)
// 	if err != nil {
// 		return err
// 	}
// 	s, err := o.ReadStream(streampath)
// 	if err != nil {
// 		return err
// 	}
// 	return o.DeleteStreamByID(s.StreamId, substream)
// }
//
// //LengthStream returns the total number of datapoints in the given stream
// func (o *Operator) LengthStream(streampath string) (int64, error) {
// 	_, _, streampath, _, substream, err := util.SplitStreamPath(streampath)
// 	if err != nil {
// 		return 0, err
// 	}
// 	strm, err := o.ReadStream(streampath)
// 	if err != nil {
// 		return 0, err
// 	}
// 	return o.LengthStreamByID(strm.StreamId, substream)
// }
//
// //TimeToIndexStream returns the index closest to the given timestamp
// func (o *Operator) TimeToIndexStream(streampath string, time float64) (int64, error) {
// 	_, _, streampath, _, substream, err := util.SplitStreamPath(streampath)
// 	if err != nil {
// 		return 0, err
// 	}
// 	strm, err := o.ReadStream(streampath)
// 	if err != nil {
// 		return 0, err
// 	}
// 	return o.TimeToIndexStreamByID(strm.StreamId, substream, time)
// }
//
// //InsertStream inserts the given array of datapoints into the given stream.
// func (o *Operator) InsertStream(streampath string, data datastream.DatapointArray, restamp bool) error {
// 	_, _, streampath, _, substream, err := util.SplitStreamPath(streampath)
// 	if err != nil {
// 		return err
// 	}
// 	strm, err := o.ReadStream(streampath)
// 	if err != nil {
// 		return err
// 	}
// 	return o.InsertStreamByID(strm.StreamId, substream, data, restamp)
// }
//
// //GetStreamTimeRange Reads the given stream by time range
// func (o *Operator) GetStreamTimeRange(streampath string, t1 float64, t2 float64, limit int64) (datastream.DataRange, error) {
// 	_, _, streampath, _, substream, err := util.SplitStreamPath(streampath)
// 	if err != nil {
// 		return nil, err
// 	}
// 	strm, err := o.ReadStream(streampath)
// 	if err != nil {
// 		return nil, err
// 	}
// 	return o.GetStreamTimeRangeByID(strm.StreamId, substream, t1, t2, limit)
// }
//
// //GetStreamIndexRange Reads the given stream by index range
// func (o *Operator) GetStreamIndexRange(streampath string, i1 int64, i2 int64) (datastream.DataRange, error) {
// 	_, _, streampath, _, substream, err := util.SplitStreamPath(streampath)
// 	if err != nil {
// 		return nil, err
// 	}
// 	strm, err := o.ReadStream(streampath)
// 	if err != nil {
// 		return nil, err
// 	}
// 	return o.GetStreamIndexRangeByID(strm.StreamId, substream, i1, i2)
// }
//
// //SubscribeUser subscribes to everything the user does
// func (o *Operator) SubscribeUser(username string, chn chan messenger.Message) (*nats.Subscription, error) {
// 	usr, err := o.ReadUser(username)
// 	if err != nil {
// 		return nil, err
// 	}
// 	return o.SubscribeUserByID(usr.UserId, chn)
// }
//
// //SubscribeDevice subscribes to everythnig the device does
// func (o *Operator) SubscribeDevice(devpath string, chn chan messenger.Message) (*nats.Subscription, error) {
// 	dev, err := o.ReadDevice(devpath)
// 	if err != nil {
// 		return nil, err
// 	}
// 	return o.SubscribeDeviceByID(dev.DeviceId, chn)
// }
//
// //SubscribeStream subscribes to the given stream
// func (o *Operator) SubscribeStream(streampath string, chn chan messenger.Message) (*nats.Subscription, error) {
// 	_, _, streampath, _, substream, err := util.SplitStreamPath(streampath)
// 	if err != nil {
// 		return nil, err
// 	}
// 	strm, err := o.ReadStream(streampath)
// 	if err != nil {
// 		return nil, err
// 	}
// 	return o.SubscribeStreamByID(strm.StreamId, substream, chn)
// }
<commit_msg>removed commented out code from operator<commit_after>package operator

import "connectordb/streamdb/operator/interfaces"

// Operator defines extension functions which work with any BaseOperator, adding
// the ability to query things by path without requiring permission specialization
type Operator interfaces.Operator
<|endoftext|>


<commit_before>// Copyright 2021 Google LLC. 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 witness is designed to make sure the checkpoints of verifiable logs
// are consistent and store/serve/sign them if so.  It is expected that a separate
// feeder component would be responsible for the actual interaction with logs.
package main

import (
	"context"
	"flag"
	"io/ioutil"

	"github.com/golang/glog"
	"github.com/google/trillian-examples/witness/golang/cmd/witness/impl"
	"golang.org/x/mod/sumdb/note"
	"gopkg.in/yaml.v2"
)

var (
	listenAddr = flag.String("listen", ":8000", "address:port to listen for requests on")
	dbFile     = flag.String("db_file", ":memory:", "path to a file to be used as sqlite3 storage for checkpoints, e.g. /tmp/chkpts.db")
	configFile = flag.String("config_file", "example.conf", "path to a YAML config file that specifies the logs followed by this witness")
	witnessSK  = flag.String("private_key", "", "private signing key for the witness")
)

func main() {
	flag.Parse()

	if *witnessSK == "" {
		glog.Exit("--private_key must not be empty")
	}
	signer, err := note.NewSigner(*witnessSK)
	if err != nil {
		glog.Exitf("Error forming a signer: %v", err)
	}

	if len(*configFile) == 0 {
		glog.Exit("--config_file must not be empty")
	}
	fileData, err := ioutil.ReadFile(*configFile)
	if err != nil {
		glog.Exitf("Failed to read from config file: %v", err)
	}
	var js impl.LogConfig
	if err := yaml.Unmarshal(fileData, &js); err != nil {
		glog.Exitf("Failed to parse config file as proper JSON: %v", err)
	}

	ctx := context.Background()
	if err := impl.Main(ctx, impl.ServerOpts{
		ListenAddr: *listenAddr,
		DBFile:     *dbFile,
		Signer:     signer,
		Config:     js,
	}); err != nil {
		glog.Exitf("Error running witness: %v", err)
	}
}
<commit_msg>updated error to reflect config now YAML (#502)<commit_after>// Copyright 2021 Google LLC. 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 witness is designed to make sure the checkpoints of verifiable logs
// are consistent and store/serve/sign them if so.  It is expected that a separate
// feeder component would be responsible for the actual interaction with logs.
package main

import (
	"context"
	"flag"
	"io/ioutil"

	"github.com/golang/glog"
	"github.com/google/trillian-examples/witness/golang/cmd/witness/impl"
	"golang.org/x/mod/sumdb/note"
	"gopkg.in/yaml.v2"
)

var (
	listenAddr = flag.String("listen", ":8000", "address:port to listen for requests on")
	dbFile     = flag.String("db_file", ":memory:", "path to a file to be used as sqlite3 storage for checkpoints, e.g. /tmp/chkpts.db")
	configFile = flag.String("config_file", "example.conf", "path to a YAML config file that specifies the logs followed by this witness")
	witnessSK  = flag.String("private_key", "", "private signing key for the witness")
)

func main() {
	flag.Parse()

	if *witnessSK == "" {
		glog.Exit("--private_key must not be empty")
	}
	signer, err := note.NewSigner(*witnessSK)
	if err != nil {
		glog.Exitf("Error forming a signer: %v", err)
	}

	if len(*configFile) == 0 {
		glog.Exit("--config_file must not be empty")
	}
	fileData, err := ioutil.ReadFile(*configFile)
	if err != nil {
		glog.Exitf("Failed to read from config file: %v", err)
	}
	var js impl.LogConfig
	if err := yaml.Unmarshal(fileData, &js); err != nil {
		glog.Exitf("Failed to parse config file as proper YAML: %v", err)
	}

	ctx := context.Background()
	if err := impl.Main(ctx, impl.ServerOpts{
		ListenAddr: *listenAddr,
		DBFile:     *dbFile,
		Signer:     signer,
		Config:     js,
	}); err != nil {
		glog.Exitf("Error running witness: %v", err)
	}
}
<|endoftext|>


<commit_before>package create

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

	"github.com/hashicorp/consul/api"
	"github.com/hashicorp/consul/command/flags"
	"github.com/hashicorp/consul/command/intention/finder"
	"github.com/mitchellh/cli"
)

func New(ui cli.Ui) *cmd {
	c := &cmd{UI: ui}
	c.init()
	return c
}

type cmd struct {
	UI    cli.Ui
	flags *flag.FlagSet
	http  *flags.HTTPFlags
	help  string

	// flags
	flagAllow   bool
	flagDeny    bool
	flagFile    bool
	flagReplace bool
	flagMeta    map[string]string

	// testStdin is the input for testing.
	testStdin io.Reader
}

func (c *cmd) init() {
	c.flags = flag.NewFlagSet("", flag.ContinueOnError)
	c.flags.BoolVar(&c.flagAllow, "allow", false,
		"Create an intention that allows when matched.")
	c.flags.BoolVar(&c.flagDeny, "deny", false,
		"Create an intention that denies when matched.")
	c.flags.BoolVar(&c.flagFile, "file", false,
		"Read intention data from one or more files.")
	c.flags.BoolVar(&c.flagReplace, "replace", false,
		"Replace matching intentions. This is not an atomic operation. "+
			"If the insert fails, then the previous intention will still be deleted.")
	c.flags.Var((*flags.FlagMapValue)(&c.flagMeta), "meta",
		"Metadata to set on the intention, formatted as key=value. This flag "+
			"may be specified multiple times to set multiple meta fields.")

	c.http = &flags.HTTPFlags{}
	flags.Merge(c.flags, c.http.ClientFlags())
	flags.Merge(c.flags, c.http.ServerFlags())
	c.help = flags.Usage(help, c.flags)
}

func (c *cmd) Run(args []string) int {
	if err := c.flags.Parse(args); err != nil {
		return 1
	}

	// Default to allow
	if !c.flagAllow && !c.flagDeny {
		c.flagAllow = true
	}

	// If both are specified it is an error
	if c.flagAllow && c.flagDeny {
		c.UI.Error("Only one of -allow or -deny may be specified.")
		return 1
	}

	// Check for arg validation
	args = c.flags.Args()
	ixns, err := c.ixnsFromArgs(args)
	if err != nil {
		c.UI.Error(fmt.Sprintf("Error: %s", err))
		return 1
	}

	// Create and test the HTTP client
	client, err := c.http.APIClient()
	if err != nil {
		c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err))
		return 1
	}

	// Create the finder in case we need it
	find := &finder.Finder{Client: client}

	// Go through and create each intention
	for _, ixn := range ixns {
		// If replace is set to true, then find this intention and delete it.
		if c.flagReplace {
			ixn, err := find.Find(ixn.SourceString(), ixn.DestinationString())
			if err != nil {
				c.UI.Error(fmt.Sprintf(
					"Error looking up intention for replacement with source %q "+
						"and destination %q: %s",
					ixn.SourceString(),
					ixn.DestinationString(),
					err))
				return 1
			}
			if ixn != nil {
				if _, err := client.Connect().IntentionDelete(ixn.ID, nil); err != nil {
					c.UI.Error(fmt.Sprintf(
						"Error deleting intention for replacement with source %q "+
							"and destination %q: %s",
						ixn.SourceString(),
						ixn.DestinationString(),
						err))
					return 1
				}
			}
		}

		_, _, err := client.Connect().IntentionCreate(ixn, nil)
		if err != nil {
			c.UI.Error(fmt.Sprintf("Error creating intention %q: %s", ixn, err))
			return 1
		}

		c.UI.Output(fmt.Sprintf("Created: %s", ixn))
	}

	return 0
}

// ixnsFromArgs returns the set of intentions to create based on the arguments
// given and the flags set. This will call ixnsFromFiles if the -file flag
// was set.
func (c *cmd) ixnsFromArgs(args []string) ([]*api.Intention, error) {
	// If we're in file mode, load from files
	if c.flagFile {
		return c.ixnsFromFiles(args)
	}

	// From args we require exactly two
	if len(args) != 2 {
		return nil, fmt.Errorf("Must specify two arguments: source and destination")
	}

	return []*api.Intention{&api.Intention{
		SourceName:      args[0],
		DestinationName: args[1],
		SourceType:      api.IntentionSourceConsul,
		Action:          c.ixnAction(),
		Meta:            c.flagMeta,
	}}, nil
}

func (c *cmd) ixnsFromFiles(args []string) ([]*api.Intention, error) {
	var result []*api.Intention
	for _, path := range args {
		f, err := os.Open(path)
		if err != nil {
			return nil, err
		}

		var ixn api.Intention
		err = json.NewDecoder(f).Decode(&ixn)
		f.Close()
		if err != nil {
			return nil, err
		}

		result = append(result, &ixn)
	}

	return result, nil
}

// ixnAction returns the api.IntentionAction based on the flag set.
func (c *cmd) ixnAction() api.IntentionAction {
	if c.flagAllow {
		return api.IntentionActionAllow
	}

	return api.IntentionActionDeny
}

func (c *cmd) Synopsis() string {
	return synopsis
}

func (c *cmd) Help() string {
	return c.help
}

const synopsis = "Create intentions for service connections."
const help = `
Usage: consul intention create [options] SRC DST
Usage: consul intention create [options] -file FILE...

  Create one or more intentions. The data can be specified as a single
  source and destination pair or via a set of files when the "-file" flag
  is specified.

      $ consul intention create web db

  To consume data from a set of files:

      $ consul intention create -file one.json two.json

  When specifying the "-file" flag, "-" may be used once to read from stdin:

      $ echo "{ ... }" | consul intention create -file -

  An "allow" intention is created by default (whitelist). To create a
  "deny" intention, the "-deny" flag should be specified.

  If a conflicting intention is found, creation will fail. To replace any
  conflicting intentions, specify the "-replace" flag. This will replace any
  conflicting intentions with the intention specified in this command.
  Metadata and any other fields of the previous intention will not be
  preserved.

  Additional flags and more advanced use cases are detailed below.
`
<commit_msg>command/intention/create: -replace does an atomic change<commit_after>package create

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

	"github.com/hashicorp/consul/api"
	"github.com/hashicorp/consul/command/flags"
	"github.com/hashicorp/consul/command/intention/finder"
	"github.com/mitchellh/cli"
)

func New(ui cli.Ui) *cmd {
	c := &cmd{UI: ui}
	c.init()
	return c
}

type cmd struct {
	UI    cli.Ui
	flags *flag.FlagSet
	http  *flags.HTTPFlags
	help  string

	// flags
	flagAllow   bool
	flagDeny    bool
	flagFile    bool
	flagReplace bool
	flagMeta    map[string]string

	// testStdin is the input for testing.
	testStdin io.Reader
}

func (c *cmd) init() {
	c.flags = flag.NewFlagSet("", flag.ContinueOnError)
	c.flags.BoolVar(&c.flagAllow, "allow", false,
		"Create an intention that allows when matched.")
	c.flags.BoolVar(&c.flagDeny, "deny", false,
		"Create an intention that denies when matched.")
	c.flags.BoolVar(&c.flagFile, "file", false,
		"Read intention data from one or more files.")
	c.flags.BoolVar(&c.flagReplace, "replace", false,
		"Replace matching intentions.")
	c.flags.Var((*flags.FlagMapValue)(&c.flagMeta), "meta",
		"Metadata to set on the intention, formatted as key=value. This flag "+
			"may be specified multiple times to set multiple meta fields.")

	c.http = &flags.HTTPFlags{}
	flags.Merge(c.flags, c.http.ClientFlags())
	flags.Merge(c.flags, c.http.ServerFlags())
	c.help = flags.Usage(help, c.flags)
}

func (c *cmd) Run(args []string) int {
	if err := c.flags.Parse(args); err != nil {
		return 1
	}

	// Default to allow
	if !c.flagAllow && !c.flagDeny {
		c.flagAllow = true
	}

	// If both are specified it is an error
	if c.flagAllow && c.flagDeny {
		c.UI.Error("Only one of -allow or -deny may be specified.")
		return 1
	}

	// Check for arg validation
	args = c.flags.Args()
	ixns, err := c.ixnsFromArgs(args)
	if err != nil {
		c.UI.Error(fmt.Sprintf("Error: %s", err))
		return 1
	}

	// Create and test the HTTP client
	client, err := c.http.APIClient()
	if err != nil {
		c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err))
		return 1
	}

	// Create the finder in case we need it
	find := &finder.Finder{Client: client}

	// Go through and create each intention
	for _, ixn := range ixns {
		// If replace is set to true, then find this intention and delete it.
		if c.flagReplace {
			oldIxn, err := find.Find(ixn.SourceString(), ixn.DestinationString())
			if err != nil {
				c.UI.Error(fmt.Sprintf(
					"Error looking up intention for replacement with source %q "+
						"and destination %q: %s",
					ixn.SourceString(),
					ixn.DestinationString(),
					err))
				return 1
			}
			if oldIxn != nil {
				// We set the ID of our intention so we overwrite it
				ixn.ID = oldIxn.ID

				if _, err := client.Connect().IntentionUpdate(ixn, nil); err != nil {
					c.UI.Error(fmt.Sprintf(
						"Error replacing intention with source %q "+
							"and destination %q: %s",
						ixn.SourceString(),
						ixn.DestinationString(),
						err))
					return 1
				}

				// Continue since we don't want to try to insert a new intention
				continue
			}
		}

		_, _, err := client.Connect().IntentionCreate(ixn, nil)
		if err != nil {
			c.UI.Error(fmt.Sprintf("Error creating intention %q: %s", ixn, err))
			return 1
		}

		c.UI.Output(fmt.Sprintf("Created: %s", ixn))
	}

	return 0
}

// ixnsFromArgs returns the set of intentions to create based on the arguments
// given and the flags set. This will call ixnsFromFiles if the -file flag
// was set.
func (c *cmd) ixnsFromArgs(args []string) ([]*api.Intention, error) {
	// If we're in file mode, load from files
	if c.flagFile {
		return c.ixnsFromFiles(args)
	}

	// From args we require exactly two
	if len(args) != 2 {
		return nil, fmt.Errorf("Must specify two arguments: source and destination")
	}

	return []*api.Intention{&api.Intention{
		SourceName:      args[0],
		DestinationName: args[1],
		SourceType:      api.IntentionSourceConsul,
		Action:          c.ixnAction(),
		Meta:            c.flagMeta,
	}}, nil
}

func (c *cmd) ixnsFromFiles(args []string) ([]*api.Intention, error) {
	var result []*api.Intention
	for _, path := range args {
		f, err := os.Open(path)
		if err != nil {
			return nil, err
		}

		var ixn api.Intention
		err = json.NewDecoder(f).Decode(&ixn)
		f.Close()
		if err != nil {
			return nil, err
		}

		result = append(result, &ixn)
	}

	return result, nil
}

// ixnAction returns the api.IntentionAction based on the flag set.
func (c *cmd) ixnAction() api.IntentionAction {
	if c.flagAllow {
		return api.IntentionActionAllow
	}

	return api.IntentionActionDeny
}

func (c *cmd) Synopsis() string {
	return synopsis
}

func (c *cmd) Help() string {
	return c.help
}

const synopsis = "Create intentions for service connections."
const help = `
Usage: consul intention create [options] SRC DST
Usage: consul intention create [options] -file FILE...

  Create one or more intentions. The data can be specified as a single
  source and destination pair or via a set of files when the "-file" flag
  is specified.

      $ consul intention create web db

  To consume data from a set of files:

      $ consul intention create -file one.json two.json

  When specifying the "-file" flag, "-" may be used once to read from stdin:

      $ echo "{ ... }" | consul intention create -file -

  An "allow" intention is created by default (whitelist). To create a
  "deny" intention, the "-deny" flag should be specified.

  If a conflicting intention is found, creation will fail. To replace any
  conflicting intentions, specify the "-replace" flag. This will replace any
  conflicting intentions with the intention specified in this command.
  Metadata and any other fields of the previous intention will not be
  preserved.

  Additional flags and more advanced use cases are detailed below.
`
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"io"
	"os"

	"github.com/git-lfs/git-lfs/errors"
	"github.com/git-lfs/git-lfs/filepathfilter"
	"github.com/git-lfs/git-lfs/git"
	"github.com/git-lfs/git-lfs/lfs"
	"github.com/spf13/cobra"
)

const (
	// cleanFilterBufferCapacity is the desired capacity of the
	// `*git.PacketWriter`'s internal buffer when the filter protocol
	// dictates the "clean" command. 512 bytes is (in most cases) enough to
	// hold an entire LFS pointer in memory.
	cleanFilterBufferCapacity = 512

	// smudgeFilterBufferCapacity is the desired capacity of the
	// `*git.PacketWriter`'s internal buffer when the filter protocol
	// dictates the "smudge" command.
	smudgeFilterBufferCapacity = git.MaxPacketLength
)

// filterSmudgeSkip is a command-line flag owned by the `filter-process` command
// dictating whether or not to skip the smudging process, leaving pointers as-is
// in the working tree.
var filterSmudgeSkip bool

func filterCommand(cmd *cobra.Command, args []string) {
	requireStdin("This command should be run by the Git filter process")
	lfs.InstallHooks(false)

	s := git.NewFilterProcessScanner(os.Stdin, os.Stdout)

	if err := s.Init(); err != nil {
		ExitWithError(err)
	}
	if err := s.NegotiateCapabilities(); err != nil {
		ExitWithError(err)
	}

	skip := filterSmudgeSkip || cfg.Os.Bool("GIT_LFS_SKIP_SMUDGE", false)
	filter := filepathfilter.New(cfg.FetchIncludePaths(), cfg.FetchExcludePaths())

	var malformed []string

	for s.Scan() {
		var err error
		var w *git.PktlineWriter

		req := s.Request()

		s.WriteStatus(statusFromErr(nil))

		switch req.Header["command"] {
		case "clean":
			w = git.NewPktlineWriter(os.Stdout, cleanFilterBufferCapacity)
			err = clean(w, req.Payload, req.Header["pathname"])
		case "smudge":
			w = git.NewPktlineWriter(os.Stdout, smudgeFilterBufferCapacity)
			err = smudge(w, req.Payload, req.Header["pathname"], skip, filter)
		default:
			ExitWithError(fmt.Errorf("Unknown command %q", req.Header["command"]))
		}

		if errors.IsNotAPointerError(err) {
			malformed = append(malformed, req.Header["pathname"])
			err = nil
		}

		var status string
		if ferr := w.Flush(); ferr != nil {
			status = statusFromErr(ferr)
		} else {
			status = statusFromErr(err)
		}

		s.WriteStatus(status)
	}

	if len(malformed) > 0 {
		fmt.Fprintf(os.Stderr, "Encountered %d files that should have been pointers, but weren't:\n", len(malformed))
		for _, m := range malformed {
			fmt.Fprintf(os.Stderr, "\t%s\n", m)
		}
	}

	if err := s.Err(); err != nil && err != io.EOF {
		ExitWithError(err)
	}
}

// statusFromErr returns the status code that should be sent over the filter
// protocol based on a given error, "err".
func statusFromErr(err error) string {
	if err != nil && err != io.EOF {
		return "error"
	}
	return "success"
}

func init() {
	RegisterCommand("filter-process", filterCommand, func(cmd *cobra.Command) {
		cmd.Flags().BoolVarP(&filterSmudgeSkip, "skip", "s", false, "")
	})
}
<commit_msg>commands/fp: sort of pluralize "file(s)"<commit_after>package commands

import (
	"fmt"
	"io"
	"os"

	"github.com/git-lfs/git-lfs/errors"
	"github.com/git-lfs/git-lfs/filepathfilter"
	"github.com/git-lfs/git-lfs/git"
	"github.com/git-lfs/git-lfs/lfs"
	"github.com/spf13/cobra"
)

const (
	// cleanFilterBufferCapacity is the desired capacity of the
	// `*git.PacketWriter`'s internal buffer when the filter protocol
	// dictates the "clean" command. 512 bytes is (in most cases) enough to
	// hold an entire LFS pointer in memory.
	cleanFilterBufferCapacity = 512

	// smudgeFilterBufferCapacity is the desired capacity of the
	// `*git.PacketWriter`'s internal buffer when the filter protocol
	// dictates the "smudge" command.
	smudgeFilterBufferCapacity = git.MaxPacketLength
)

// filterSmudgeSkip is a command-line flag owned by the `filter-process` command
// dictating whether or not to skip the smudging process, leaving pointers as-is
// in the working tree.
var filterSmudgeSkip bool

func filterCommand(cmd *cobra.Command, args []string) {
	requireStdin("This command should be run by the Git filter process")
	lfs.InstallHooks(false)

	s := git.NewFilterProcessScanner(os.Stdin, os.Stdout)

	if err := s.Init(); err != nil {
		ExitWithError(err)
	}
	if err := s.NegotiateCapabilities(); err != nil {
		ExitWithError(err)
	}

	skip := filterSmudgeSkip || cfg.Os.Bool("GIT_LFS_SKIP_SMUDGE", false)
	filter := filepathfilter.New(cfg.FetchIncludePaths(), cfg.FetchExcludePaths())

	var malformed []string

	for s.Scan() {
		var err error
		var w *git.PktlineWriter

		req := s.Request()

		s.WriteStatus(statusFromErr(nil))

		switch req.Header["command"] {
		case "clean":
			w = git.NewPktlineWriter(os.Stdout, cleanFilterBufferCapacity)
			err = clean(w, req.Payload, req.Header["pathname"])
		case "smudge":
			w = git.NewPktlineWriter(os.Stdout, smudgeFilterBufferCapacity)
			err = smudge(w, req.Payload, req.Header["pathname"], skip, filter)
		default:
			ExitWithError(fmt.Errorf("Unknown command %q", req.Header["command"]))
		}

		if errors.IsNotAPointerError(err) {
			malformed = append(malformed, req.Header["pathname"])
			err = nil
		}

		var status string
		if ferr := w.Flush(); ferr != nil {
			status = statusFromErr(ferr)
		} else {
			status = statusFromErr(err)
		}

		s.WriteStatus(status)
	}

	if len(malformed) > 0 {
		fmt.Fprintf(os.Stderr, "Encountered %d file(s) that should have been pointers, but weren't:\n", len(malformed))
		for _, m := range malformed {
			fmt.Fprintf(os.Stderr, "\t%s\n", m)
		}
	}

	if err := s.Err(); err != nil && err != io.EOF {
		ExitWithError(err)
	}
}

// statusFromErr returns the status code that should be sent over the filter
// protocol based on a given error, "err".
func statusFromErr(err error) string {
	if err != nil && err != io.EOF {
		return "error"
	}
	return "success"
}

func init() {
	RegisterCommand("filter-process", filterCommand, func(cmd *cobra.Command) {
		cmd.Flags().BoolVarP(&filterSmudgeSkip, "skip", "s", false, "")
	})
}
<|endoftext|>


<commit_before>package file

import (
	"fmt"
	"hash"
	"hash/crc32"
	"io"
	"io/ioutil"
	"os"
)

func Checksum32(path string) uint32 {
	file, _ := os.Open(path)
	defer file.Close()
	c := crc32.NewIEEE()
	bytes, _ := ioutil.ReadAll(file)
	withcrc := c.Sum(bytes)
	return crc32.ChecksumIEEE(withcrc)
}

func Hash(hasher hash.Hash, path string) ([]byte, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	if _, err := io.Copy(hasher, f); err != nil {
		return nil, err
	}
	return hasher.Sum(nil), nil
}

func HashStr(hasher hash.Hash, path string) (string, error) {
	if csum, err := Hash(hasher, path); err != nil {
		return "", err
	} else {
		return fmt.Sprintf("%x", csum), nil
	}
}

func IsDir(path string) bool {
	finfo, err := os.Stat(path)
	switch {
	case err != nil:
		return false
	case finfo.IsDir():
		return true
	default:
		return false
	}
}

func Exists(path string) bool {
	_, err := os.Stat(path)
	return !os.IsNotExist(err)
}

func Copy(src, dest string) error {
	fsrc, err := os.Open(src)
	if err != nil {
		return err
	}
	defer fsrc.Close()

	fdest, err := os.Create(dest)
	if err != nil {
		return err
	}
	defer fdest.Close()

	if _, err := io.Copy(fdest, fsrc); err != nil {
		return err
	}

	return nil
}
<commit_msg>Add routine to normalize all file paths to forward slashes.<commit_after>package file

import (
	"fmt"
	"hash"
	"hash/crc32"
	"io"
	"io/ioutil"
	"os"
	"strings"
)

func NormalizePath(path string) string {
	return strings.Replace(path, "\\", "/", -1)
}

func Checksum32(path string) uint32 {
	file, _ := os.Open(path)
	defer file.Close()
	c := crc32.NewIEEE()
	bytes, _ := ioutil.ReadAll(file)
	withcrc := c.Sum(bytes)
	return crc32.ChecksumIEEE(withcrc)
}

func Hash(hasher hash.Hash, path string) ([]byte, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	if _, err := io.Copy(hasher, f); err != nil {
		return nil, err
	}
	return hasher.Sum(nil), nil
}

func HashStr(hasher hash.Hash, path string) (string, error) {
	if csum, err := Hash(hasher, path); err != nil {
		return "", err
	} else {
		return fmt.Sprintf("%x", csum), nil
	}
}

func IsDir(path string) bool {
	finfo, err := os.Stat(path)
	switch {
	case err != nil:
		return false
	case finfo.IsDir():
		return true
	default:
		return false
	}
}

func Exists(path string) bool {
	_, err := os.Stat(path)
	return !os.IsNotExist(err)
}

func Copy(src, dest string) error {
	fsrc, err := os.Open(src)
	if err != nil {
		return err
	}
	defer fsrc.Close()

	fdest, err := os.Create(dest)
	if err != nil {
		return err
	}
	defer fdest.Close()

	if _, err := io.Copy(fdest, fsrc); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://github.com/go-ego/ego/blob/master/LICENSE
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

package file

// package gt

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"path"
	"strings"

	"io/ioutil"
	"path/filepath"
)

// Read read file and return string
func Read(fileName string) (string, error) {
	fin, err := os.Open(fileName)
	if err != nil {
		// log.Println("os.Open: ", fileName, err)
		return "", err
	}
	defer fin.Close()

	var str string
	buf := make([]byte, 1024)
	for {
		n, _ := fin.Read(buf)
		if 0 == n {
			break
		}
		// os.Stdout.Write(buf[:n])
		strBuf := string(buf[:n])
		str += strBuf
	}

	return str, nil
}

// WriteFile writes data to a file named by filename.
// If the file does not exist, WriteFile creates it
// and its upper level paths.
func WriteFile(fileName string, data []byte) error {
	os.MkdirAll(path.Dir(fileName), os.ModePerm)
	return ioutil.WriteFile(fileName, data, 0655)
}

// Write writes data to a file named by filename.
// If the file does not exist, WriteFile creates it
// and its upper level paths.
func Write(fileName, writeStr string) error {
	os.MkdirAll(path.Dir(fileName), os.ModePerm)

	fout, err := os.Create(fileName)
	if err != nil {
		// log.Println("Write file "+fileName, err)
		return err
	}
	defer fout.Close()

	_, err = fout.WriteString(writeStr)
	return err
}

// ReadIo read file return io.Reader
func ReadIo(fileName string) (io.Reader, error) {
	f, err := os.Open(fileName)
	if err != nil {
		return nil, err
	}

	reader := bufio.NewReader(f)
	return reader, err
}

// WriteIo wite file with io.Reader
func WriteIo(fileName string, fio io.Reader) error {
	data, err := ioutil.ReadAll(fio)
	if err != nil {
		return err
	}

	return ioutil.WriteFile(fileName, data, 0655)
}

// ReadFromIO read io.Reader return string and error
func ReadFromIO(fio io.Reader) (string, error) {
	b, err := ioutil.ReadAll(fio)
	if err != nil {
		return "", err
	}

	return string(b), nil
}

// AppendTo append to file
func AppendTo(fileName, content string) error {
	// write only
	f, err := os.OpenFile(fileName, os.O_WRONLY, 0644)
	if err != nil {
		log.Println("File open failed. err: " + err.Error())
		return err
	}

	n, _ := f.Seek(0, os.SEEK_END)
	_, err = f.WriteAt([]byte(content), n)

	f.Close()
	return err
}

// Empty empty the file
func Empty(fileName string, args ...int64) {
	var size int64
	if len(args) > 0 {
		size = args[0]
	}

	os.Truncate(fileName, size)
}

// List list file
func List(dirPth, suffix string) (files []string, err error) {
	files = make([]string, 0, 10)
	dir, err := ioutil.ReadDir(dirPth)
	if err != nil {
		return nil, err
	}

	PthSep := string(os.PathSeparator)
	suffix = strings.ToUpper(suffix)
	for _, fi := range dir {
		if fi.IsDir() {
			continue
		}
		if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) {
			files = append(files, dirPth+PthSep+fi.Name())
		}
	}

	return files, nil
}

// ListDir list dir
func ListDir(dirPth, suffix string) (files []string, err error) {
	files = make([]string, 0, 10)
	dir, err := ioutil.ReadDir(dirPth)
	if err != nil {
		return nil, err
	}

	PthSep := string(os.PathSeparator)
	suffix = strings.ToUpper(suffix)
	for _, fi := range dir {
		if !fi.IsDir() {
			continue
		}
		if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) {
			files = append(files, dirPth+PthSep+fi.Name())
		}
	}

	return files, nil
}

// Walk walk file
func Walk(dirPth, suffix string) (files []string, err error) {
	files = make([]string, 0, 30)
	suffix = strings.ToUpper(suffix)
	err = filepath.Walk(
		dirPth, func(filename string, fi os.FileInfo, err error) error {
			if fi.IsDir() {
				return nil
			}

			if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) {
				files = append(files, filename)
			}
			return nil
		})

	return files, err
}

// WalkDir walk dir
func WalkDir(dirPth, suffix string) (files []string, err error) {
	files = make([]string, 0, 30)
	suffix = strings.ToUpper(suffix)
	err = filepath.Walk(
		dirPth, func(filename string, fi os.FileInfo, err error) error {
			if !fi.IsDir() {
				return nil
			}

			if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) {
				files = append(files, filename)
			}
			return nil
		})

	return files, err
}

// Copy copies file from source to target path.
func Copy(src, dst string) error {
	// Gather file information to set back later.
	si, err := os.Lstat(src)
	if err != nil {
		return err
	}

	// Handle symbolic link.
	if si.Mode()&os.ModeSymlink != 0 {
		target, err := os.Readlink(src)
		if err != nil {
			return err
		}
		// NOTE: os.Chmod and os.Chtimes don't recoganize symbolic link,
		// which will lead "no such file or directory" error.
		return os.Symlink(target, dst)
	}

	sr, err := os.Open(src)
	if err != nil {
		return err
	}
	defer sr.Close()

	dw, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer dw.Close()

	if _, err = io.Copy(dw, sr); err != nil {
		return err
	}

	// Set back file information.
	if err = os.Chtimes(dst, si.ModTime(), si.ModTime()); err != nil {
		return err
	}

	return os.Chmod(dst, si.Mode())
}

// CopyFile copies file from source to target path.
func CopyFile(src, dst string) (int64, error) {
	srcFile, err := os.Open(src)
	if err != nil {
		return 0, err
	}
	defer srcFile.Close()

	// if Exist(dst) != true {
	if !Exist(dst) {
		Write(dst, "")
	}

	dstFile, err := os.Create(dst)
	if err != nil {
		// fmt.Println(err.Error())
		return 0, err
	}
	defer dstFile.Close()

	return io.Copy(dstFile, srcFile)
}

// OpenCopy open and copy file
func OpenCopy(srcName, dstName string) (int64, error) {
	src, err := os.Open(srcName)
	if err != nil {
		return 0, err
	}
	defer src.Close()

	dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		fmt.Println(err)
		return 0, err
	}
	defer dst.Close()

	return io.Copy(dst, src)
}
<commit_msg>remove error log print<commit_after>// Copyright 2016 The go-vgo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://github.com/go-ego/ego/blob/master/LICENSE
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

package file

// package gt

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"path"
	"strings"

	"io/ioutil"
	"path/filepath"
)

// Read read file and return string
func Read(fileName string) (string, error) {
	fin, err := os.Open(fileName)
	if err != nil {
		// log.Println("os.Open: ", fileName, err)
		return "", err
	}
	defer fin.Close()

	var str string
	buf := make([]byte, 1024)
	for {
		n, _ := fin.Read(buf)
		if 0 == n {
			break
		}
		// os.Stdout.Write(buf[:n])
		strBuf := string(buf[:n])
		str += strBuf
	}

	return str, nil
}

// WriteFile writes data to a file named by filename.
// If the file does not exist, WriteFile creates it
// and its upper level paths.
func WriteFile(fileName string, data []byte) error {
	os.MkdirAll(path.Dir(fileName), os.ModePerm)
	return ioutil.WriteFile(fileName, data, 0655)
}

// Write writes data to a file named by filename.
// If the file does not exist, WriteFile creates it
// and its upper level paths.
func Write(fileName, writeStr string) error {
	os.MkdirAll(path.Dir(fileName), os.ModePerm)

	fout, err := os.Create(fileName)
	if err != nil {
		// log.Println("Write file "+fileName, err)
		return err
	}
	defer fout.Close()

	_, err = fout.WriteString(writeStr)
	return err
}

// ReadIo read file return io.Reader
func ReadIo(fileName string) (io.Reader, error) {
	f, err := os.Open(fileName)
	if err != nil {
		return nil, err
	}

	reader := bufio.NewReader(f)
	return reader, err
}

// WriteIo wite file with io.Reader
func WriteIo(fileName string, fio io.Reader) error {
	data, err := ioutil.ReadAll(fio)
	if err != nil {
		return err
	}

	return ioutil.WriteFile(fileName, data, 0655)
}

// ReadFromIO read io.Reader return string and error
func ReadFromIO(fio io.Reader) (string, error) {
	b, err := ioutil.ReadAll(fio)
	if err != nil {
		return "", err
	}

	return string(b), nil
}

// AppendTo append to file
func AppendTo(fileName, content string) error {
	// write only
	f, err := os.OpenFile(fileName, os.O_WRONLY, 0644)
	if err != nil {
		// log.Println("File open failed. err: " + err.Error())
		return err
	}

	n, _ := f.Seek(0, os.SEEK_END)
	_, err = f.WriteAt([]byte(content), n)

	f.Close()
	return err
}

// Empty empty the file
func Empty(fileName string, args ...int64) {
	var size int64
	if len(args) > 0 {
		size = args[0]
	}

	os.Truncate(fileName, size)
}

// List list file
func List(dirPth, suffix string) (files []string, err error) {
	files = make([]string, 0, 10)
	dir, err := ioutil.ReadDir(dirPth)
	if err != nil {
		return nil, err
	}

	PthSep := string(os.PathSeparator)
	suffix = strings.ToUpper(suffix)
	for _, fi := range dir {
		if fi.IsDir() {
			continue
		}
		if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) {
			files = append(files, dirPth+PthSep+fi.Name())
		}
	}

	return files, nil
}

// ListDir list dir
func ListDir(dirPth, suffix string) (files []string, err error) {
	files = make([]string, 0, 10)
	dir, err := ioutil.ReadDir(dirPth)
	if err != nil {
		return nil, err
	}

	PthSep := string(os.PathSeparator)
	suffix = strings.ToUpper(suffix)
	for _, fi := range dir {
		if !fi.IsDir() {
			continue
		}
		if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) {
			files = append(files, dirPth+PthSep+fi.Name())
		}
	}

	return files, nil
}

// Walk walk file
func Walk(dirPth, suffix string) (files []string, err error) {
	files = make([]string, 0, 30)
	suffix = strings.ToUpper(suffix)
	err = filepath.Walk(
		dirPth, func(filename string, fi os.FileInfo, err error) error {
			if fi.IsDir() {
				return nil
			}

			if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) {
				files = append(files, filename)
			}
			return nil
		})

	return files, err
}

// WalkDir walk dir
func WalkDir(dirPth, suffix string) (files []string, err error) {
	files = make([]string, 0, 30)
	suffix = strings.ToUpper(suffix)
	err = filepath.Walk(
		dirPth, func(filename string, fi os.FileInfo, err error) error {
			if !fi.IsDir() {
				return nil
			}

			if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) {
				files = append(files, filename)
			}
			return nil
		})

	return files, err
}

// Copy copies file from source to target path.
func Copy(src, dst string) error {
	// Gather file information to set back later.
	si, err := os.Lstat(src)
	if err != nil {
		return err
	}

	// Handle symbolic link.
	if si.Mode()&os.ModeSymlink != 0 {
		target, err := os.Readlink(src)
		if err != nil {
			return err
		}
		// NOTE: os.Chmod and os.Chtimes don't recoganize symbolic link,
		// which will lead "no such file or directory" error.
		return os.Symlink(target, dst)
	}

	sr, err := os.Open(src)
	if err != nil {
		return err
	}
	defer sr.Close()

	dw, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer dw.Close()

	if _, err = io.Copy(dw, sr); err != nil {
		return err
	}

	// Set back file information.
	if err = os.Chtimes(dst, si.ModTime(), si.ModTime()); err != nil {
		return err
	}

	return os.Chmod(dst, si.Mode())
}

// CopyFile copies file from source to target path.
func CopyFile(src, dst string) (int64, error) {
	srcFile, err := os.Open(src)
	if err != nil {
		return 0, err
	}
	defer srcFile.Close()

	// if Exist(dst) != true {
	if !Exist(dst) {
		Write(dst, "")
	}

	dstFile, err := os.Create(dst)
	if err != nil {
		// fmt.Println(err.Error())
		return 0, err
	}
	defer dstFile.Close()

	return io.Copy(dstFile, srcFile)
}

// OpenCopy open and copy file
func OpenCopy(srcName, dstName string) (int64, error) {
	src, err := os.Open(srcName)
	if err != nil {
		return 0, err
	}
	defer src.Close()

	dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		fmt.Println(err)
		return 0, err
	}
	defer dst.Close()

	return io.Copy(dst, src)
}
<|endoftext|>


<commit_before>package tlcore

import (
	"encoding/binary"
	"fmt"
	"math/rand"
	"os"
	"sync"
	"testing"
)
import "bytes"

/*
This file contains all core testing functions.

*/

const numChunks = 8

//Test a simple put & get
func TestSimple(t *testing.T) {
	m := NewMap("testdb/", numChunks)
	defer os.RemoveAll("testdb/")
	defer m.Close()

	m.Set([]byte("k1"), []byte("v1"))
	rval, _ := m.Get([]byte("k1"))
	if !bytes.Equal([]byte("v1"), rval) {
		t.Fatal("Error: value mismatch")
	}
}

//Test a simple put & get (after a map close())
func TestSimpleRestore(t *testing.T) {
	defer os.RemoveAll("testdb/")
	{
		m := NewMap("testdb/", numChunks)
		m.Set([]byte("k1"), []byte("v1"))
		m.Close()
	}
	{
		m := OpenMap("testdb/")
		rval, _ := m.Get([]byte("k1"))
		if !bytes.Equal([]byte("v1"), rval) {
			t.Fatal("Error: value mismatch")
		}
		m.Close()
	}
}

//Test lots of simple put & get before and after closing the map
func TestSimpleLots(t *testing.T) {
	defer os.RemoveAll("testdb/")
	k := make([]byte, 4)
	v := make([]byte, 4)
	{
		m1 := NewMap("testdb/", numChunks)
		for i := 0; i < 128*1024; i++ {
			binary.LittleEndian.PutUint32(k, uint32(i))
			binary.LittleEndian.PutUint32(v, uint32(i))
			m1.Set(k, v)
		}
		for i := 0; i < 128*1024; i++ {
			binary.LittleEndian.PutUint32(k, uint32(i))
			binary.LittleEndian.PutUint32(v, uint32(i))
			rval, _ := m1.Get(k)
			if !bytes.Equal(v, rval) {
				t.Fatal("Error 1: value mismatch")
			}
		}
		m1.Close()
	}
	{
		m2 := OpenMap("testdb/")
		for i := 0; i < 128*1024; i++ {
			binary.LittleEndian.PutUint32(k, uint32(i))
			binary.LittleEndian.PutUint32(v, uint32(i))
			rval, _ := m2.Get(k)
			if !bytes.Equal(v, rval) {
				t.Fatal("Error 2: value mismatch")
			}
		}
		m2.Close()
	}
}

//Test lots of simple put & get, in a parallel way, test multi thread safety
func TestParSimpleLots(t *testing.T) {
	defer os.RemoveAll("testdb/")
	m1 := NewMap("testdb/", numChunks)
	var w sync.WaitGroup
	w.Add(27)
	for tid := 0; tid < 27; tid++ {
		go func(tid int) {
			k := make([]byte, 4)
			v := make([]byte, 4)
			for i := 0; i < 1024; i++ {
				binary.LittleEndian.PutUint32(k, uint32(i*27+tid))
				binary.LittleEndian.PutUint32(v, uint32(i*27+tid))
				m1.Set(k, v)
			}
			w.Done()
		}(tid)
	}
	w.Wait()

	k := make([]byte, 4)
	v := make([]byte, 4)
	for i := 0; i < 27*1024; i++ {
		binary.LittleEndian.PutUint32(k, uint32(i))
		binary.LittleEndian.PutUint32(v, uint32(i))
		rval, _ := m1.Get(k)
		if !bytes.Equal(v, rval) {
			t.Fatal("Error 1: value mismatch")
		}
	}

	m1.Close()
}

//Test lots of simple put & get, in a parallel way, test multi thread safety, after a map close
func TestParSimpleLotsRestore(t *testing.T) {
	defer os.RemoveAll("testdb/")
	{
		m1 := NewMap("testdb/", numChunks)
		var w sync.WaitGroup
		w.Add(27)
		for tid := 0; tid < 27; tid++ {
			go func(tid int) {
				k := make([]byte, 4)
				v := make([]byte, 4)
				for i := 0; i < 1024; i++ {
					binary.LittleEndian.PutUint32(k, uint32(i*27+tid))
					binary.LittleEndian.PutUint32(v, uint32(i*27+tid))
					m1.Set(k, v)
				}
				w.Done()
			}(tid)
		}
		w.Wait()
		m1.Close()
	}
	{
		m2 := OpenMap("testdb/")
		k := make([]byte, 4)
		v := make([]byte, 4)
		for i := 0; i < 27*1024; i++ {
			binary.LittleEndian.PutUint32(k, uint32(i))
			binary.LittleEndian.PutUint32(v, uint32(i))
			rval, _ := m2.Get(k)
			if !bytes.Equal(v, rval) {
				t.Fatal("Error 2: value mismatch")
			}
		}
		m2.Close()
	}
}

//Test simple set
//Test simple del

//Test complex get, put, set, del mix

//Common functions test
func TestCmplx1(t *testing.T) {
	metaTest(2000, 11, 129, 64)
}

//Low key size: test delete operation
func TestCmplx2(t *testing.T) {
	metaTest(2000, 2, 129, 64)
}

//Large key size
func TestCmplx3(t *testing.T) {
	metaTest(2000, 130, 129, 64)
}

//Large value size
func TestCmplx4(t *testing.T) {
	metaTest(2000, 11, 555, 64)
}

//Test low value size
func TestCmplx5(t *testing.T) {
	metaTest(2000, 11, 2, 64)
}

func operate() {

}
func goOperate() {

}
func dbOperate() {

}
func checkDB() {

}

//TODO dejar bien, quitar chapuzas
func metaTest(numOperations, maxKeySize, maxValueSize, threads int) {
	defer os.RemoveAll("testdb/")

	//Operate on built-in map
	goMap := make(map[string][]byte)
	var goDeletes []([]byte)
	for core := 0; core < threads; core++ {
		r := rand.New(rand.NewSource(int64(core)))
		base := make([]byte, 4)
		base2 := make([]byte, 4)
		for i := 0; i < numOperations; i++ {
			opType := 1 + r.Intn(2)
			opKeySize := r.Intn(maxKeySize-1) + 1
			opValueSize := r.Intn(maxValueSize-1) + 1
			binary.LittleEndian.PutUint32(base, uint32(r.Int31()*64)+uint32(core))
			binary.LittleEndian.PutUint32(base2, uint32(i*64+core))
			key := bytes.Repeat([]byte(base), opKeySize)[0:opKeySize]
			value := bytes.Repeat([]byte(base2), opValueSize)[0:opValueSize]
			//fmt.Println("gomap", opType, key, value)
			switch opType {
			case OpSet:
				goMap[string(key)] = value
			case OpDel:
				if _, ok := goMap[string(key)]; ok {
					delete(goMap, string(key))
					goDeletes = append(goDeletes, key)
				}
			}
		}
	}
	{
		//Operate on DB
		m1 := NewMap("testdb/", numChunks)

		var w sync.WaitGroup
		w.Add(threads)
		for core := 0; core < threads; core++ {
			go func(core int) {
				r := rand.New(rand.NewSource(int64(core)))
				base := make([]byte, 4)
				base2 := make([]byte, 4)
				for i := 0; i < numOperations; i++ {
					opType := 1 + r.Intn(2)
					opKeySize := r.Intn(maxKeySize-1) + 1
					opValueSize := r.Intn(maxValueSize-1) + 1
					binary.LittleEndian.PutUint32(base, uint32(r.Int31()*64)+uint32(core))
					binary.LittleEndian.PutUint32(base2, uint32(i*64+core))
					key := bytes.Repeat([]byte(base), opKeySize)[0:opKeySize]
					value := bytes.Repeat([]byte(base2), opValueSize)[0:opValueSize]
					//fmt.Println("db   ", opType, key, value)
					switch opType {
					case OpSet:
						m1.Set(key, value)
					case OpDel:
						m1.Delete(key)
					}
				}
				w.Done()
			}(core)
		}
		w.Wait()
		//Check map is in DB
		for key, value := range goMap {
			rval, err := m1.Get([]byte(key))
			//fmt.Println([]byte(key), value)
			if err != nil {
				panic(err)
			}
			if !bytes.Equal(rval, value) {
				panic(1)
			}
		}

		//Check deleteds aren't in DB
		fmt.Println("Tested deletes:", len(goDeletes))
		for i := 0; i < len(goDeletes); i++ {
			key := goDeletes[i]
			if _, ok := goMap[string(key)]; ok {
				//The key was set after a delete
				continue
			}
			_, err := m1.Get([]byte(key))
			if err == nil {
				panic(2)
			}
		}
		//Close DB
		m1.Close()
	}
	{
		//Restore DB
		m2 := OpenMap("testdb/")

		//Check again
		//Check map is in DB
		for key, value := range goMap {
			rval, err := m2.Get([]byte(key))
			//fmt.Println([]byte(key), value)
			if err != nil {
				panic(err)
			}
			if !bytes.Equal(rval, value) {
				panic(1)
			}
		}

		//Check deleteds aren't in DB
		fmt.Println("Tested deletes:", len(goDeletes))
		for i := 0; i < len(goDeletes); i++ {
			key := goDeletes[i]
			if _, ok := goMap[string(key)]; ok {
				//The key was set after a delete
				continue
			}
			_, err := m2.Get([]byte(key))
			if err == nil {
				panic(2)
			}
		}
	}
}

//Test parallel complex get, put, set, del mix

//Tests operational limits: size

//Test sync/nosync file

//Bench with diferents sizes

/*
//Bench lots of gets
func BenchmarkGet(b *testing.B) {
	defer os.RemoveAll("benchdb/")
	defer os.Chdir("../")
	if testing.Verbose() {
		fmt.Println("\tInserting", b.N, "keys...")
	}
	db := Create("benchdb/")
	m, _ := db.AllocMap("mapA")
	key := make([]byte, 4)
	lenValue := 100
	value := bytes.Repeat([]byte("X"), lenValue)
	for i := 0; i < b.N/32+1; i++ {
		binary.LittleEndian.PutUint32(key, uint32(3*i))
		binary.LittleEndian.PutUint32(value, uint32(3*i))
		err := m.Put(key, value)
		if err != nil {
			panic(err)
		}
	}
	gid := uint64(0)
	fmt.Println("get...")
	b.ResetTimer()
	b.RunParallel(func(pb *testing.PB) {
		sum := 0
		key := make([]byte, 4)
		id := uint32(atomic.AddUint64(&gid, 1))
		fmt.Println(id)
		r := rand.New(rand.NewSource(int64(id)))
		for i := 0; pb.Next(); i++ {
			binary.LittleEndian.PutUint32(key, uint32(3*r.Intn(b.N/32+1)))
			v, err := m.Get(key)
			sum += int(v[len(v)-1])
			if err != nil || !bytes.Equal(v, v) {
				b.Fatal("Key not present", key, id, i, v, sum)
			}
		}
	})
	b.StopTimer()
	db.Close()
}

//Bench lots of gets, in a parallel way

//Bench lots of puts

//Bench lots of puts, in a parallel way
*/
<commit_msg>core - metatest refactorizado<commit_after>package tlcore

import (
	"encoding/binary"
	"fmt"
	"math/rand"
	"os"
	"sync"
	"testing"
)
import "bytes"

/*
This file contains all core testing functions.

*/

const numChunks = 8

//Test a simple put & get
func TestSimple(t *testing.T) {
	m := NewMap("testdb/", numChunks)
	defer os.RemoveAll("testdb/")
	defer m.Close()

	m.Set([]byte("k1"), []byte("v1"))
	rval, _ := m.Get([]byte("k1"))
	if !bytes.Equal([]byte("v1"), rval) {
		t.Fatal("Error: value mismatch")
	}
}

//Test a simple put & get (after a map close())
func TestSimpleRestore(t *testing.T) {
	defer os.RemoveAll("testdb/")
	{
		m := NewMap("testdb/", numChunks)
		m.Set([]byte("k1"), []byte("v1"))
		m.Close()
	}
	{
		m := OpenMap("testdb/")
		rval, _ := m.Get([]byte("k1"))
		if !bytes.Equal([]byte("v1"), rval) {
			t.Fatal("Error: value mismatch")
		}
		m.Close()
	}
}

//Test lots of simple put & get before and after closing the map
func TestSimpleLots(t *testing.T) {
	defer os.RemoveAll("testdb/")
	k := make([]byte, 4)
	v := make([]byte, 4)
	{
		m1 := NewMap("testdb/", numChunks)
		for i := 0; i < 128*1024; i++ {
			binary.LittleEndian.PutUint32(k, uint32(i))
			binary.LittleEndian.PutUint32(v, uint32(i))
			m1.Set(k, v)
		}
		for i := 0; i < 128*1024; i++ {
			binary.LittleEndian.PutUint32(k, uint32(i))
			binary.LittleEndian.PutUint32(v, uint32(i))
			rval, _ := m1.Get(k)
			if !bytes.Equal(v, rval) {
				t.Fatal("Error 1: value mismatch")
			}
		}
		m1.Close()
	}
	{
		m2 := OpenMap("testdb/")
		for i := 0; i < 128*1024; i++ {
			binary.LittleEndian.PutUint32(k, uint32(i))
			binary.LittleEndian.PutUint32(v, uint32(i))
			rval, _ := m2.Get(k)
			if !bytes.Equal(v, rval) {
				t.Fatal("Error 2: value mismatch")
			}
		}
		m2.Close()
	}
}

//Test lots of simple put & get, in a parallel way, test multi thread safety
func TestParSimpleLots(t *testing.T) {
	defer os.RemoveAll("testdb/")
	m1 := NewMap("testdb/", numChunks)
	var w sync.WaitGroup
	w.Add(27)
	for tid := 0; tid < 27; tid++ {
		go func(tid int) {
			k := make([]byte, 4)
			v := make([]byte, 4)
			for i := 0; i < 1024; i++ {
				binary.LittleEndian.PutUint32(k, uint32(i*27+tid))
				binary.LittleEndian.PutUint32(v, uint32(i*27+tid))
				m1.Set(k, v)
			}
			w.Done()
		}(tid)
	}
	w.Wait()

	k := make([]byte, 4)
	v := make([]byte, 4)
	for i := 0; i < 27*1024; i++ {
		binary.LittleEndian.PutUint32(k, uint32(i))
		binary.LittleEndian.PutUint32(v, uint32(i))
		rval, _ := m1.Get(k)
		if !bytes.Equal(v, rval) {
			t.Fatal("Error 1: value mismatch")
		}
	}

	m1.Close()
}

//Test lots of simple put & get, in a parallel way, test multi thread safety, after a map close
func TestParSimpleLotsRestore(t *testing.T) {
	defer os.RemoveAll("testdb/")
	{
		m1 := NewMap("testdb/", numChunks)
		var w sync.WaitGroup
		w.Add(27)
		for tid := 0; tid < 27; tid++ {
			go func(tid int) {
				k := make([]byte, 4)
				v := make([]byte, 4)
				for i := 0; i < 1024; i++ {
					binary.LittleEndian.PutUint32(k, uint32(i*27+tid))
					binary.LittleEndian.PutUint32(v, uint32(i*27+tid))
					m1.Set(k, v)
				}
				w.Done()
			}(tid)
		}
		w.Wait()
		m1.Close()
	}
	{
		m2 := OpenMap("testdb/")
		k := make([]byte, 4)
		v := make([]byte, 4)
		for i := 0; i < 27*1024; i++ {
			binary.LittleEndian.PutUint32(k, uint32(i))
			binary.LittleEndian.PutUint32(v, uint32(i))
			rval, _ := m2.Get(k)
			if !bytes.Equal(v, rval) {
				t.Fatal("Error 2: value mismatch")
			}
		}
		m2.Close()
	}
}

//Test simple set
//Test simple del

//Test get, set, del

//Common functions test
func TestMix(t *testing.T) {
	metaTest(2000, 11, 129, 64)
}

//Large key size
func TestMixLargeKey(t *testing.T) {
	metaTest(2000, 130, 129, 64)
}

//Large value size
func TestMixLargeValue(t *testing.T) {
	metaTest(2000, 11, 555, 64)
}

func operate() {

}
func goOperate() {

}
func dbOperate() {

}
func checkDB() {

}

func randKVOpGenerator(maxKeySize, maxValueSize, seed, mult, offset int) func() (op int, k, v []byte) {
	r := rand.New(rand.NewSource(int64(seed)))
	base := make([]byte, 4)
	base2 := make([]byte, 4)
	return func() (op int, k, v []byte) {
		opKeySize := r.Intn(maxKeySize-1) + 1
		opValueSize := r.Intn(maxValueSize-1) + 1
		binary.LittleEndian.PutUint32(base, uint32(r.Int31())*uint32(mult)+uint32(offset))
		binary.LittleEndian.PutUint32(base2, uint32(r.Int31())*uint32(mult)+uint32(offset))
		key := bytes.Repeat([]byte(base), opKeySize)[0:opKeySize]
		value := bytes.Repeat([]byte(base2), opValueSize)[0:opValueSize]
		return 1 + r.Intn(2), key, value
	}
}

func metaTest(numOperations, maxKeySize, maxValueSize, threads int) {
	defer os.RemoveAll("testdb/")

	//Operate on built-in map
	goMap := make(map[string][]byte)
	var goDeletes []([]byte)
	for core := 0; core < threads; core++ {
		rNext := randKVOpGenerator(maxKeySize, maxValueSize, core, 64, core)
		for i := 0; i < numOperations; i++ {
			opType, key, value := rNext()
			switch opType {
			case OpSet:
				goMap[string(key)] = value
			case OpDel:
				if _, ok := goMap[string(key)]; ok {
					delete(goMap, string(key))
					goDeletes = append(goDeletes, key)
				}
			}
		}
	}
	{
		//Operate on DB
		m1 := NewMap("testdb/", numChunks)

		var w sync.WaitGroup
		w.Add(threads)
		for core := 0; core < threads; core++ {
			go func(core int) {
				rNext := randKVOpGenerator(maxKeySize, maxValueSize, core, 64, core)
				for i := 0; i < numOperations; i++ {
					opType, key, value := rNext()
					switch opType {
					case OpSet:
						m1.Set(key, value)
					case OpDel:
						m1.Delete(key)
					}
				}
				w.Done()
			}(core)
		}
		w.Wait()
		//Check map is in DB
		for key, value := range goMap {
			rval, err := m1.Get([]byte(key))
			//fmt.Println([]byte(key), value)
			if err != nil {
				panic(err)
			}
			if !bytes.Equal(rval, value) {
				panic(1)
			}
		}

		//Check deleteds aren't in DB
		for i := 0; i < len(goDeletes); i++ {
			key := goDeletes[i]
			if _, ok := goMap[string(key)]; ok {
				//The key was set after a delete
				continue
			}
			_, err := m1.Get([]byte(key))
			if err == nil {
				panic(2)
			}
		}
		//Close DB
		m1.Close()
	}
	{
		//Restore DB
		m2 := OpenMap("testdb/")

		//Check again
		//Check map is in DB
		for key, value := range goMap {
			rval, err := m2.Get([]byte(key))
			//fmt.Println([]byte(key), value)
			if err != nil {
				panic(err)
			}
			if !bytes.Equal(rval, value) {
				panic(1)
			}
		}

		//Check deleteds aren't in DB
		testedDeletes := 0
		for i := 0; i < len(goDeletes); i++ {
			key := goDeletes[i]
			if _, ok := goMap[string(key)]; ok {
				//The key was set after a delete
				continue
			}
			_, err := m2.Get([]byte(key))
			if err == nil {
				panic(2)
			}
			testedDeletes++
		}
		fmt.Println("Tested deletes:", testedDeletes)
	}
}

//Test parallel complex get, set, del mix

//Tests operational limits: size

//Bench with diferents sizes

/*
//Bench lots of gets
func BenchmarkGet(b *testing.B) {
	defer os.RemoveAll("benchdb/")
	defer os.Chdir("../")
	if testing.Verbose() {
		fmt.Println("\tInserting", b.N, "keys...")
	}
	db := Create("benchdb/")
	m, _ := db.AllocMap("mapA")
	key := make([]byte, 4)
	lenValue := 100
	value := bytes.Repeat([]byte("X"), lenValue)
	for i := 0; i < b.N/32+1; i++ {
		binary.LittleEndian.PutUint32(key, uint32(3*i))
		binary.LittleEndian.PutUint32(value, uint32(3*i))
		err := m.Put(key, value)
		if err != nil {
			panic(err)
		}
	}
	gid := uint64(0)
	fmt.Println("get...")
	b.ResetTimer()
	b.RunParallel(func(pb *testing.PB) {
		sum := 0
		key := make([]byte, 4)
		id := uint32(atomic.AddUint64(&gid, 1))
		fmt.Println(id)
		r := rand.New(rand.NewSource(int64(id)))
		for i := 0; pb.Next(); i++ {
			binary.LittleEndian.PutUint32(key, uint32(3*r.Intn(b.N/32+1)))
			v, err := m.Get(key)
			sum += int(v[len(v)-1])
			if err != nil || !bytes.Equal(v, v) {
				b.Fatal("Key not present", key, id, i, v, sum)
			}
		}
	})
	b.StopTimer()
	db.Close()
}

//Bench lots of gets, in a parallel way

//Bench lots of puts

//Bench lots of puts, in a parallel way
*/
<|endoftext|>


<commit_before>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
)

const VERSION = "0.0.19"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.5", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	g, err := lb.NewAllGrouper(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	h := lb.NewProxy(k, g, r, conf)
	h = g.Wrap(h) // add/del/list endpoints
	h = r.Wrap(h) // stats / dash endpoint

	err = serve(conf.Listen, h)
	if err != nil {
		logrus.WithError(err).Fatal("server error")
	}
}

func serve(addr string, handler http.Handler) error {
	server := &http.Server{Addr: addr, Handler: handler}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		for sig := range ch {
			logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")
			server.Shutdown(context.Background()) // safe shutdown
			return
		}
	}()
	return server.ListenAndServe()
}
<commit_msg>fnlb: 0.0.20 release [skip ci]<commit_after>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
)

const VERSION = "0.0.20"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.6", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	g, err := lb.NewAllGrouper(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	h := lb.NewProxy(k, g, r, conf)
	h = g.Wrap(h) // add/del/list endpoints
	h = r.Wrap(h) // stats / dash endpoint

	err = serve(conf.Listen, h)
	if err != nil {
		logrus.WithError(err).Fatal("server error")
	}
}

func serve(addr string, handler http.Handler) error {
	server := &http.Server{Addr: addr, Handler: handler}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		for sig := range ch {
			logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")
			server.Shutdown(context.Background()) // safe shutdown
			return
		}
	}()
	return server.ListenAndServe()
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.190"

func main() {
	// XXX (reed): normalize
	level, err := logrus.ParseLevel(os.Getenv("LOG_LEVEL"))
	if err != nil {
		level = logrus.InfoLevel
	}
	logrus.SetLevel(level)

	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.157", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory; use k8s for kuberneted")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.StringVar(&conf.MgmtListen, "mgmt-listen", ":8081", "management port to run on")
	flag.IntVar(&conf.ShutdownTimeout, "shutdown-timeout", 0, "graceful shutdown timeout")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckHealthy, "hc-healthy", 1, "threshold of success checks to declare node healthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.StringVar(&conf.Namespace, "namespace", "", "kubernetes namespace to monitor")
	flag.StringVar(&conf.LabelSelector, "label-selector", "", "kubernetes label selector to monitor")
	flag.IntVar(&conf.TargetPort, "target-port", 8080, "kubernetes port to target on selected pods")

	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	db, err := lb.NewDB(conf) // Handles case where DBurl == "k8s"
	if err != nil {
		logrus.WithError(err).Fatal("error setting up database")
	}
	defer db.Close()

	g, err := lb.NewAllGrouper(conf, db)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	servers := make([]*http.Server, 0, 1)
	handler := lb.NewProxy(k, g, r, conf)

	// a separate mgmt listener is requested? then let's create a LB traffic only server
	if conf.Listen != conf.MgmtListen {
		servers = append(servers, &http.Server{Addr: conf.Listen, Handler: handler})
		handler = lb.NullHandler()
	}

	// add mgmt endpoints to the handler
	handler = g.Wrap(handler) // add/del/list endpoints
	handler = r.Wrap(handler) // stats / dash endpoint

	servers = append(servers, &http.Server{Addr: conf.MgmtListen, Handler: handler})
	serve(servers, &conf)
}

func serve(servers []*http.Server, conf *lb.Config) {

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)

	for i := 0; i < len(servers); i++ {
		go func(idx int) {
			err := servers[idx].ListenAndServe()
			if err != nil && err != http.ErrServerClosed {
				logrus.WithFields(logrus.Fields{"server_id": idx}).WithError(err).Fatal("server error")
			} else {
				logrus.WithFields(logrus.Fields{"server_id": idx}).Info("server stopped")
			}
		}(i)
	}

	sig := <-ch
	logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")

	for i := 0; i < len(servers); i++ {

		ctx := context.Background()

		if conf.ShutdownTimeout > 0 {
			tmpCtx, cancel := context.WithTimeout(context.Background(), time.Duration(conf.ShutdownTimeout)*time.Second)
			ctx = tmpCtx
			defer cancel()
		}

		err := servers[i].Shutdown(ctx) // safe shutdown
		if err != nil {
			logrus.WithFields(logrus.Fields{"server_id": i}).WithError(err).Fatal("server shutdown error")
		} else {
			logrus.WithFields(logrus.Fields{"server_id": i}).Info("server shutdown")
		}
	}
}
<commit_msg>fnlb: 0.0.191 release [skip ci]<commit_after>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.191"

func main() {
	// XXX (reed): normalize
	level, err := logrus.ParseLevel(os.Getenv("LOG_LEVEL"))
	if err != nil {
		level = logrus.InfoLevel
	}
	logrus.SetLevel(level)

	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.158", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory; use k8s for kuberneted")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.StringVar(&conf.MgmtListen, "mgmt-listen", ":8081", "management port to run on")
	flag.IntVar(&conf.ShutdownTimeout, "shutdown-timeout", 0, "graceful shutdown timeout")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckHealthy, "hc-healthy", 1, "threshold of success checks to declare node healthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.StringVar(&conf.Namespace, "namespace", "", "kubernetes namespace to monitor")
	flag.StringVar(&conf.LabelSelector, "label-selector", "", "kubernetes label selector to monitor")
	flag.IntVar(&conf.TargetPort, "target-port", 8080, "kubernetes port to target on selected pods")

	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	db, err := lb.NewDB(conf) // Handles case where DBurl == "k8s"
	if err != nil {
		logrus.WithError(err).Fatal("error setting up database")
	}
	defer db.Close()

	g, err := lb.NewAllGrouper(conf, db)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	servers := make([]*http.Server, 0, 1)
	handler := lb.NewProxy(k, g, r, conf)

	// a separate mgmt listener is requested? then let's create a LB traffic only server
	if conf.Listen != conf.MgmtListen {
		servers = append(servers, &http.Server{Addr: conf.Listen, Handler: handler})
		handler = lb.NullHandler()
	}

	// add mgmt endpoints to the handler
	handler = g.Wrap(handler) // add/del/list endpoints
	handler = r.Wrap(handler) // stats / dash endpoint

	servers = append(servers, &http.Server{Addr: conf.MgmtListen, Handler: handler})
	serve(servers, &conf)
}

func serve(servers []*http.Server, conf *lb.Config) {

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)

	for i := 0; i < len(servers); i++ {
		go func(idx int) {
			err := servers[idx].ListenAndServe()
			if err != nil && err != http.ErrServerClosed {
				logrus.WithFields(logrus.Fields{"server_id": idx}).WithError(err).Fatal("server error")
			} else {
				logrus.WithFields(logrus.Fields{"server_id": idx}).Info("server stopped")
			}
		}(i)
	}

	sig := <-ch
	logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")

	for i := 0; i < len(servers); i++ {

		ctx := context.Background()

		if conf.ShutdownTimeout > 0 {
			tmpCtx, cancel := context.WithTimeout(context.Background(), time.Duration(conf.ShutdownTimeout)*time.Second)
			ctx = tmpCtx
			defer cancel()
		}

		err := servers[i].Shutdown(ctx) // safe shutdown
		if err != nil {
			logrus.WithFields(logrus.Fields{"server_id": i}).WithError(err).Fatal("server shutdown error")
		} else {
			logrus.WithFields(logrus.Fields{"server_id": i}).Info("server shutdown")
		}
	}
}
<|endoftext|>


<commit_before>package form

import (
	"io/ioutil"
	"math"
	"net/http"
	"net/url"
	"reflect"
	"regexp"
	"strings"
	"testing"
)

func TestCreateTypeMap(t *testing.T) {
	for n, test := range [...]struct {
		Input  reflect.Type
		Output typeMap
	}{
		{ // 1
			Input: reflect.TypeOf(struct {
				A int
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 2
			Input: reflect.TypeOf(struct {
				A int `form:"B"`
			}{}),
			Output: typeMap{
				"B": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 3
			Input: reflect.TypeOf(struct {
				A int `form:",required"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Required: true,
					Index:    []int{0},
				},
			},
		},
		{ // 4
			Input: reflect.TypeOf(struct {
				A int `form:",post"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Post:  true,
					Index: []int{0},
				},
			},
		},
		{ // 5
			Input: reflect.TypeOf(struct {
				A int `form:",post,required"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Post:     true,
					Required: true,
					Index:    []int{0},
				},
			},
		},
		{ // 6
			Input: reflect.TypeOf(struct {
				A int `form:",required,post"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Post:     true,
					Required: true,
					Index:    []int{0},
				},
			},
		},
		{ // 7
			Input: reflect.TypeOf(struct {
				A int `min:"-20"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  -20,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 8
			Input: reflect.TypeOf(struct {
				A int `max:"-20"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  -20,
					},
					Index: []int{0},
				},
			},
		},
		{ // 9
			Input: reflect.TypeOf(struct {
				A int8
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 8,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 10
			Input: reflect.TypeOf(struct {
				A int16
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 16,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 11
			Input: reflect.TypeOf(struct {
				A int32
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 32,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 12
			Input: reflect.TypeOf(struct {
				A int64
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 13
			Input: reflect.TypeOf(struct {
				A uint
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 14
			Input: reflect.TypeOf(struct {
				A uint `min:"10"`
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						min:  10,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 15
			Input: reflect.TypeOf(struct {
				A uint `min:"-1"`
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 16
			Input: reflect.TypeOf(struct {
				A uint `max:"100"`
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  100,
					},
					Index: []int{0},
				},
			},
		},
		{ // 17
			Input: reflect.TypeOf(struct {
				A uint8
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 8,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 18
			Input: reflect.TypeOf(struct {
				A uint16
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 16,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 19
			Input: reflect.TypeOf(struct {
				A uint32
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 32,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 20
			Input: reflect.TypeOf(struct {
				A uint
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 21
			Input: reflect.TypeOf(struct {
				A float32
			}{}),
			Output: typeMap{
				"A": {
					processor: float{
						bits: 32,
						min:  -math.MaxFloat64,
						max:  math.MaxFloat64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 22
			Input: reflect.TypeOf(struct {
				A float64
			}{}),
			Output: typeMap{
				"A": {
					processor: float{
						bits: 64,
						min:  -math.MaxFloat64,
						max:  math.MaxFloat64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 23
			Input: reflect.TypeOf(struct {
				A float64 `min:"-10"`
			}{}),
			Output: typeMap{
				"A": {
					processor: float{
						bits: 64,
						min:  -10,
						max:  math.MaxFloat64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 24
			Input: reflect.TypeOf(struct {
				A float64 `max:"10"`
			}{}),
			Output: typeMap{
				"A": {
					processor: float{
						bits: 64,
						min:  -math.MaxFloat64,
						max:  10,
					},
					Index: []int{0},
				},
			},
		},
		{ // 25
			Input: reflect.TypeOf(struct {
				A string
			}{}),
			Output: typeMap{
				"A": {
					processor: str{},
					Index:     []int{0},
				},
			},
		},
		{ // 26
			Input: reflect.TypeOf(struct {
				A string `regex:"/aaa/"`
			}{}),
			Output: typeMap{
				"A": {
					processor: str{
						regex: regexp.MustCompile("/aaa/"),
					},
					Index: []int{0},
				},
			},
		},
		{ // 27
			Input: reflect.TypeOf(struct {
				A bool
			}{}),
			Output: typeMap{
				"A": {
					processor: boolean{},
					Index:     []int{0},
				},
			},
		},
		{ // 28
			Input: reflect.TypeOf(struct {
				A []bool
			}{}),
			Output: typeMap{
				"A": {
					processor: slice{
						processor: boolean{},
						typ:       reflect.TypeOf(false),
					},
					Index: []int{0},
				},
			},
		},
	} {
		output := createTypeMap(test.Input)
		if !reflect.DeepEqual(output, test.Output) {
			t.Errorf("test %d: expecting output %v, got %v", n+1, test.Output, output)
		}
	}
}

func TestProcess(t *testing.T) {
	for n, test := range [...]struct {
		Get, Post url.Values
		Output    interface{}
		Err       error
	}{
		{
			url.Values{
				"A": []string{"1"},
			},
			url.Values{},
			struct {
				A int
			}{
				A: 1,
			},
			nil,
		},
		{
			url.Values{},
			url.Values{
				"A": []string{"1"},
			},
			struct {
				A int
			}{
				A: 1,
			},
			nil,
		},
	} {
		r := http.Request{
			Method: http.MethodPost,
			URL: &url.URL{
				RawQuery: test.Get.Encode(),
			},
			Header: http.Header{
				"Content-Type": []string{"application/x-www-form-urlencoded"},
			},
			Body: ioutil.NopCloser(strings.NewReader(test.Post.Encode())),
		}
		output := reflect.New(reflect.TypeOf(test.Output))
		err := Process(&r, output.Interface())
		if err != nil {
			if test.Err == nil {
				t.Errorf("test %d: unexpected error: %s", n+1, err)
			} else if err != test.Err {
				t.Errorf("test %d: expecting error: %s\ngot: %s", n+1, test.Err, err)
			}
		} else if test.Err != nil {
			t.Errorf("test %d: got no error when expecting: %s", n+1, test.Err)
		} else if o := output.Elem().Interface(); !reflect.DeepEqual(o, test.Output) {
			t.Errorf("test %d: expecting output: %#v\ngot: %#v", n+1, test.Output, o)
		}
	}
}
<commit_msg>added embeded test<commit_after>package form

import (
	"io/ioutil"
	"math"
	"net/http"
	"net/url"
	"reflect"
	"regexp"
	"strings"
	"testing"
)

type X struct {
	A string
}

func TestCreateTypeMap(t *testing.T) {
	for n, test := range [...]struct {
		Input  reflect.Type
		Output typeMap
	}{
		{ // 1
			Input: reflect.TypeOf(struct {
				A int
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 2
			Input: reflect.TypeOf(struct {
				A int `form:"B"`
			}{}),
			Output: typeMap{
				"B": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 3
			Input: reflect.TypeOf(struct {
				A int `form:",required"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Required: true,
					Index:    []int{0},
				},
			},
		},
		{ // 4
			Input: reflect.TypeOf(struct {
				A int `form:",post"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Post:  true,
					Index: []int{0},
				},
			},
		},
		{ // 5
			Input: reflect.TypeOf(struct {
				A int `form:",post,required"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Post:     true,
					Required: true,
					Index:    []int{0},
				},
			},
		},
		{ // 6
			Input: reflect.TypeOf(struct {
				A int `form:",required,post"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Post:     true,
					Required: true,
					Index:    []int{0},
				},
			},
		},
		{ // 7
			Input: reflect.TypeOf(struct {
				A int `min:"-20"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  -20,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 8
			Input: reflect.TypeOf(struct {
				A int `max:"-20"`
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  -20,
					},
					Index: []int{0},
				},
			},
		},
		{ // 9
			Input: reflect.TypeOf(struct {
				A int8
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 8,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 10
			Input: reflect.TypeOf(struct {
				A int16
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 16,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 11
			Input: reflect.TypeOf(struct {
				A int32
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 32,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 12
			Input: reflect.TypeOf(struct {
				A int64
			}{}),
			Output: typeMap{
				"A": {
					processor: inum{
						bits: 64,
						min:  math.MinInt64,
						max:  math.MaxInt64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 13
			Input: reflect.TypeOf(struct {
				A uint
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 14
			Input: reflect.TypeOf(struct {
				A uint `min:"10"`
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						min:  10,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 15
			Input: reflect.TypeOf(struct {
				A uint `min:"-1"`
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 16
			Input: reflect.TypeOf(struct {
				A uint `max:"100"`
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  100,
					},
					Index: []int{0},
				},
			},
		},
		{ // 17
			Input: reflect.TypeOf(struct {
				A uint8
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 8,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 18
			Input: reflect.TypeOf(struct {
				A uint16
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 16,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 19
			Input: reflect.TypeOf(struct {
				A uint32
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 32,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 20
			Input: reflect.TypeOf(struct {
				A uint
			}{}),
			Output: typeMap{
				"A": {
					processor: unum{
						bits: 64,
						max:  math.MaxUint64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 21
			Input: reflect.TypeOf(struct {
				A float32
			}{}),
			Output: typeMap{
				"A": {
					processor: float{
						bits: 32,
						min:  -math.MaxFloat64,
						max:  math.MaxFloat64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 22
			Input: reflect.TypeOf(struct {
				A float64
			}{}),
			Output: typeMap{
				"A": {
					processor: float{
						bits: 64,
						min:  -math.MaxFloat64,
						max:  math.MaxFloat64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 23
			Input: reflect.TypeOf(struct {
				A float64 `min:"-10"`
			}{}),
			Output: typeMap{
				"A": {
					processor: float{
						bits: 64,
						min:  -10,
						max:  math.MaxFloat64,
					},
					Index: []int{0},
				},
			},
		},
		{ // 24
			Input: reflect.TypeOf(struct {
				A float64 `max:"10"`
			}{}),
			Output: typeMap{
				"A": {
					processor: float{
						bits: 64,
						min:  -math.MaxFloat64,
						max:  10,
					},
					Index: []int{0},
				},
			},
		},
		{ // 25
			Input: reflect.TypeOf(struct {
				A string
			}{}),
			Output: typeMap{
				"A": {
					processor: str{},
					Index:     []int{0},
				},
			},
		},
		{ // 26
			Input: reflect.TypeOf(struct {
				A string `regex:"/aaa/"`
			}{}),
			Output: typeMap{
				"A": {
					processor: str{
						regex: regexp.MustCompile("/aaa/"),
					},
					Index: []int{0},
				},
			},
		},
		{ // 27
			Input: reflect.TypeOf(struct {
				A bool
			}{}),
			Output: typeMap{
				"A": {
					processor: boolean{},
					Index:     []int{0},
				},
			},
		},
		{ // 28
			Input: reflect.TypeOf(struct {
				A []bool
			}{}),
			Output: typeMap{
				"A": {
					processor: slice{
						processor: boolean{},
						typ:       reflect.TypeOf(false),
					},
					Index: []int{0},
				},
			},
		},
		{ // 29
			Input: reflect.TypeOf(struct {
				X
			}{}),
			Output: typeMap{
				"A": {
					processor: str{},
					Index:     []int{0, 0},
				},
			},
		},
	} {
		output := createTypeMap(test.Input)
		if !reflect.DeepEqual(output, test.Output) {
			t.Errorf("test %d: expecting output %v, got %v", n+1, test.Output, output)
		}
	}
}

func TestProcess(t *testing.T) {
	for n, test := range [...]struct {
		Get, Post url.Values
		Output    interface{}
		Err       error
	}{
		{
			url.Values{
				"A": []string{"1"},
			},
			url.Values{},
			struct {
				A int
			}{
				A: 1,
			},
			nil,
		},
		{
			url.Values{},
			url.Values{
				"A": []string{"1"},
			},
			struct {
				A int
			}{
				A: 1,
			},
			nil,
		},
	} {
		r := http.Request{
			Method: http.MethodPost,
			URL: &url.URL{
				RawQuery: test.Get.Encode(),
			},
			Header: http.Header{
				"Content-Type": []string{"application/x-www-form-urlencoded"},
			},
			Body: ioutil.NopCloser(strings.NewReader(test.Post.Encode())),
		}
		output := reflect.New(reflect.TypeOf(test.Output))
		err := Process(&r, output.Interface())
		if err != nil {
			if test.Err == nil {
				t.Errorf("test %d: unexpected error: %s", n+1, err)
			} else if err != test.Err {
				t.Errorf("test %d: expecting error: %s\ngot: %s", n+1, test.Err, err)
			}
		} else if test.Err != nil {
			t.Errorf("test %d: got no error when expecting: %s", n+1, test.Err)
		} else if o := output.Elem().Interface(); !reflect.DeepEqual(o, test.Output) {
			t.Errorf("test %d: expecting output: %#v\ngot: %#v", n+1, test.Output, o)
		}
	}
}
<|endoftext|>