<commit_before>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package cmd

import (
	"fmt"
	"io"
	"regexp"
	"strings"

	"github.com/renstrom/dedent"
	"github.com/spf13/cobra"

	"k8s.io/kubernetes/pkg/kubectl"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/kubectl/resource"
	"k8s.io/kubernetes/pkg/runtime"
	"k8s.io/kubernetes/pkg/util/validation"
)

// ExposeOptions is the start of the data required to perform the operation.  As new fields are added, add them here instead of
// referencing the cmd.Flags()
type ExposeOptions struct {
	Filenames []string
	Recursive bool
}

var (
	expose_resources = dedent.Dedent(`
		pod (po), service (svc), replicationcontroller (rc),
		deployment (deploy), replicaset (rs)
	`)

	expose_long = dedent.Dedent(`
		Expose a resource as a new Kubernetes service.

		Looks up a deployment, service, replica set, replication controller or pod by name and uses the selector
		for that resource as the selector for a new service on the specified port. A deployment or replica set
		will be exposed as a service only if its selector is convertible to a selector that service supports,
		i.e. when the selector contains only the matchLabels component. Note that if no port is specified via
		--port and the exposed resource has multiple ports, all will be re-used by the new service. Also if no
		labels are specified, the new service will re-use the labels from the resource it exposes.

		Possible resources include (case insensitive): `) + expose_resources

	expose_example = dedent.Dedent(`
		# Create a service for a replicated nginx, which serves on port 80 and connects to the containers on port 8000.
		kubectl expose rc nginx --port=80 --target-port=8000

		# Create a service for a replication controller identified by type and name specified in "nginx-controller.yaml", which serves on port 80 and connects to the containers on port 8000.
		kubectl expose -f nginx-controller.yaml --port=80 --target-port=8000

		# Create a service for a pod valid-pod, which serves on port 444 with the name "frontend"
		kubectl expose pod valid-pod --port=444 --name=frontend

		# Create a second service based on the above service, exposing the container port 8443 as port 443 with the name "nginx-https"
		kubectl expose service nginx --port=443 --target-port=8443 --name=nginx-https

		# Create a service for a replicated streaming application on port 4100 balancing UDP traffic and named 'video-stream'.
		kubectl expose rc streamer --port=4100 --protocol=udp --name=video-stream

		# Create a service for a replicated nginx using replica set, which serves on port 80 and connects to the containers on port 8000.
		kubectl expose rs nginx --port=80 --target-port=8000

		# Create a service for an nginx deployment, which serves on port 80 and connects to the containers on port 8000.
		kubectl expose deployment nginx --port=80 --target-port=8000`)
)

func NewCmdExposeService(f *cmdutil.Factory, out io.Writer) *cobra.Command {
	options := &ExposeOptions{}

	validArgs, argAliases := []string{}, []string{}
	resources := regexp.MustCompile(`\s*,`).Split(expose_resources, -1)
	for _, r := range resources {
		validArgs = append(validArgs, strings.Fields(r)[0])
		argAliases = kubectl.ResourceAliases(validArgs)
	}

	cmd := &cobra.Command{
		Use:     "expose (-f FILENAME | TYPE NAME) [--port=port] [--protocol=TCP|UDP] [--target-port=number-or-name] [--name=name] [--external-ip=external-ip-of-service] [--type=type]",
		Short:   "Take a replication controller, service, deployment or pod and expose it as a new Kubernetes Service",
		Long:    expose_long,
		Example: expose_example,
		Run: func(cmd *cobra.Command, args []string) {
			err := RunExpose(f, out, cmd, args, options)
			cmdutil.CheckErr(err)
		},
		ValidArgs:  validArgs,
		ArgAliases: argAliases,
	}
	cmdutil.AddPrinterFlags(cmd)
	cmd.Flags().String("generator", "service/v2", "The name of the API generator to use. There are 2 generators: 'service/v1' and 'service/v2'. The only difference between them is that service port in v1 is named 'default', while it is left unnamed in v2. Default is 'service/v2'.")
	cmd.Flags().String("protocol", "", "The network protocol for the service to be created. Default is 'TCP'.")
	cmd.Flags().String("port", "", "The port that the service should serve on. Copied from the resource being exposed, if unspecified")
	cmd.Flags().String("type", "", "Type for this service: ClusterIP, NodePort, or LoadBalancer. Default is 'ClusterIP'.")
	// TODO: remove create-external-load-balancer in code on or after Aug 25, 2016.
	cmd.Flags().Bool("create-external-load-balancer", false, "If true, create an external load balancer for this service (trumped by --type). Implementation is cloud provider dependent. Default is 'false'.")
	cmd.Flags().MarkDeprecated("create-external-load-balancer", "use --type=\"LoadBalancer\" instead")
	cmd.Flags().String("load-balancer-ip", "", "IP to assign to the Load Balancer. If empty, an ephemeral IP will be created and used (cloud-provider specific).")
	cmd.Flags().String("selector", "", "A label selector to use for this service. Only equality-based selector requirements are supported. If empty (the default) infer the selector from the replication controller or replica set.")
	cmd.Flags().StringP("labels", "l", "", "Labels to apply to the service created by this call.")
	cmd.Flags().String("container-port", "", "Synonym for --target-port")
	cmd.Flags().MarkDeprecated("container-port", "--container-port will be removed in the future, please use --target-port instead")
	cmd.Flags().String("target-port", "", "Name or number for the port on the container that the service should direct traffic to. Optional.")
	cmd.Flags().String("external-ip", "", "Additional external IP address (not managed by Kubernetes) to accept for the service. If this IP is routed to a node, the service can be accessed by this IP in addition to its generated service IP.")
	cmd.Flags().String("overrides", "", "An inline JSON override for the generated object. If this is non-empty, it is used to override the generated object. Requires that the object supply a valid apiVersion field.")
	cmd.Flags().String("name", "", "The name for the newly created object.")
	cmd.Flags().String("session-affinity", "", "If non-empty, set the session affinity for the service to this; legal values: 'None', 'ClientIP'")
	cmd.Flags().String("cluster-ip", "", "ClusterIP to be assigned to the service. Leave empty to auto-allocate, or set to 'None' to create a headless service.")

	usage := "Filename, directory, or URL to a file identifying the resource to expose a service"
	kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage)
	cmdutil.AddDryRunFlag(cmd)
	cmdutil.AddRecursiveFlag(cmd, &options.Recursive)
	cmdutil.AddApplyAnnotationFlags(cmd)
	cmdutil.AddRecordFlag(cmd)
	return cmd
}

func RunExpose(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *ExposeOptions) error {
	namespace, enforceNamespace, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	mapper, typer := f.Object(false)
	r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
		ContinueOnError().
		NamespaceParam(namespace).DefaultNamespace().
		FilenameParam(enforceNamespace, options.Recursive, options.Filenames...).
		ResourceTypeOrNameArgs(false, args...).
		Flatten().
		Do()
	err = r.Err()
	if err != nil {
		return err
	}

	// Get the generator, setup and validate all required parameters
	generatorName := cmdutil.GetFlagString(cmd, "generator")
	generators := f.Generators("expose")
	generator, found := generators[generatorName]
	if !found {
		return cmdutil.UsageError(cmd, fmt.Sprintf("generator %q not found.", generatorName))
	}
	names := generator.ParamNames()

	err = r.Visit(func(info *resource.Info, err error) error {
		if err != nil {
			return err
		}

		mapping := info.ResourceMapping()
		if err := f.CanBeExposed(mapping.GroupVersionKind.GroupKind()); err != nil {
			return err
		}

		params := kubectl.MakeParams(cmd, names)
		name := info.Name
		if len(name) > validation.DNS1035LabelMaxLength {
			name = name[:validation.DNS1035LabelMaxLength]
		}
		params["default-name"] = name

		// For objects that need a pod selector, derive it from the exposed object in case a user
		// didn't explicitly specify one via --selector
		if s, found := params["selector"]; found && kubectl.IsZero(s) {
			s, err := f.MapBasedSelectorForObject(info.Object)
			if err != nil {
				return cmdutil.UsageError(cmd, fmt.Sprintf("couldn't retrieve selectors via --selector flag or introspection: %s", err))
			}
			params["selector"] = s
		}

		// For objects that need a port, derive it from the exposed object in case a user
		// didn't explicitly specify one via --port
		if port, found := params["port"]; found && kubectl.IsZero(port) {
			ports, err := f.PortsForObject(info.Object)
			if err != nil {
				return cmdutil.UsageError(cmd, fmt.Sprintf("couldn't find port via --port flag or introspection: %s", err))
			}
			switch len(ports) {
			case 0:
				return cmdutil.UsageError(cmd, "couldn't find port via --port flag or introspection")
			case 1:
				params["port"] = ports[0]
			default:
				params["ports"] = strings.Join(ports, ",")
			}
		}

		// Always try to derive protocols from the exposed object, may use
		// different protocols for different ports.
		if _, found := params["protocol"]; found {
			protocolsMap, err := f.ProtocolsForObject(info.Object)
			if err != nil {
				return cmdutil.UsageError(cmd, fmt.Sprintf("couldn't find protocol via introspection: %s", err))
			}
			if protocols := kubectl.MakeProtocols(protocolsMap); !kubectl.IsZero(protocols) {
				params["protocols"] = protocols
			}
		}

		if kubectl.IsZero(params["labels"]) {
			labels, err := f.LabelsForObject(info.Object)
			if err != nil {
				return err
			}
			params["labels"] = kubectl.MakeLabels(labels)
		}
		if err = kubectl.ValidateParams(names, params); err != nil {
			return err
		}
		// Check for invalid flags used against the present generator.
		if err := kubectl.EnsureFlagsValid(cmd, generators, generatorName); err != nil {
			return err
		}

		// Generate new object
		object, err := generator.Generate(params)
		if err != nil {
			return err
		}

		if inline := cmdutil.GetFlagString(cmd, "overrides"); len(inline) > 0 {
			codec := runtime.NewCodec(f.JSONEncoder(), f.Decoder(true))
			object, err = cmdutil.Merge(codec, object, inline, mapping.GroupVersionKind.Kind)
			if err != nil {
				return err
			}
		}

		resourceMapper := &resource.Mapper{
			ObjectTyper:  typer,
			RESTMapper:   mapper,
			ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
			Decoder:      f.Decoder(true),
		}
		info, err = resourceMapper.InfoForObject(object, nil)
		if err != nil {
			return err
		}
		if cmdutil.ShouldRecord(cmd, info) {
			if err := cmdutil.RecordChangeCause(object, f.Command()); err != nil {
				return err
			}
		}
		info.Refresh(object, true)
		if cmdutil.GetDryRunFlag(cmd) {
			return f.PrintObject(cmd, mapper, object, out)
		}
		if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, f.JSONEncoder()); err != nil {
			return err
		}

		// Serialize the object with the annotation applied.
		object, err = resource.NewHelper(info.Client, info.Mapping).Create(namespace, false, object)
		if err != nil {
			return err
		}

		if len(cmdutil.GetFlagString(cmd, "output")) > 0 {
			return f.PrintObject(cmd, mapper, object, out)
		}

		cmdutil.PrintSuccess(mapper, false, out, info.Mapping.Resource, info.Name, "exposed")
		return nil
	})
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>update `kubectl expose` output to UsageError<commit_after>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package cmd

import (
	"fmt"
	"io"
	"regexp"
	"strings"

	"github.com/renstrom/dedent"
	"github.com/spf13/cobra"

	"k8s.io/kubernetes/pkg/kubectl"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/kubectl/resource"
	"k8s.io/kubernetes/pkg/runtime"
	"k8s.io/kubernetes/pkg/util/validation"
)

// ExposeOptions is the start of the data required to perform the operation.  As new fields are added, add them here instead of
// referencing the cmd.Flags()
type ExposeOptions struct {
	Filenames []string
	Recursive bool
}

var (
	expose_resources = dedent.Dedent(`
		pod (po), service (svc), replicationcontroller (rc),
		deployment (deploy), replicaset (rs)
	`)

	expose_long = dedent.Dedent(`
		Expose a resource as a new Kubernetes service.

		Looks up a deployment, service, replica set, replication controller or pod by name and uses the selector
		for that resource as the selector for a new service on the specified port. A deployment or replica set
		will be exposed as a service only if its selector is convertible to a selector that service supports,
		i.e. when the selector contains only the matchLabels component. Note that if no port is specified via
		--port and the exposed resource has multiple ports, all will be re-used by the new service. Also if no
		labels are specified, the new service will re-use the labels from the resource it exposes.

		Possible resources include (case insensitive): `) + expose_resources

	expose_example = dedent.Dedent(`
		# Create a service for a replicated nginx, which serves on port 80 and connects to the containers on port 8000.
		kubectl expose rc nginx --port=80 --target-port=8000

		# Create a service for a replication controller identified by type and name specified in "nginx-controller.yaml", which serves on port 80 and connects to the containers on port 8000.
		kubectl expose -f nginx-controller.yaml --port=80 --target-port=8000

		# Create a service for a pod valid-pod, which serves on port 444 with the name "frontend"
		kubectl expose pod valid-pod --port=444 --name=frontend

		# Create a second service based on the above service, exposing the container port 8443 as port 443 with the name "nginx-https"
		kubectl expose service nginx --port=443 --target-port=8443 --name=nginx-https

		# Create a service for a replicated streaming application on port 4100 balancing UDP traffic and named 'video-stream'.
		kubectl expose rc streamer --port=4100 --protocol=udp --name=video-stream

		# Create a service for a replicated nginx using replica set, which serves on port 80 and connects to the containers on port 8000.
		kubectl expose rs nginx --port=80 --target-port=8000

		# Create a service for an nginx deployment, which serves on port 80 and connects to the containers on port 8000.
		kubectl expose deployment nginx --port=80 --target-port=8000`)
)

func NewCmdExposeService(f *cmdutil.Factory, out io.Writer) *cobra.Command {
	options := &ExposeOptions{}

	validArgs, argAliases := []string{}, []string{}
	resources := regexp.MustCompile(`\s*,`).Split(expose_resources, -1)
	for _, r := range resources {
		validArgs = append(validArgs, strings.Fields(r)[0])
		argAliases = kubectl.ResourceAliases(validArgs)
	}

	cmd := &cobra.Command{
		Use:     "expose (-f FILENAME | TYPE NAME) [--port=port] [--protocol=TCP|UDP] [--target-port=number-or-name] [--name=name] [--external-ip=external-ip-of-service] [--type=type]",
		Short:   "Take a replication controller, service, deployment or pod and expose it as a new Kubernetes Service",
		Long:    expose_long,
		Example: expose_example,
		Run: func(cmd *cobra.Command, args []string) {
			err := RunExpose(f, out, cmd, args, options)
			cmdutil.CheckErr(err)
		},
		ValidArgs:  validArgs,
		ArgAliases: argAliases,
	}
	cmdutil.AddPrinterFlags(cmd)
	cmd.Flags().String("generator", "service/v2", "The name of the API generator to use. There are 2 generators: 'service/v1' and 'service/v2'. The only difference between them is that service port in v1 is named 'default', while it is left unnamed in v2. Default is 'service/v2'.")
	cmd.Flags().String("protocol", "", "The network protocol for the service to be created. Default is 'TCP'.")
	cmd.Flags().String("port", "", "The port that the service should serve on. Copied from the resource being exposed, if unspecified")
	cmd.Flags().String("type", "", "Type for this service: ClusterIP, NodePort, or LoadBalancer. Default is 'ClusterIP'.")
	// TODO: remove create-external-load-balancer in code on or after Aug 25, 2016.
	cmd.Flags().Bool("create-external-load-balancer", false, "If true, create an external load balancer for this service (trumped by --type). Implementation is cloud provider dependent. Default is 'false'.")
	cmd.Flags().MarkDeprecated("create-external-load-balancer", "use --type=\"LoadBalancer\" instead")
	cmd.Flags().String("load-balancer-ip", "", "IP to assign to the Load Balancer. If empty, an ephemeral IP will be created and used (cloud-provider specific).")
	cmd.Flags().String("selector", "", "A label selector to use for this service. Only equality-based selector requirements are supported. If empty (the default) infer the selector from the replication controller or replica set.")
	cmd.Flags().StringP("labels", "l", "", "Labels to apply to the service created by this call.")
	cmd.Flags().String("container-port", "", "Synonym for --target-port")
	cmd.Flags().MarkDeprecated("container-port", "--container-port will be removed in the future, please use --target-port instead")
	cmd.Flags().String("target-port", "", "Name or number for the port on the container that the service should direct traffic to. Optional.")
	cmd.Flags().String("external-ip", "", "Additional external IP address (not managed by Kubernetes) to accept for the service. If this IP is routed to a node, the service can be accessed by this IP in addition to its generated service IP.")
	cmd.Flags().String("overrides", "", "An inline JSON override for the generated object. If this is non-empty, it is used to override the generated object. Requires that the object supply a valid apiVersion field.")
	cmd.Flags().String("name", "", "The name for the newly created object.")
	cmd.Flags().String("session-affinity", "", "If non-empty, set the session affinity for the service to this; legal values: 'None', 'ClientIP'")
	cmd.Flags().String("cluster-ip", "", "ClusterIP to be assigned to the service. Leave empty to auto-allocate, or set to 'None' to create a headless service.")

	usage := "Filename, directory, or URL to a file identifying the resource to expose a service"
	kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage)
	cmdutil.AddDryRunFlag(cmd)
	cmdutil.AddRecursiveFlag(cmd, &options.Recursive)
	cmdutil.AddApplyAnnotationFlags(cmd)
	cmdutil.AddRecordFlag(cmd)
	return cmd
}

func RunExpose(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *ExposeOptions) error {
	namespace, enforceNamespace, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	mapper, typer := f.Object(false)
	r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
		ContinueOnError().
		NamespaceParam(namespace).DefaultNamespace().
		FilenameParam(enforceNamespace, options.Recursive, options.Filenames...).
		ResourceTypeOrNameArgs(false, args...).
		Flatten().
		Do()
	err = r.Err()
	if err != nil {
		return cmdutil.UsageError(cmd, err.Error())
	}

	// Get the generator, setup and validate all required parameters
	generatorName := cmdutil.GetFlagString(cmd, "generator")
	generators := f.Generators("expose")
	generator, found := generators[generatorName]
	if !found {
		return cmdutil.UsageError(cmd, fmt.Sprintf("generator %q not found.", generatorName))
	}
	names := generator.ParamNames()

	err = r.Visit(func(info *resource.Info, err error) error {
		if err != nil {
			return err
		}

		mapping := info.ResourceMapping()
		if err := f.CanBeExposed(mapping.GroupVersionKind.GroupKind()); err != nil {
			return err
		}

		params := kubectl.MakeParams(cmd, names)
		name := info.Name
		if len(name) > validation.DNS1035LabelMaxLength {
			name = name[:validation.DNS1035LabelMaxLength]
		}
		params["default-name"] = name

		// For objects that need a pod selector, derive it from the exposed object in case a user
		// didn't explicitly specify one via --selector
		if s, found := params["selector"]; found && kubectl.IsZero(s) {
			s, err := f.MapBasedSelectorForObject(info.Object)
			if err != nil {
				return cmdutil.UsageError(cmd, fmt.Sprintf("couldn't retrieve selectors via --selector flag or introspection: %s", err))
			}
			params["selector"] = s
		}

		// For objects that need a port, derive it from the exposed object in case a user
		// didn't explicitly specify one via --port
		if port, found := params["port"]; found && kubectl.IsZero(port) {
			ports, err := f.PortsForObject(info.Object)
			if err != nil {
				return cmdutil.UsageError(cmd, fmt.Sprintf("couldn't find port via --port flag or introspection: %s", err))
			}
			switch len(ports) {
			case 0:
				return cmdutil.UsageError(cmd, "couldn't find port via --port flag or introspection")
			case 1:
				params["port"] = ports[0]
			default:
				params["ports"] = strings.Join(ports, ",")
			}
		}

		// Always try to derive protocols from the exposed object, may use
		// different protocols for different ports.
		if _, found := params["protocol"]; found {
			protocolsMap, err := f.ProtocolsForObject(info.Object)
			if err != nil {
				return cmdutil.UsageError(cmd, fmt.Sprintf("couldn't find protocol via introspection: %s", err))
			}
			if protocols := kubectl.MakeProtocols(protocolsMap); !kubectl.IsZero(protocols) {
				params["protocols"] = protocols
			}
		}

		if kubectl.IsZero(params["labels"]) {
			labels, err := f.LabelsForObject(info.Object)
			if err != nil {
				return err
			}
			params["labels"] = kubectl.MakeLabels(labels)
		}
		if err = kubectl.ValidateParams(names, params); err != nil {
			return err
		}
		// Check for invalid flags used against the present generator.
		if err := kubectl.EnsureFlagsValid(cmd, generators, generatorName); err != nil {
			return err
		}

		// Generate new object
		object, err := generator.Generate(params)
		if err != nil {
			return err
		}

		if inline := cmdutil.GetFlagString(cmd, "overrides"); len(inline) > 0 {
			codec := runtime.NewCodec(f.JSONEncoder(), f.Decoder(true))
			object, err = cmdutil.Merge(codec, object, inline, mapping.GroupVersionKind.Kind)
			if err != nil {
				return err
			}
		}

		resourceMapper := &resource.Mapper{
			ObjectTyper:  typer,
			RESTMapper:   mapper,
			ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
			Decoder:      f.Decoder(true),
		}
		info, err = resourceMapper.InfoForObject(object, nil)
		if err != nil {
			return err
		}
		if cmdutil.ShouldRecord(cmd, info) {
			if err := cmdutil.RecordChangeCause(object, f.Command()); err != nil {
				return err
			}
		}
		info.Refresh(object, true)
		if cmdutil.GetDryRunFlag(cmd) {
			return f.PrintObject(cmd, mapper, object, out)
		}
		if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, f.JSONEncoder()); err != nil {
			return err
		}

		// Serialize the object with the annotation applied.
		object, err = resource.NewHelper(info.Client, info.Mapping).Create(namespace, false, object)
		if err != nil {
			return err
		}

		if len(cmdutil.GetFlagString(cmd, "output")) > 0 {
			return f.PrintObject(cmd, mapper, object, out)
		}

		cmdutil.PrintSuccess(mapper, false, out, info.Mapping.Resource, info.Name, "exposed")
		return nil
	})
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package logging

import (
	"log"
	"net/http"

	"net"
	"strings"

	"github.com/gorilla/context"
	"github.com/satori/go.uuid"
)

func UUID(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		context.Set(r, "uuid", uuid.NewV4())
		h.ServeHTTP(w, r)
	})
}

func IP(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		for _, h := range []string{"X-Forwarded-For", "X-Real-Ip"} {
			addresses := strings.Split(r.Header.Get(h), ",")
			// march from right to left until we get a public address
			// that will be the address right before our proxy.
			for i := len(addresses) - 1; i >= 0; i-- {
				ip := strings.TrimSpace(addresses[i])
				// header can contain spaces too, strip those out.
				realIP := net.ParseIP(ip)
				if !realIP.IsGlobalUnicast() {
					// bad address, go to next
					continue
				}
				log.Printf("IP: %s\n", realIP.String())
				context.Set(r, "ip", realIP.String())
				break
			}
		}

		h.ServeHTTP(w, r)

	})
}

func ContentTypeJSON(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		h.ServeHTTP(w, r)
	})
}
<commit_msg>Removed ip logging to heroku logs<commit_after>package logging

import (
	"net/http"

	"net"
	"strings"

	"github.com/gorilla/context"
	"github.com/satori/go.uuid"
)

func UUID(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		context.Set(r, "uuid", uuid.NewV4())
		h.ServeHTTP(w, r)
	})
}

func IP(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		for _, h := range []string{"X-Forwarded-For", "X-Real-Ip"} {
			addresses := strings.Split(r.Header.Get(h), ",")
			// march from right to left until we get a public address
			// that will be the address right before our proxy.
			for i := len(addresses) - 1; i >= 0; i-- {
				ip := strings.TrimSpace(addresses[i])
				// header can contain spaces too, strip those out.
				realIP := net.ParseIP(ip)
				if !realIP.IsGlobalUnicast() {
					// bad address, go to next
					continue
				}
				context.Set(r, "ip", realIP.String())
				break
			}
		}

		h.ServeHTTP(w, r)

	})
}

func ContentTypeJSON(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		h.ServeHTTP(w, r)
	})
}
<|endoftext|>


<commit_before>// Copyright 2016-2017 Authors of Cilium
//
// 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 option

import (
	. "gopkg.in/check.v1"
)

type OptionSuite struct{}

var _ = Suite(&OptionSuite{})

func (s *OptionSuite) TestGetFmtOpt(c *C) {
	OptionTest := Option{
		Define:      "TEST_DEFINE",
		Description: "This is a test",
	}

	o := BoolOptions{
		Opts: OptionMap{
			"test": true,
			"BAR":  false,
		},
		Library: &OptionLibrary{
			"test": &OptionTest,
		},
	}
	c.Assert(o.GetFmtOpt("test"), Equals, "#define TEST_DEFINE")
	c.Assert(o.GetFmtOpt("BAR"), Equals, "#undef BAR")
	c.Assert(o.GetFmtOpt("BAZ"), Equals, "#undef BAZ")
}
<commit_msg>option: fixed broken option_test.go<commit_after>// Copyright 2016-2017 Authors of Cilium
//
// 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 option

import (
	"testing"

	. "gopkg.in/check.v1"
)

// Hook up gocheck into the "go test" runner.
func Test(t *testing.T) {
	TestingT(t)
}

type OptionSuite struct{}

var _ = Suite(&OptionSuite{})

func (s *OptionSuite) TestGetFmtOpt(c *C) {
	OptionTest := Option{
		Define:      "TEST_DEFINE",
		Description: "This is a test",
	}

	o := BoolOptions{
		Opts: OptionMap{
			"test": true,
			"BAR":  false,
		},
		Library: &OptionLibrary{
			"test": &OptionTest,
		},
	}
	c.Assert(o.GetFmtOpt("test"), Equals, "#define TEST_DEFINE")
	c.Assert(o.GetFmtOpt("BAR"), Equals, "#undef BAR")
	c.Assert(o.GetFmtOpt("BAZ"), Equals, "#undef BAZ")
}
<|endoftext|>


<commit_before>// +build real

package carbonserver

import (
	"context"
	"flag"
	"io/ioutil"
	"reflect"
	"runtime/debug"
	"sort"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/OneOfOne/go-utils/memory"
)

var testDataPath = flag.String("testdata", "files.txt", "path to test file")
var checkMemory = flag.Bool("memory-size", false, "show index memory size")
var targetQueryPath = flag.String("query-data", "queries.txt", "queries for testing")
var carbonPath = flag.String("carbon", "/var/lib/carbon/whisper", "carbon data path")
var noTrigram = flag.Bool("no-trigram", false, "disable trigram search")
var pureTrie = flag.Bool("no-trie-with-trigram", false, "enable trigram in trie")
var localTest = flag.Bool("local-test", false, "trim prefix and replace / with . on trigram result")
var excludeFilesNotInTestData = flag.Bool("exclude-non-test-files", false, "filter out files trigram matched by using filepath.Glob")

func readFile(path string) []string {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}

	// if strings.HasSuffix(path, ".tar.gz") || strings.HasSuffix(path, ".tgz") {
	// 	tar.NewReader()
	// }

	lines := strings.Split(string(data), "\n")
	if lines[len(lines)-1] == "" {
		return lines[:len(lines)-1]
	}
	return lines
}

// TestTrieGlobRealData is built for benchmarking against real data, for two reasons:
// 		* trigram index solution invokes stat syscall
// 		* can't share production data in open source project
func TestTrieGlobRealData(t *testing.T) {
	files := readFile(*testDataPath)
	filesm := make(map[string]bool)
	dirm := make(map[string]bool)
	for _, f := range files {
		f = strings.TrimSuffix(f, ".wsp")
		f = strings.TrimPrefix(f, "/")
		filesm[f] = true
		dirs := strings.Split(f, "/")
		for i := range dirs[:len(dirs)-1] {
			dirm[strings.Join(dirs[:i+1], "/")] = true
		}
	}
	var trieServer, trigramServer *CarbonserverListener

	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		trieServer = newTrieServer(files, !*pureTrie)
		trieServer.whisperData = *carbonPath

		if *checkMemory {
			start := time.Now()
			t.Logf("memory.Sizeof(btrieServer)\t\t= %+v took %s\n", memory.Sizeof(trieServer), time.Now().Sub(start))
		}
		wg.Done()
	}()

	if !*noTrigram {
		wg.Add(1)
		go func() {
			trigramServer = newTrigramServer(files)
			trigramServer.whisperData = *carbonPath

			if *checkMemory {
				start := time.Now()
				t.Logf("memory.Sizeof(btrigramServer)\t\t= %+v took %s\n", memory.Sizeof(trigramServer), time.Now().Sub(start))
			}
			wg.Done()
		}()
	}
	wg.Wait()

	queries := readFile(*targetQueryPath)
	for _, query := range queries {
		t.Run(query, func(t *testing.T) {
			defer func() {
				if r := recover(); r != nil {
					t.Errorf("%q: %s", query, r)
					debug.PrintStack()
				}
			}()
			start1 := time.Now()
			trierc := make(chan *ExpandedGlobResponse, 1)
			trieServer.expandGlobs(context.TODO(), query, trierc)
			trier := <-trierc
			trieFiles, trieLeafs, err := trier.Files, trier.Leafs, trier.Err
			if err != nil {
				t.Errorf("trie search error: %s", err)
			}
			trieTime := time.Now().Sub(start1)
			t.Logf("trie took %s", trieTime)

			// for i, str := range trieFiles {
			// 	log.Printf("%d: %s\n", i, str)
			// }
			// log.Printf("len(trieFiles) = %+v\n", len(trieFiles))

			if *noTrigram {
				return
			}

			start2 := time.Now()
			trigramrc := make(chan *ExpandedGlobResponse, 1)
			trigramServer.expandGlobs(context.TODO(), query, trigramrc)
			trigramr := <-trigramrc
			trigramFiles, trigramLeafs, err := trigramr.Files, trigramr.Leafs, trigramr.Err
			// log.Printf("trigramLeafs = %+v\n", trigramLeafs)
			if err != nil {
				t.Errorf("trigram search error: %s", err)
			}
			trigramTime := time.Now().Sub(start2)
			t.Logf("trigram took %s", trigramTime)

			if *localTest {
				for i := range trigramFiles {
					trigramFiles[i] = strings.TrimPrefix(trigramFiles[i], *carbonPath+"/")
					trigramFiles[i] = strings.TrimSuffix(trigramFiles[i], ".wsp")
					trigramFiles[i] = strings.Replace(trigramFiles[i], "/", ".", -1)
				}
			}
			if *excludeFilesNotInTestData {
				var index int
				for i := range trigramFiles {
					name := strings.Replace(trigramFiles[i], ".", "/", -1)
					if (trigramLeafs[i] && filesm[name]) || (!trigramLeafs[i] && dirm[name]) {
						trigramFiles[index] = trigramFiles[i]
						trigramLeafs[index] = trigramLeafs[i]
						index++
					}
				}
				// if index == 0 {
				// 	index = 1
				// }
				trigramFiles = trigramFiles[:index]
				trigramLeafs = trigramLeafs[:index]
			}

			if trieTime < trigramTime {
				t.Logf("trie is %f times faster", float64(trigramTime)/float64(trieTime))
			} else {
				t.Logf("trie is %f times slower", float64(trieTime)/float64(trigramTime))
			}

			t.Logf("trie %d trigram %d", len(trieFiles), len(trigramFiles))

			sortFilesLeafs(trieFiles, trieLeafs)
			sortFilesLeafs(trigramFiles, trigramLeafs)

			if trieFiles == nil {
				trieFiles = []string{}
			}
			if trigramFiles == nil {
				trigramFiles = []string{}
			}
			if trieLeafs == nil {
				trieLeafs = []bool{}
			}
			if trigramLeafs == nil {
				trigramLeafs = []bool{}
			}

			if !reflect.DeepEqual(trieFiles, trigramFiles) {
				t.Errorf("files diff\n\ttrie:    %v\n\ttrigram: %v\n", trieFiles, trigramFiles)
			}
			if trieLeafs == nil {
				trieLeafs = []bool{}
			}
			if !reflect.DeepEqual(trieLeafs, trigramLeafs[:]) {
				t.Errorf("leafs diff\n\ttrie:    %#v\n\ttrigram: %#v\n", trieLeafs, trigramLeafs)
			}
		})
	}
}

func sortFilesLeafs(files []string, leafs []bool) {
	if len(files) <= 1 {
		return
	}

	oldIndex := map[string]int{}
	for i, f := range files {
		oldIndex[f] = i
	}
	sort.Strings(files)
	oldLeafs := make([]bool, len(leafs))
	copy(leafs, oldLeafs)
	for i, f := range files {
		leafs[i] = oldLeafs[oldIndex[f]]
	}
}
<commit_msg>trie: trie_real_test.go: fix some minor (testing) bugs and reduce test noises due to duplicated trigram query result<commit_after>// +build real

package carbonserver

import (
	"context"
	"flag"
	"io/ioutil"
	"reflect"
	"runtime/debug"
	"sort"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/OneOfOne/go-utils/memory"
)

var testDataPath = flag.String("testdata", "files.txt", "path to test file")
var checkMemory = flag.Bool("memory-size", false, "show index memory size")
var targetQueryPath = flag.String("query-data", "queries.txt", "queries for testing")
var carbonPath = flag.String("carbon", "/var/lib/carbon/whisper", "carbon data path")
var noTrigram = flag.Bool("no-trigram", false, "disable trigram search")
var pureTrie = flag.Bool("no-trie-with-trigram", false, "enable trigram in trie")
var localTest = flag.Bool("local-test", false, "trim prefix and replace / with . on trigram result")
var excludeFilesNotInTestData = flag.Bool("exclude-non-test-files", false, "filter out files trigram matched by using filepath.Glob")

func readFile(path string) []string {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}

	// if strings.HasSuffix(path, ".tar.gz") || strings.HasSuffix(path, ".tgz") {
	// 	tar.NewReader()
	// }

	lines := strings.Split(string(data), "\n")
	if lines[len(lines)-1] == "" {
		return lines[:len(lines)-1]
	}
	return lines
}

// TestTrieGlobRealData is built for benchmarking against real data, for two reasons:
// 		* trigram index solution invokes stat syscall
// 		* can't share production data in open source project
func TestTrieGlobRealData(t *testing.T) {
	files := readFile(*testDataPath)
	filesm := make(map[string]bool)
	dirm := make(map[string]bool)
	for _, f := range files {
		f = strings.TrimSuffix(f, ".wsp")
		f = strings.TrimPrefix(f, "/")
		filesm[f] = true
		dirs := strings.Split(f, "/")
		for i := range dirs[:len(dirs)-1] {
			dirm[strings.Join(dirs[:i+1], "/")] = true
		}
	}
	var trieServer, trigramServer *CarbonserverListener

	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		trieServer = newTrieServer(files, !*pureTrie)
		trieServer.whisperData = *carbonPath

		if *checkMemory {
			start := time.Now()
			t.Logf("memory.Sizeof(btrieServer)\t\t= %+v took %s\n", memory.Sizeof(trieServer), time.Now().Sub(start))
		}
		wg.Done()
	}()

	if !*noTrigram {
		wg.Add(1)
		go func() {
			trigramServer = newTrigramServer(files)
			trigramServer.whisperData = *carbonPath

			if *checkMemory {
				start := time.Now()
				t.Logf("memory.Sizeof(btrigramServer)\t\t= %+v took %s\n", memory.Sizeof(trigramServer), time.Now().Sub(start))
			}
			wg.Done()
		}()
	}
	wg.Wait()

	queries := readFile(*targetQueryPath)
	for _, query := range queries {
		t.Run(query, func(t *testing.T) {
			defer func() {
				if r := recover(); r != nil {
					t.Errorf("%q: %s", query, r)
					debug.PrintStack()
				}
			}()
			start1 := time.Now()
			trierc := make(chan *ExpandedGlobResponse, 1)
			trieServer.expandGlobs(context.TODO(), query, trierc)
			trier := <-trierc
			trieFiles, trieLeafs, err := trier.Files, trier.Leafs, trier.Err
			if err != nil {
				t.Errorf("trie search error: %s", err)
			}
			trieTime := time.Now().Sub(start1)
			t.Logf("trie took %s", trieTime)

			// for i, str := range trieFiles {
			// 	log.Printf("%d: %s %t\n", i, str, trieLeafs[i])
			// }
			// log.Printf("len(trieFiles) = %+v\n", len(trieFiles))

			if *noTrigram {
				return
			}

			start2 := time.Now()
			trigramrc := make(chan *ExpandedGlobResponse, 1)
			trigramServer.expandGlobs(context.TODO(), query, trigramrc)
			trigramr := <-trigramrc
			trigramFiles, trigramLeafs, err := trigramr.Files, trigramr.Leafs, trigramr.Err
			// log.Printf("trigramLeafs = %+v\n", trigramLeafs)
			if err != nil {
				t.Errorf("trigram search error: %s", err)
			}
			trigramTime := time.Now().Sub(start2)
			t.Logf("trigram took %s", trigramTime)

			if *localTest {
				for i := range trigramFiles {
					trigramFiles[i] = strings.TrimPrefix(trigramFiles[i], *carbonPath+"/")
					trigramFiles[i] = strings.TrimSuffix(trigramFiles[i], ".wsp")
					trigramFiles[i] = strings.Replace(trigramFiles[i], "/", ".", -1)
				}
			}
			if *excludeFilesNotInTestData {
				var index int
				for i := range trigramFiles {
					name := strings.Replace(trigramFiles[i], ".", "/", -1)
					if (trigramLeafs[i] && filesm[name]) || (!trigramLeafs[i] && dirm[name]) {
						trigramFiles[index] = trigramFiles[i]
						trigramLeafs[index] = trigramLeafs[i]
						index++
					}
				}
				// if index == 0 {
				// 	index = 1
				// }
				trigramFiles = trigramFiles[:index]
				trigramLeafs = trigramLeafs[:index]
			}

			if trieTime < trigramTime {
				t.Logf("trie is %f times faster", float64(trigramTime)/float64(trieTime))
			} else {
				t.Logf("trie is %f times slower", float64(trieTime)/float64(trigramTime))
			}

			t.Logf("trie %d trigram %d (raw)", len(trieFiles), len(trigramFiles))

			sortFilesLeafs(trieFiles, trieLeafs)
			sortFilesLeafs(trigramFiles, trigramLeafs)

			// trigram index is returning duplicated result, might be due to my test
			// environment, adding a simple de-duplication here to reduce noise.
			trigramFiles, trigramLeafs = uniqFilesLeafs(trigramFiles, trigramLeafs)

			t.Logf("trie %d trigram %d (unique)", len(trieFiles), len(trigramFiles))

			if trieFiles == nil {
				trieFiles = []string{}
			}
			if trigramFiles == nil {
				trigramFiles = []string{}
			}
			if trieLeafs == nil {
				trieLeafs = []bool{}
			}
			if trigramLeafs == nil {
				trigramLeafs = []bool{}
			}

			if !reflect.DeepEqual(trieFiles, trigramFiles) {
				t.Errorf("files diff\n\ttrie:    %v\n\ttrigram: %v\n", trieFiles, trigramFiles)
			}
			if trieLeafs == nil {
				trieLeafs = []bool{}
			}
			if !reflect.DeepEqual(trieLeafs, trigramLeafs[:]) {
				t.Errorf("leafs diff\n\ttrie:    %#v\n\ttrigram: %#v\n", trieLeafs, trigramLeafs)
			}
		})
	}
}

func sortFilesLeafs(files []string, leafs []bool) {
	if len(files) <= 1 {
		return
	}

	oldIndex := map[string]int{}
	for i, f := range files {
		oldIndex[f] = i
	}
	sort.Strings(files)
	oldLeafs := make([]bool, len(leafs))
	copy(oldLeafs, leafs)
	for i, f := range files {
		leafs[i] = oldLeafs[oldIndex[f]]
	}
}

func uniqFilesLeafs(files []string, leafs []bool) ([]string, []bool) {
	if len(files) <= 1 {
		return files, leafs
	}
	var index = 0
	for i := 1; i < len(files); i++ {
		if files[index] == files[i] {
			continue
		}
		index++
		files[index] = files[i]
		leafs[index] = leafs[i]
	}
	return files[:index+1], leafs[:index+1]
}
<|endoftext|>


<commit_before>package http

import (
	"context"
	"fmt"
	"hash/fnv"
	"io"
	"net/http"
	"time"

	"github.com/cenkalti/backoff/v4"
	"github.com/traefik/paerser/file"
	ptypes "github.com/traefik/paerser/types"
	"github.com/traefik/traefik/v2/pkg/config/dynamic"
	"github.com/traefik/traefik/v2/pkg/job"
	"github.com/traefik/traefik/v2/pkg/log"
	"github.com/traefik/traefik/v2/pkg/provider"
	"github.com/traefik/traefik/v2/pkg/safe"
	"github.com/traefik/traefik/v2/pkg/tls"
	"github.com/traefik/traefik/v2/pkg/types"
)

var _ provider.Provider = (*Provider)(nil)

// Provider is a provider.Provider implementation that queries an HTTP(s) endpoint for a configuration.
type Provider struct {
	Endpoint              string           `description:"Load configuration from this endpoint." json:"endpoint" toml:"endpoint" yaml:"endpoint"`
	PollInterval          ptypes.Duration  `description:"Polling interval for endpoint." json:"pollInterval,omitempty" toml:"pollInterval,omitempty" yaml:"pollInterval,omitempty" export:"true"`
	PollTimeout           ptypes.Duration  `description:"Polling timeout for endpoint." json:"pollTimeout,omitempty" toml:"pollTimeout,omitempty" yaml:"pollTimeout,omitempty" export:"true"`
	TLS                   *types.ClientTLS `description:"Enable TLS support." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
	httpClient            *http.Client
	lastConfigurationHash uint64
}

// SetDefaults sets the default values.
func (p *Provider) SetDefaults() {
	p.PollInterval = ptypes.Duration(5 * time.Second)
	p.PollTimeout = ptypes.Duration(5 * time.Second)
}

// Init the provider.
func (p *Provider) Init() error {
	if p.Endpoint == "" {
		return fmt.Errorf("non-empty endpoint is required")
	}

	if p.PollInterval <= 0 {
		return fmt.Errorf("poll interval must be greater than 0")
	}

	p.httpClient = &http.Client{
		Timeout: time.Duration(p.PollTimeout),
	}

	if p.TLS != nil {
		tlsConfig, err := p.TLS.CreateTLSConfig(context.Background())
		if err != nil {
			return fmt.Errorf("unable to create client TLS configuration: %w", err)
		}

		p.httpClient.Transport = &http.Transport{
			TLSClientConfig: tlsConfig,
		}
	}

	return nil
}

// Provide allows the provider to provide configurations to traefik using the given configuration channel.
func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error {
	pool.GoCtx(func(routineCtx context.Context) {
		ctxLog := log.With(routineCtx, log.Str(log.ProviderName, "http"))
		logger := log.FromContext(ctxLog)

		operation := func() error {
			ticker := time.NewTicker(time.Duration(p.PollInterval))
			defer ticker.Stop()

			for {
				select {
				case <-ticker.C:
					configData, err := p.fetchConfigurationData()
					if err != nil {
						return fmt.Errorf("cannot fetch configuration data: %w", err)
					}

					fnvHasher := fnv.New64()

					_, err = fnvHasher.Write(configData)
					if err != nil {
						return fmt.Errorf("cannot hash configuration data: %w", err)
					}

					hash := fnvHasher.Sum64()
					if hash == p.lastConfigurationHash {
						continue
					}

					p.lastConfigurationHash = hash

					configuration, err := decodeConfiguration(configData)
					if err != nil {
						return fmt.Errorf("cannot decode configuration data: %w", err)
					}

					configurationChan <- dynamic.Message{
						ProviderName:  "http",
						Configuration: configuration,
					}

				case <-routineCtx.Done():
					return nil
				}
			}
		}

		notify := func(err error, time time.Duration) {
			logger.Errorf("Provider connection error %+v, retrying in %s", err, time)
		}
		err := backoff.RetryNotify(safe.OperationWithRecover(operation), backoff.WithContext(job.NewBackOff(backoff.NewExponentialBackOff()), ctxLog), notify)
		if err != nil {
			logger.Errorf("Cannot connect to server endpoint %+v", err)
		}
	})

	return nil
}

// fetchConfigurationData fetches the configuration data from the configured endpoint.
func (p *Provider) fetchConfigurationData() ([]byte, error) {
	res, err := p.httpClient.Get(p.Endpoint)
	if err != nil {
		return nil, err
	}

	defer res.Body.Close()

	if res.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("received non-ok response code: %d", res.StatusCode)
	}

	return io.ReadAll(res.Body)
}

// decodeConfiguration decodes and returns the dynamic configuration from the given data.
func decodeConfiguration(data []byte) (*dynamic.Configuration, error) {
	configuration := &dynamic.Configuration{
		HTTP: &dynamic.HTTPConfiguration{
			Routers:           make(map[string]*dynamic.Router),
			Middlewares:       make(map[string]*dynamic.Middleware),
			Services:          make(map[string]*dynamic.Service),
			ServersTransports: make(map[string]*dynamic.ServersTransport),
		},
		TCP: &dynamic.TCPConfiguration{
			Routers:  make(map[string]*dynamic.TCPRouter),
			Services: make(map[string]*dynamic.TCPService),
		},
		TLS: &dynamic.TLSConfiguration{
			Stores:  make(map[string]tls.Store),
			Options: make(map[string]tls.Options),
		},
		UDP: &dynamic.UDPConfiguration{
			Routers:  make(map[string]*dynamic.UDPRouter),
			Services: make(map[string]*dynamic.UDPService),
		},
	}

	err := file.DecodeContent(string(data), ".yaml", configuration)
	if err != nil {
		return nil, err
	}

	return configuration, nil
}
<commit_msg>Start polling HTTP provider at the beginning<commit_after>package http

import (
	"context"
	"fmt"
	"hash/fnv"
	"io"
	"net/http"
	"time"

	"github.com/cenkalti/backoff/v4"
	"github.com/traefik/paerser/file"
	ptypes "github.com/traefik/paerser/types"
	"github.com/traefik/traefik/v2/pkg/config/dynamic"
	"github.com/traefik/traefik/v2/pkg/job"
	"github.com/traefik/traefik/v2/pkg/log"
	"github.com/traefik/traefik/v2/pkg/provider"
	"github.com/traefik/traefik/v2/pkg/safe"
	"github.com/traefik/traefik/v2/pkg/tls"
	"github.com/traefik/traefik/v2/pkg/types"
)

var _ provider.Provider = (*Provider)(nil)

// Provider is a provider.Provider implementation that queries an HTTP(s) endpoint for a configuration.
type Provider struct {
	Endpoint              string           `description:"Load configuration from this endpoint." json:"endpoint" toml:"endpoint" yaml:"endpoint"`
	PollInterval          ptypes.Duration  `description:"Polling interval for endpoint." json:"pollInterval,omitempty" toml:"pollInterval,omitempty" yaml:"pollInterval,omitempty" export:"true"`
	PollTimeout           ptypes.Duration  `description:"Polling timeout for endpoint." json:"pollTimeout,omitempty" toml:"pollTimeout,omitempty" yaml:"pollTimeout,omitempty" export:"true"`
	TLS                   *types.ClientTLS `description:"Enable TLS support." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
	httpClient            *http.Client
	lastConfigurationHash uint64
}

// SetDefaults sets the default values.
func (p *Provider) SetDefaults() {
	p.PollInterval = ptypes.Duration(5 * time.Second)
	p.PollTimeout = ptypes.Duration(5 * time.Second)
}

// Init the provider.
func (p *Provider) Init() error {
	if p.Endpoint == "" {
		return fmt.Errorf("non-empty endpoint is required")
	}

	if p.PollInterval <= 0 {
		return fmt.Errorf("poll interval must be greater than 0")
	}

	p.httpClient = &http.Client{
		Timeout: time.Duration(p.PollTimeout),
	}

	if p.TLS != nil {
		tlsConfig, err := p.TLS.CreateTLSConfig(context.Background())
		if err != nil {
			return fmt.Errorf("unable to create client TLS configuration: %w", err)
		}

		p.httpClient.Transport = &http.Transport{
			TLSClientConfig: tlsConfig,
		}
	}

	return nil
}

// Provide allows the provider to provide configurations to traefik using the given configuration channel.
func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error {
	pool.GoCtx(func(routineCtx context.Context) {
		ctxLog := log.With(routineCtx, log.Str(log.ProviderName, "http"))
		logger := log.FromContext(ctxLog)

		operation := func() error {
			if err := p.updateConfiguration(configurationChan); err != nil {
				return err
			}

			ticker := time.NewTicker(time.Duration(p.PollInterval))
			defer ticker.Stop()

			for {
				select {
				case <-ticker.C:
					if err := p.updateConfiguration(configurationChan); err != nil {
						return err
					}

				case <-routineCtx.Done():
					return nil
				}
			}
		}

		notify := func(err error, time time.Duration) {
			logger.Errorf("Provider connection error %+v, retrying in %s", err, time)
		}
		err := backoff.RetryNotify(safe.OperationWithRecover(operation), backoff.WithContext(job.NewBackOff(backoff.NewExponentialBackOff()), ctxLog), notify)
		if err != nil {
			logger.Errorf("Cannot connect to server endpoint %+v", err)
		}
	})

	return nil
}

func (p *Provider) updateConfiguration(configurationChan chan<- dynamic.Message) error {
	configData, err := p.fetchConfigurationData()
	if err != nil {
		return fmt.Errorf("cannot fetch configuration data: %w", err)
	}

	fnvHasher := fnv.New64()

	if _, err = fnvHasher.Write(configData); err != nil {
		return fmt.Errorf("cannot hash configuration data: %w", err)
	}

	hash := fnvHasher.Sum64()
	if hash == p.lastConfigurationHash {
		return nil
	}

	p.lastConfigurationHash = hash

	configuration, err := decodeConfiguration(configData)
	if err != nil {
		return fmt.Errorf("cannot decode configuration data: %w", err)
	}

	configurationChan <- dynamic.Message{
		ProviderName:  "http",
		Configuration: configuration,
	}

	return nil
}

// fetchConfigurationData fetches the configuration data from the configured endpoint.
func (p *Provider) fetchConfigurationData() ([]byte, error) {
	res, err := p.httpClient.Get(p.Endpoint)
	if err != nil {
		return nil, err
	}

	defer res.Body.Close()

	if res.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("received non-ok response code: %d", res.StatusCode)
	}

	return io.ReadAll(res.Body)
}

// decodeConfiguration decodes and returns the dynamic configuration from the given data.
func decodeConfiguration(data []byte) (*dynamic.Configuration, error) {
	configuration := &dynamic.Configuration{
		HTTP: &dynamic.HTTPConfiguration{
			Routers:           make(map[string]*dynamic.Router),
			Middlewares:       make(map[string]*dynamic.Middleware),
			Services:          make(map[string]*dynamic.Service),
			ServersTransports: make(map[string]*dynamic.ServersTransport),
		},
		TCP: &dynamic.TCPConfiguration{
			Routers:  make(map[string]*dynamic.TCPRouter),
			Services: make(map[string]*dynamic.TCPService),
		},
		TLS: &dynamic.TLSConfiguration{
			Stores:  make(map[string]tls.Store),
			Options: make(map[string]tls.Options),
		},
		UDP: &dynamic.UDPConfiguration{
			Routers:  make(map[string]*dynamic.UDPRouter),
			Services: make(map[string]*dynamic.UDPService),
		},
	}

	err := file.DecodeContent(string(data), ".yaml", configuration)
	if err != nil {
		return nil, err
	}

	return configuration, nil
}
<|endoftext|>


<commit_before>package provisioning

import (
	log "github.com/Sirupsen/logrus"
	"os/exec"
	"github.com/intelsdi-x/swan/pkg/isolation"
	"time"
	"syscall"
)

// LocalTask implements Task interface.
type LocalTask struct{
	pid isolation.TaskPID
	statusCh chan Status
	status Status
	terminated bool
}

// NewLocalTask returns a LocalTask instance.
func NewLocalTask(pid isolation.TaskPID, statusCh chan Status) *LocalTask {
	t := &LocalTask{
		pid,
		statusCh,
		Status{},
		false,
	}
	return t
}

func (task *LocalTask) completeTask(status Status) {
	task.terminated = true
	task.status = status
	task.statusCh = nil
}

// Stop terminates the local task.
func (task *LocalTask) Stop() {
	if (task.terminated) {
		panic("Task is not running.")
	}

	log.Debug("Sending SIGTERM to PID ", -task.pid)
	err := syscall.Kill(-int(task.pid), syscall.SIGTERM)
	if (err != nil) {
		panic(err)
	}
}

// Status gets status of the local task.
func (task LocalTask) Status() Status {
	// TODO(bp): Get status.
	return task.status
}

// Wait blocks until process is terminated or timeout appeared.
// Returns true after timeout exceeds.
func (task *LocalTask) Wait(timeoutSeconds int) bool {
	if (task.terminated) {
		return false
	}

	if (timeoutSeconds == 0) {
		s := <-task.statusCh
		task.completeTask(s)

	} else {
		timeoutDuration := time.Duration(timeoutSeconds) * time.Second

		select {
		case s := <-task.statusCh:
			task.completeTask(s)
		case <-time.After(timeoutDuration):
			return true
		}
	}

	return false
}

// Local provisioning is responsible for providing the execution environment
// on local machine via exec.Command. It also needed to setup given isolation
// using Isolation Manager.
type Local struct{
	user string
	isolations []isolation.Isolation

	// It is important to set additional PGID for parent process and his children
	// to have ability to kill all the children processes.
	setPGID bool
}

// NewLocal returns a Local instance.
func NewLocal(user string, isolations []isolation.Isolation) Local {
	l := Local{
		user: user,
		isolations: isolations,
		setPGID: true,
	}
	return l
}

// Run runs the command given as input.
// Returned Task pointer is able to stop & monitor the provisioned process.
func (l Local) Run(command string) (Task) {
	statusCh := make(chan Status)

	taskPidCh := make(chan isolation.TaskPID)

	// Run task in local locally.
	go func() {
		log.Debug("Starting ", command)

		cmd := exec.Command("sh", "-c", command)

		cmd.SysProcAttr = &syscall.SysProcAttr{}
		cmd.SysProcAttr.Setpgid = l.setPGID

		err := cmd.Start()

		if (err != nil) {
			panic(err)
		}

		log.Debug("Started with pid ", cmd.Process.Pid)

		// Report the process id.
		taskPidCh <- isolation.TaskPID(cmd.Process.Pid)

		// Wait for task completion.
		cmd.Wait()

		log.Debug("Ended ", command)

		// TODO(bplotka): Fetch status code.

		output, _ := cmd.Output()
		statusCh <- Status{
			cmd.ProcessState.Sys().(syscall.WaitStatus),
			string(output),
		}
	}()

	// Get PID
	taskPid := <-taskPidCh

	// Perform rest of the isolation synchronously.
	for _, isolation := range l.isolations {
		isolation.Isolate(taskPid)
	}

	t := NewLocalTask(taskPid, statusCh)

	return t
}
<commit_msg>Added dot to Comment.<commit_after>package provisioning

import (
	log "github.com/Sirupsen/logrus"
	"os/exec"
	"github.com/intelsdi-x/swan/pkg/isolation"
	"time"
	"syscall"
)

// LocalTask implements Task interface.
type LocalTask struct{
	pid isolation.TaskPID
	statusCh chan Status
	status Status
	terminated bool
}

// NewLocalTask returns a LocalTask instance.
func NewLocalTask(pid isolation.TaskPID, statusCh chan Status) *LocalTask {
	t := &LocalTask{
		pid,
		statusCh,
		Status{},
		false,
	}
	return t
}

func (task *LocalTask) completeTask(status Status) {
	task.terminated = true
	task.status = status
	task.statusCh = nil
}

// Stop terminates the local task.
func (task *LocalTask) Stop() {
	if (task.terminated) {
		panic("Task is not running.")
	}

	log.Debug("Sending SIGTERM to PID ", -task.pid)
	err := syscall.Kill(-int(task.pid), syscall.SIGTERM)
	if (err != nil) {
		panic(err)
	}
}

// Status gets status of the local task.
func (task LocalTask) Status() Status {
	// TODO(bp): Get status.
	return task.status
}

// Wait blocks until process is terminated or timeout appeared.
// Returns true after timeout exceeds.
func (task *LocalTask) Wait(timeoutSeconds int) bool {
	if (task.terminated) {
		return false
	}

	if (timeoutSeconds == 0) {
		s := <-task.statusCh
		task.completeTask(s)

	} else {
		timeoutDuration := time.Duration(timeoutSeconds) * time.Second

		select {
		case s := <-task.statusCh:
			task.completeTask(s)
		case <-time.After(timeoutDuration):
			return true
		}
	}

	return false
}

// Local provisioning is responsible for providing the execution environment
// on local machine via exec.Command. It also needed to setup given isolation
// using Isolation Manager.
type Local struct{
	user string
	isolations []isolation.Isolation

	// It is important to set additional PGID for parent process and his children
	// to have ability to kill all the children processes.
	setPGID bool
}

// NewLocal returns a Local instance.
func NewLocal(user string, isolations []isolation.Isolation) Local {
	l := Local{
		user: user,
		isolations: isolations,
		setPGID: true,
	}
	return l
}

// Run runs the command given as input.
// Returned Task pointer is able to stop & monitor the provisioned process.
func (l Local) Run(command string) (Task) {
	statusCh := make(chan Status)

	taskPidCh := make(chan isolation.TaskPID)

	// Run task in local locally.
	go func() {
		log.Debug("Starting ", command)

		cmd := exec.Command("sh", "-c", command)

		cmd.SysProcAttr = &syscall.SysProcAttr{}
		cmd.SysProcAttr.Setpgid = l.setPGID

		err := cmd.Start()

		if (err != nil) {
			panic(err)
		}

		log.Debug("Started with pid ", cmd.Process.Pid)

		// Report the process id.
		taskPidCh <- isolation.TaskPID(cmd.Process.Pid)

		// Wait for task completion.
		cmd.Wait()

		log.Debug("Ended ", command)

		// TODO(bplotka): Fetch status code.

		output, _ := cmd.Output()
		statusCh <- Status{
			cmd.ProcessState.Sys().(syscall.WaitStatus),
			string(output),
		}
	}()

	// Get PID.
	taskPid := <-taskPidCh

	// Perform rest of the isolation synchronously.
	for _, isolation := range l.isolations {
		isolation.Isolate(taskPid)
	}

	t := NewLocalTask(taskPid, statusCh)

	return t
}
<|endoftext|>


<commit_before>package stats

import (
	"fmt"
	"net/http"
	"strings"

	statsd "gopkg.in/alexcesaro/statsd.v2"
)

type StatsClient struct {
	StatsDClient *statsd.Client
}

// NewStatsClient returns initialised stats client instance
func NewStatsClient(statsdClient *statsd.Client) *StatsClient {
	return &StatsClient{statsdClient}
}

// TrackRequest tracks stats for generic request
func (sc *StatsClient) TrackRequest(timing statsd.Timing, req *http.Request) {
	bucket := "request." + sc.getStatsdMetricName(req)

	timing.Send(bucket)
	sc.StatsDClient.Increment(bucket)
}

// TrackRoundTrip tracks stats for round trip request
func (sc *StatsClient) TrackRoundTrip(timing statsd.Timing, req *http.Request, success bool) {
	prefix := fmt.Sprintf("round-%s.", map[bool]string{true: "ok", false: "fail"}[success])
	bucket := prefix + sc.getStatsdMetricName(req)

	timing.Send(bucket)
	sc.StatsDClient.Increment(bucket)
}

// Returns metric name for StatsD in "<request method>.<request path>" format
func (sc *StatsClient) getStatsdMetricName(req *http.Request) string {
	path := strings.Replace(
		// Double underscores
		strings.Replace(req.URL.Path, "_", "__", -1),
		// and replace dots with single underscore
		".",
		"_",
		-1,
	)
	return fmt.Sprintf("%s.%s", strings.ToLower(req.Method), path)
}
<commit_msg>Take only first two sections of the path for stats<commit_after>package stats

import (
	"fmt"
	"net/http"
	"strings"

	statsd "gopkg.in/alexcesaro/statsd.v2"
)

type StatsClient struct {
	StatsDClient *statsd.Client
}

// NewStatsClient returns initialised stats client instance
func NewStatsClient(statsdClient *statsd.Client) *StatsClient {
	return &StatsClient{statsdClient}
}

// TrackRequest tracks stats for generic request
func (sc *StatsClient) TrackRequest(timing statsd.Timing, req *http.Request) {
	bucket := "request." + sc.getStatsdMetricName(req)

	timing.Send(bucket)
	sc.StatsDClient.Increment(bucket)
}

// TrackRoundTrip tracks stats for round trip request
func (sc *StatsClient) TrackRoundTrip(timing statsd.Timing, req *http.Request, success bool) {
	prefix := fmt.Sprintf("round-%s.", map[bool]string{true: "ok", false: "fail"}[success])
	bucket := prefix + sc.getStatsdMetricName(req)

	timing.Send(bucket)
	sc.StatsDClient.Increment(bucket)
}

// Returns metric name for StatsD in "<request method>.<request path>" format
func (sc *StatsClient) getStatsdMetricName(req *http.Request) string {
	path := strings.Replace(
		// Double underscores
		strings.Replace(req.URL.Path, "_", "__", -1),
		// and replace dots with single underscore
		".",
		"_",
		-1,
	)

	var pathFragments []string
	if path == "/" {
		pathFragments = []string{"/"}
	} else {
		// we need only two first fragments of path (first one always empty, as path always starts with slash)
		pathFragments = strings.Split(path, "/")
		fragmentsCount := 3
		if len(pathFragments) < fragmentsCount {
			fragmentsCount = len(pathFragments)
		}
		pathFragments = pathFragments[:fragmentsCount]
		pathFragments[0] = "/"
	}
	return fmt.Sprintf("%s.%s", strings.ToLower(req.Method), strings.Join(pathFragments, "."))
}
<|endoftext|>


<commit_before>package supervisor

import (
	"context"
	"fmt"
	"runtime/debug"
	"sync/atomic"

	"github.com/pkg/errors"
)

// A Process represents a goroutine being run from a Worker.
type Process struct {
	supervisor *Supervisor
	worker     *Worker
	// Used to signal graceful shutdown.
	shutdown       chan struct{}
	ready          bool
	shutdownClosed bool
}

// Supervisor returns the Supervisor that is managing this Process.
func (p *Process) Supervisor() *Supervisor {
	return p.supervisor
}

// Worker returns the Worker that this Process is running.
func (p *Process) Worker() *Worker {
	return p.worker
}

// Context returns the Process' context.
func (p *Process) Context() context.Context {
	return p.supervisor.context
}

// Ready is called by the Process' Worker to notify the supervisor
// that it is now ready.
func (p *Process) Ready() {
	p.Supervisor().change(func() {
		p.ready = true
	})
}

// Shutdown is used for graceful shutdown...
func (p *Process) Shutdown() <-chan struct{} {
	return p.shutdown
}

// Log is used for logging...
func (p *Process) Log(obj interface{}) {
	p.supervisor.Logger.Printf("%s: %v", p.Worker().Name, obj)
}

// Logf is used for logging...
func (p *Process) Logf(format string, args ...interface{}) {
	p.supervisor.Logger.Printf("%s: %v", p.Worker().Name, fmt.Sprintf(format, args...))
}

// We would _like_ to have Debug and Debugf, but we can't really support that with
// dlog right now. So for now, these are no-ops.
func (p *Process) Debug(obj interface{}) {
	// Yes, this is a no-op, see above.
	if false {
		p.supervisor.Logger.Printf("%s: %v", p.Worker().Name, obj)
	}
}

func (p *Process) Debugf(format string, args ...interface{}) {
	// Yes, this is a no-op, see above.
	if false {
		p.supervisor.Logger.Printf("%s: %v", p.Worker().Name, fmt.Sprintf(format, args...))
	}
}

func (p *Process) allocateID() int64 {
	return atomic.AddInt64(&p.Worker().children, 1)
}

// Go is shorthand for launching a child worker... it is named
// "<parent>[<child-count>]".
func (p *Process) Go(fn func(*Process) error) *Worker {
	w := &Worker{
		Name: fmt.Sprintf("%s[%d]", p.Worker().Name, p.allocateID()),
		Work: fn,
	}
	p.Supervisor().Supervise(w)
	return w
}

// GoName is shorthand for launching a named worker... it is named
// "<parent>.<name>".
func (p *Process) GoName(name string, fn func(*Process) error) *Worker {
	w := &Worker{
		Name: fmt.Sprintf("%s.%s", p.Worker().Name, name),
		Work: fn,
	}
	p.Supervisor().Supervise(w)
	return w
}

// Do is shorthand for proper shutdown handling while doing a
// potentially blocking activity. This method will return nil if the
// activity completes normally and an error if the activity panics or
// returns an error.
//
// If you want to know whether the work was aborted or might still be
// running when Do returns, then use DoClean like so:
//
//   aborted := errors.New("aborted")
//
//   err := p.DoClean(..., func() { return aborted })
//
//   if err == aborted {
//     ...
//   }
func (p *Process) Do(fn func() error) (err error) {
	return p.DoClean(fn, func() error { return nil })
}

// DoClean is the same as Process.Do() but executes the supplied clean
// function on abort.
func (p *Process) DoClean(fn, clean func() error) error {
	sup := p.Supervisor()
	done := make(chan struct{})
	go func() {
		var err error
		defer func() {
			if r := recover(); r != nil {
				stack := string(debug.Stack())
				err := errors.Errorf("FUNCTION PANICKED: %v\n%s", r, stack)
				sup.mutex.Lock()
				sup.errors = append(sup.errors, err)
				sup.wantsShutdown = true
				sup.mutex.Unlock()
			}
			select {
			case done <- err:
			default: // don't block if p.Shutdown() caused us to return early
			}
			close(done)
		}()

		err = fn()
	}()

	select {
	case <-p.Shutdown():
		return clean()
	case err := <-done:
		return err
	}
}
<commit_msg>(from AES) oops<commit_after>package supervisor

import (
	"context"
	"fmt"
	"runtime/debug"
	"sync/atomic"

	"github.com/pkg/errors"
)

// A Process represents a goroutine being run from a Worker.
type Process struct {
	supervisor *Supervisor
	worker     *Worker
	// Used to signal graceful shutdown.
	shutdown       chan struct{}
	ready          bool
	shutdownClosed bool
}

// Supervisor returns the Supervisor that is managing this Process.
func (p *Process) Supervisor() *Supervisor {
	return p.supervisor
}

// Worker returns the Worker that this Process is running.
func (p *Process) Worker() *Worker {
	return p.worker
}

// Context returns the Process' context.
func (p *Process) Context() context.Context {
	return p.supervisor.context
}

// Ready is called by the Process' Worker to notify the supervisor
// that it is now ready.
func (p *Process) Ready() {
	p.Supervisor().change(func() {
		p.ready = true
	})
}

// Shutdown is used for graceful shutdown...
func (p *Process) Shutdown() <-chan struct{} {
	return p.shutdown
}

// Log is used for logging...
func (p *Process) Log(obj interface{}) {
	p.supervisor.Logger.Printf("%s: %v", p.Worker().Name, obj)
}

// Logf is used for logging...
func (p *Process) Logf(format string, args ...interface{}) {
	p.supervisor.Logger.Printf("%s: %v", p.Worker().Name, fmt.Sprintf(format, args...))
}

// We would _like_ to have Debug and Debugf, but we can't really support that with
// dlog right now. So for now, these are no-ops.
func (p *Process) Debug(obj interface{}) {
	// Yes, this is a no-op, see above.
	if false {
		p.supervisor.Logger.Printf("%s: %v", p.Worker().Name, obj)
	}
}

func (p *Process) Debugf(format string, args ...interface{}) {
	// Yes, this is a no-op, see above.
	if false {
		p.supervisor.Logger.Printf("%s: %v", p.Worker().Name, fmt.Sprintf(format, args...))
	}
}

func (p *Process) allocateID() int64 {
	return atomic.AddInt64(&p.Worker().children, 1)
}

// Go is shorthand for launching a child worker... it is named
// "<parent>[<child-count>]".
func (p *Process) Go(fn func(*Process) error) *Worker {
	w := &Worker{
		Name: fmt.Sprintf("%s[%d]", p.Worker().Name, p.allocateID()),
		Work: fn,
	}
	p.Supervisor().Supervise(w)
	return w
}

// GoName is shorthand for launching a named worker... it is named
// "<parent>.<name>".
func (p *Process) GoName(name string, fn func(*Process) error) *Worker {
	w := &Worker{
		Name: fmt.Sprintf("%s.%s", p.Worker().Name, name),
		Work: fn,
	}
	p.Supervisor().Supervise(w)
	return w
}

// Do is shorthand for proper shutdown handling while doing a
// potentially blocking activity. This method will return nil if the
// activity completes normally and an error if the activity panics or
// returns an error.
//
// If you want to know whether the work was aborted or might still be
// running when Do returns, then use DoClean like so:
//
//   aborted := errors.New("aborted")
//
//   err := p.DoClean(..., func() { return aborted })
//
//   if err == aborted {
//     ...
//   }
func (p *Process) Do(fn func() error) (err error) {
	return p.DoClean(fn, func() error { return nil })
}

// DoClean is the same as Process.Do() but executes the supplied clean
// function on abort.
func (p *Process) DoClean(fn, clean func() error) error {
	sup := p.Supervisor()
	done := make(chan error)
	go func() {
		var err error
		defer func() {
			if r := recover(); r != nil {
				stack := string(debug.Stack())
				err := errors.Errorf("FUNCTION PANICKED: %v\n%s", r, stack)
				sup.mutex.Lock()
				sup.errors = append(sup.errors, err)
				sup.wantsShutdown = true
				sup.mutex.Unlock()
			}
			select {
			case done <- err:
			default: // don't block if p.Shutdown() caused us to return early
			}
			close(done)
		}()

		err = fn()
	}()

	select {
	case <-p.Shutdown():
		return clean()
	case err := <-done:
		return err
	}
}
<|endoftext|>


<commit_before>/******************************************************************************
 * Discordgo demo program.
 *
 * Please run this with command line arguments of email and password.
 */
package main

import (
	"fmt"
	"os"

	discord "github.com/bwmarrin/discordgo"
)

func main() {

	var err error
	var email string = os.Args[1]
	var password string = os.Args[2]

	// Create new session object and enable debugging.
	session := discord.Session{Debug: true}

	// Login to the Discord server with the provided  email and password
	// from the command line arguments
	session.Token, err = session.Login(email, password)
	if err != nil {
		fmt.Println("Unable to login to Discord.")
		fmt.Println(err)
		return
	}

	// Example using Request function to query a specific URL
	// This pulls authenticated user's information.
	// Request returns the actual request body not JSON
	body, err := discord.Request(&session, "http://discordapp.com/api/users/@me")
	fmt.Println(body)

	// Use the User function to do the same as above.  This function
	// returns a User structure
	user, err := discord.Users(&session, "@me")
	fmt.Println(user)

	// Use the PrivateChannels function to get a list of PrivateChannels
	// for a given user.
	private, err := discord.PrivateChannels(&session, "@me")
	fmt.Println(private)

	// Use the Servers function to pull all available servers for a given user
	// This returns a Server structure
	servers, err := discord.Servers(&session, "@me")
	fmt.Println(servers)

	// Use the Members function to pull all members of a given server.
	members, err := discord.Members(&session, servers[0].Id)
	fmt.Println(members)

	// Use the Channels function to pull all available channels for a given
	// server.  This returns a Channel structure.
	channels, err := discord.Channels(&session, servers[0].Id)
	fmt.Println(channels)

	// Use the Messages function to pull messages from the given channel
	// limit the result to 2 messages and don't provide beforeId or afterId
	messages, err := discord.Messages(&session, channels[0].Id, 2, 0, 0)
	fmt.Println(messages)

	// Use SendMessage to send a message to the given channel.
	responce, err := discord.SendMessage(&session, channels[0].Id, "Testing Discordgo")
	fmt.Println(responce)

	// Use the Logout function to Logout from the Discord server.
	discord.Logout(&session)
	return
}
<commit_msg>Removing demo, replacing it with new.<commit_after><|endoftext|>