<commit_before>package cli

import (
	"fmt"
	"os"
	"strings"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	"github.com/datawire/ambassador/pkg/kates"
	"github.com/datawire/telepresence2/v2/pkg/client/auth"
	"github.com/datawire/telepresence2/v2/pkg/client/connector"
	"github.com/datawire/telepresence2/v2/pkg/client/daemon"
)

var help = `Telepresence can connect to a cluster and route all outbound traffic from your
workstation to that cluster so that software running locally can communicate
as if it executed remotely, inside the cluster. This is achieved using the
command:

telepresence connect

Telepresence can also intercept traffic intended for a specific service in a
cluster and redirect it to your local workstation:

telepresence intercept <name of service>

Telepresence uses background processes to manage the cluster session. One of
the processes runs with superuser privileges because it modifies the network.
Unless the daemons are already started, an attempt will be made to start them.
This will involve a call to sudo unless this command is run as root (not
recommended) which in turn may result in a password prompt.`

// TODO: Provide a link in the help text to more info about telepresence

func statusCommand() *cobra.Command {
	return &cobra.Command{
		Use:   "status",
		Short: "Show connectivity status",
		Args:  cobra.NoArgs,
		RunE:  status,
	}
}

func versionCommand() *cobra.Command {
	return &cobra.Command{
		Use:     "version",
		Short:   "Show version",
		Args:    cobra.NoArgs,
		PreRunE: forcedUpdateCheck,
		RunE:    printVersion,
	}
}

func quitCommand() *cobra.Command {
	return &cobra.Command{
		Use:   "quit",
		Short: "Tell telepresence daemon to quit",
		Args:  cobra.NoArgs,
		RunE:  quit,
	}
}

// global options
var dnsIP string
var fallbackIP string
var kubeFlags *pflag.FlagSet

// OnlySubcommands is a cobra.PositionalArgs that is similar to cobra.NoArgs, but prints a better
// error message.
func OnlySubcommands(cmd *cobra.Command, args []string) error {
	if len(args) != 0 {
		err := fmt.Errorf("invalid subcommand %q", args[0])

		if cmd.SuggestionsMinimumDistance <= 0 {
			cmd.SuggestionsMinimumDistance = 2
		}
		if suggestions := cmd.SuggestionsFor(args[0]); len(suggestions) > 0 {
			err = fmt.Errorf("%w\nDid you mean one of these?\n\t%s", err, strings.Join(suggestions, "\n\t"))
		}

		return cmd.FlagErrorFunc()(cmd, err)
	}
	return nil
}

// RunSubCommands is for use as a cobra.Command.RunE for commands that don't do anything themselves
// but have subcommands.  In such cases, it is important to set RunE even though there's nothing to
// run, because otherwise cobra will treat that as "success", and it shouldn't be "success" if the
// user typos a command and types something invalid.
func RunSubcommands(cmd *cobra.Command, args []string) error {
	cmd.SetOutput(cmd.ErrOrStderr())
	cmd.HelpFunc()(cmd, args)
	return nil
}

// Command returns the top level "telepresence" CLI command
func Command() *cobra.Command {
	myName := "Telepresence"
	if !IsServerRunning() {
		myName = "Telepresence (daemon unavailable)"
	}

	rootCmd := &cobra.Command{
		Use:           "telepresence",
		Short:         myName,
		Long:          help,
		Args:          OnlySubcommands,
		RunE:          RunSubcommands,
		SilenceErrors: true, // main() will handle it after .ExecuteContext() returns
		SilenceUsage:  true, // our FlagErrorFunc will handle it
	}

	rootCmd.SetFlagErrorFunc(func(cmd *cobra.Command, err error) error {
		if err == nil {
			return nil
		}

		// If the error is multiple lines, include an extra blank line before the "See
		// --help" line.
		errStr := strings.TrimRight(err.Error(), "\n")
		if strings.Contains(errStr, "\n") {
			errStr += "\n"
		}

		fmt.Fprintf(cmd.ErrOrStderr(), "%s: %s\nSee '%s --help'.\n", cmd.CommandPath(), errStr, cmd.CommandPath())
		os.Exit(2)
		return nil
	})

	// Hidden/internal commands. These are called by Telepresence itself from
	// the correct context and execute in-place immediately.
	rootCmd.AddCommand(daemon.Command())
	rootCmd.AddCommand(connector.Command())

	globalFlagGroups = []FlagGroup{
		{
			Name: "Kubernetes flags",
			Flags: func() *pflag.FlagSet {
				kubeFlags = pflag.NewFlagSet("", 0)
				kates.NewConfigFlags(false).AddFlags(kubeFlags)
				return kubeFlags
			}(),
		},
		{
			Name: "Telepresence networking flags",
			Flags: func() *pflag.FlagSet {
				netflags := pflag.NewFlagSet("", 0)
				netflags.StringVarP(&dnsIP,
					"dns", "", "",
					"DNS IP address to intercept locally. Defaults to the first nameserver listed in /etc/resolv.conf.",
				)
				netflags.StringVarP(&fallbackIP,
					"fallback", "", "",
					"DNS fallback, how non-cluster DNS queries are resolved. Defaults to Google DNS (8.8.8.8).",
				)
				return netflags
			}(),
		},
		{
			Name: "other Telepresence flags",
			Flags: func() *pflag.FlagSet {
				flags := pflag.NewFlagSet("", 0)
				flags.Bool(
					"no-report", false,
					"turn off anonymous crash reports and log submission on failure",
				)
				return flags
			}(),
		},
	}

	rootCmd.InitDefaultHelpCmd()
	AddCommandGroups(rootCmd, []CommandGroup{
		{
			Name:     "Session Commands",
			Commands: []*cobra.Command{connectCommand(), auth.LoginCommand(), auth.LogoutCommand(), statusCommand(), quitCommand()},
		},
		{
			Name:     "Traffic Commands",
			Commands: []*cobra.Command{listCommand(), interceptCommand(), leaveCommand(), previewCommand()},
		},
		{
			Name:     "Other Commands",
			Commands: []*cobra.Command{versionCommand(), uninstallCommand(), dashboardCommand()},
		},
	})
	for _, group := range globalFlagGroups {
		rootCmd.PersistentFlags().AddFlagSet(group.Flags)
	}
	return rootCmd
}
<commit_msg>Use cmd.SetOut() instead of deprecated cmd.SetOutput()<commit_after>package cli

import (
	"fmt"
	"os"
	"strings"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	"github.com/datawire/ambassador/pkg/kates"
	"github.com/datawire/telepresence2/v2/pkg/client/auth"
	"github.com/datawire/telepresence2/v2/pkg/client/connector"
	"github.com/datawire/telepresence2/v2/pkg/client/daemon"
)

var help = `Telepresence can connect to a cluster and route all outbound traffic from your
workstation to that cluster so that software running locally can communicate
as if it executed remotely, inside the cluster. This is achieved using the
command:

telepresence connect

Telepresence can also intercept traffic intended for a specific service in a
cluster and redirect it to your local workstation:

telepresence intercept <name of service>

Telepresence uses background processes to manage the cluster session. One of
the processes runs with superuser privileges because it modifies the network.
Unless the daemons are already started, an attempt will be made to start them.
This will involve a call to sudo unless this command is run as root (not
recommended) which in turn may result in a password prompt.`

// TODO: Provide a link in the help text to more info about telepresence

func statusCommand() *cobra.Command {
	return &cobra.Command{
		Use:   "status",
		Short: "Show connectivity status",
		Args:  cobra.NoArgs,
		RunE:  status,
	}
}

func versionCommand() *cobra.Command {
	return &cobra.Command{
		Use:     "version",
		Short:   "Show version",
		Args:    cobra.NoArgs,
		PreRunE: forcedUpdateCheck,
		RunE:    printVersion,
	}
}

func quitCommand() *cobra.Command {
	return &cobra.Command{
		Use:   "quit",
		Short: "Tell telepresence daemon to quit",
		Args:  cobra.NoArgs,
		RunE:  quit,
	}
}

// global options
var dnsIP string
var fallbackIP string
var kubeFlags *pflag.FlagSet

// OnlySubcommands is a cobra.PositionalArgs that is similar to cobra.NoArgs, but prints a better
// error message.
func OnlySubcommands(cmd *cobra.Command, args []string) error {
	if len(args) != 0 {
		err := fmt.Errorf("invalid subcommand %q", args[0])

		if cmd.SuggestionsMinimumDistance <= 0 {
			cmd.SuggestionsMinimumDistance = 2
		}
		if suggestions := cmd.SuggestionsFor(args[0]); len(suggestions) > 0 {
			err = fmt.Errorf("%w\nDid you mean one of these?\n\t%s", err, strings.Join(suggestions, "\n\t"))
		}

		return cmd.FlagErrorFunc()(cmd, err)
	}
	return nil
}

// RunSubCommands is for use as a cobra.Command.RunE for commands that don't do anything themselves
// but have subcommands.  In such cases, it is important to set RunE even though there's nothing to
// run, because otherwise cobra will treat that as "success", and it shouldn't be "success" if the
// user typos a command and types something invalid.
func RunSubcommands(cmd *cobra.Command, args []string) error {
	cmd.SetOut(cmd.ErrOrStderr())
	cmd.HelpFunc()(cmd, args)
	return nil
}

// Command returns the top level "telepresence" CLI command
func Command() *cobra.Command {
	myName := "Telepresence"
	if !IsServerRunning() {
		myName = "Telepresence (daemon unavailable)"
	}

	rootCmd := &cobra.Command{
		Use:           "telepresence",
		Short:         myName,
		Long:          help,
		Args:          OnlySubcommands,
		RunE:          RunSubcommands,
		SilenceErrors: true, // main() will handle it after .ExecuteContext() returns
		SilenceUsage:  true, // our FlagErrorFunc will handle it
	}

	rootCmd.SetFlagErrorFunc(func(cmd *cobra.Command, err error) error {
		if err == nil {
			return nil
		}

		// If the error is multiple lines, include an extra blank line before the "See
		// --help" line.
		errStr := strings.TrimRight(err.Error(), "\n")
		if strings.Contains(errStr, "\n") {
			errStr += "\n"
		}

		fmt.Fprintf(cmd.ErrOrStderr(), "%s: %s\nSee '%s --help'.\n", cmd.CommandPath(), errStr, cmd.CommandPath())
		os.Exit(2)
		return nil
	})

	// Hidden/internal commands. These are called by Telepresence itself from
	// the correct context and execute in-place immediately.
	rootCmd.AddCommand(daemon.Command())
	rootCmd.AddCommand(connector.Command())

	globalFlagGroups = []FlagGroup{
		{
			Name: "Kubernetes flags",
			Flags: func() *pflag.FlagSet {
				kubeFlags = pflag.NewFlagSet("", 0)
				kates.NewConfigFlags(false).AddFlags(kubeFlags)
				return kubeFlags
			}(),
		},
		{
			Name: "Telepresence networking flags",
			Flags: func() *pflag.FlagSet {
				netflags := pflag.NewFlagSet("", 0)
				netflags.StringVarP(&dnsIP,
					"dns", "", "",
					"DNS IP address to intercept locally. Defaults to the first nameserver listed in /etc/resolv.conf.",
				)
				netflags.StringVarP(&fallbackIP,
					"fallback", "", "",
					"DNS fallback, how non-cluster DNS queries are resolved. Defaults to Google DNS (8.8.8.8).",
				)
				return netflags
			}(),
		},
		{
			Name: "other Telepresence flags",
			Flags: func() *pflag.FlagSet {
				flags := pflag.NewFlagSet("", 0)
				flags.Bool(
					"no-report", false,
					"turn off anonymous crash reports and log submission on failure",
				)
				return flags
			}(),
		},
	}

	rootCmd.InitDefaultHelpCmd()
	AddCommandGroups(rootCmd, []CommandGroup{
		{
			Name:     "Session Commands",
			Commands: []*cobra.Command{connectCommand(), auth.LoginCommand(), auth.LogoutCommand(), statusCommand(), quitCommand()},
		},
		{
			Name:     "Traffic Commands",
			Commands: []*cobra.Command{listCommand(), interceptCommand(), leaveCommand(), previewCommand()},
		},
		{
			Name:     "Other Commands",
			Commands: []*cobra.Command{versionCommand(), uninstallCommand(), dashboardCommand()},
		},
	})
	for _, group := range globalFlagGroups {
		rootCmd.PersistentFlags().AddFlagSet(group.Flags)
	}
	return rootCmd
}
<|endoftext|>


<commit_before>/*
Copyright 2016 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 controller

import (
	"github.com/golang/glog"
	"github.com/kubernetes-incubator/service-catalog/pkg/apis/servicecatalog"
	"github.com/kubernetes-incubator/service-catalog/pkg/brokerapi"
	"github.com/kubernetes-incubator/service-catalog/pkg/controller/apiclient"
	"github.com/kubernetes-incubator/service-catalog/pkg/controller/injector"
	"github.com/satori/go.uuid"
)

const (
	catalogURLFormatString      = "%s/v2/catalog"
	serviceInstanceFormatString = "%s/v2/service_instances/%s"
	bindingFormatString         = "%s/v2/service_instances/%s/service_bindings/%s"
	defaultNamespace            = "default"
)

// Handler defines an interface used as a facade for data access operations.
// The controller uses the functions of this interface as callbacks for various
// events.
type Handler interface {
	// CreateServiceInstance takes in a (possibly incomplete)
	// ServiceInstance and will either create or update an
	// existing one.
	CreateServiceInstance(*servicecatalog.Instance) (*servicecatalog.Instance, error)

	// CreateServiceBinding takes in a (possibly incomplete)
	// ServiceBinding and will either create or update an
	// existing one.
	CreateServiceBinding(*servicecatalog.Binding) (*servicecatalog.Binding, error)

	// CreateServiceBroker takes in a (possibly incomplete)
	// ServiceBroker and will either create or update an
	// existing one.
	CreateServiceBroker(*servicecatalog.Broker) (*servicecatalog.Broker, error)
}

type handler struct {
	apiClient     apiclient.APIClient
	injector      injector.BindingInjector
	newClientFunc func(*servicecatalog.Broker) brokerapi.BrokerClient
}

func createHandler(client apiclient.APIClient, injector injector.BindingInjector, newClientFn brokerapi.CreateFunc) *handler {
	return &handler{
		apiClient:     client,
		injector:      injector,
		newClientFunc: newClientFn,
	}
}

func (h *handler) updateServiceInstance(in *servicecatalog.Instance) error {
	// Currently there's no difference between create / update,
	// but for prepping for future, split these into two different
	// methods for now.
	return h.createServiceInstance(in)
}

func (h *handler) createServiceInstance(in *servicecatalog.Instance) error {
	broker, err := apiclient.GetBrokerByServiceClassName(h.apiClient.Brokers(), h.apiClient.ServiceClasses(), in.Spec.ServiceClassName)
	if err != nil {
		return err
	}
	client := h.newClientFunc(broker)

	// TODO: uncomment parameters line once parameters types are refactored.
	// Make the request to instantiate.
	createReq := &brokerapi.CreateServiceInstanceRequest{
		ServiceID: in.Spec.OSBServiceID,
		PlanID:    in.Spec.OSBPlanID,
		// Parameters: in.Spec.Parameters,
	}
	_, err = client.CreateServiceInstance(in.Spec.OSBGUID, createReq)
	return err
}

///////////////////////////////////////////////////////////////////////////////
// All the methods implementing the Handler interface go here for clarity sake.
///////////////////////////////////////////////////////////////////////////////
func (h *handler) CreateServiceInstance(in *servicecatalog.Instance) (*servicecatalog.Instance, error) {
	serviceID, planID, planName, err := apiclient.GetServicePlanInfo(
		h.apiClient.ServiceClasses(),
		in.Spec.ServiceClassName,
		in.Spec.PlanName,
	)
	if err != nil {
		glog.Errorf("Error fetching service ID: %v", err)
		return nil, err
	}
	in.Spec.OSBServiceID = serviceID
	in.Spec.OSBPlanID = planID
	in.Spec.PlanName = planName
	if in.Spec.OSBGUID == "" {
		in.Spec.OSBGUID = uuid.NewV4().String()
	}

	glog.Infof("Instantiating service %s using service/plan %s : %s", in.Name, serviceID, planID)

	err = h.createServiceInstance(in)
	in.Status = servicecatalog.InstanceStatus{}
	if err != nil {
		in.Status.Conditions = []servicecatalog.InstanceCondition{
			{
				Type:   servicecatalog.InstanceConditionProvisionFailed,
				Status: servicecatalog.ConditionTrue,
				Reason: err.Error(),
			},
		}
		glog.Errorf("Failed to create service instance: %v", err)
	} else {
		in.Status.Conditions = []servicecatalog.InstanceCondition{
			{
				Type:   servicecatalog.InstanceConditionReady,
				Status: servicecatalog.ConditionTrue,
			},
		}
	}

	glog.Infof("Updating Service %s with State\n%v", in.Name, in.Status.Conditions[0].Type)
	return h.apiClient.Instances(in.ObjectMeta.Namespace).Update(in)
}

func (h *handler) CreateServiceBinding(in *servicecatalog.Binding) (*servicecatalog.Binding, error) {
	glog.Infof("Creating Service Binding: %v", in)

	// Get instance information for service being bound to.
	instance, err := h.apiClient.Instances(in.Spec.InstanceRef.Namespace).Get(in.Spec.InstanceRef.Name)
	if err != nil {
		glog.Errorf("Service instance does not exist %v: %v", in.Spec.InstanceRef, err)
		return nil, err
	}

	// Get the serviceclass for the instance.
	sc, err := h.apiClient.ServiceClasses().Get(instance.Spec.ServiceClassName)
	if err != nil {
		glog.Errorf("Failed to fetch service type %s : %v", instance.Spec.ServiceClassName, err)
		return nil, err
	}

	// Get the broker for the serviceclass.
	broker, err := h.apiClient.Brokers().Get(sc.BrokerName)
	if err != nil {
		glog.Errorf("Error fetching broker for service: %s : %v", sc.BrokerName, err)
		return nil, err
	}
	client := h.newClientFunc(broker)

	// Assign UUID to binding.
	in.Spec.OSBGUID = uuid.NewV4().String()

	// TODO: uncomment parameters line once parameters types are refactored.
	// Make the request to bind.
	createReq := &brokerapi.BindingRequest{
		ServiceID: instance.Spec.OSBServiceID,
		PlanID:    instance.Spec.OSBPlanID,
		// Parameters: in.Spec.Parameters,
	}
	sbr, err := client.CreateServiceBinding(instance.Spec.OSBGUID, in.Spec.OSBGUID, createReq)

	in.Status = servicecatalog.BindingStatus{}
	if err != nil {
		in.Status.Conditions = []servicecatalog.BindingCondition{
			{
				Type:   servicecatalog.BindingConditionFailed,
				Status: servicecatalog.ConditionTrue,
				Reason: err.Error(),
			},
		}
		glog.Errorf("Failed to create service instance: %v", err)
	} else {
		// Now try injection
		err := h.injector.Inject(in, &sbr.Credentials)
		if err != nil {
			in.Status.Conditions = []servicecatalog.BindingCondition{
				{
					Type:   servicecatalog.BindingConditionFailed,
					Status: servicecatalog.ConditionTrue,
					Reason: err.Error(),
				},
			}
			glog.Errorf("Failed to create service instance: %v", err)
		} else {
			in.Status.Conditions = []servicecatalog.BindingCondition{
				{
					Type:   servicecatalog.BindingConditionReady,
					Status: servicecatalog.ConditionTrue,
				},
			}
		}
	}

	glog.Infof("Updating Service Binding %s with State\n%v", in.Name, in.Status.Conditions[0].Type)
	return h.apiClient.Bindings(in.ObjectMeta.Namespace).Update(in)
}

func (h *handler) CreateServiceBroker(in *servicecatalog.Broker) (*servicecatalog.Broker, error) {
	client := h.newClientFunc(in)
	sbcat, err := client.GetCatalog()
	if err != nil {
		return nil, err
	}
	catalog, err := convertCatalog(sbcat)
	if err != nil {
		return nil, err
	}

	glog.Infof("Adding a broker %s catalog:\n%v\n", in.Name, catalog)
	_, err = h.apiClient.Brokers().Create(in)
	if err != nil {
		return nil, err
	}

	for _, sc := range catalog {
		sc.BrokerName = in.Name
		if _, err := h.apiClient.ServiceClasses().Create(sc); err != nil {
			return nil, err
		}
	}

	in.Status.Conditions = []servicecatalog.BrokerCondition{
		{
			Type:   servicecatalog.BrokerConditionReady,
			Status: servicecatalog.ConditionTrue,
		},
	}

	glog.Infof("Updating Service Broker %s with State\n%v", in.Name, in.Status.Conditions[0].Type)
	return h.apiClient.Brokers().Update(in)
}

// convertCatalog converts a service broker catalog into an array of ServiceClasses
func convertCatalog(in *brokerapi.Catalog) ([]*servicecatalog.ServiceClass, error) {
	ret := make([]*servicecatalog.ServiceClass, len(in.Services))
	for i, svc := range in.Services {
		plans := convertServicePlans(svc.Plans)
		ret[i] = &servicecatalog.ServiceClass{
			Bindable:      svc.Bindable,
			Plans:         plans,
			PlanUpdatable: svc.PlanUpdateable,
			OSBGUID:       svc.ID,
			OSBTags:       svc.Tags,
			OSBRequires:   svc.Requires,
			// OSBMetadata:   svc.Metadata,
		}
		ret[i].SetName(svc.Name)
	}
	return ret, nil
}

func convertServicePlans(plans []brokerapi.ServicePlan) []servicecatalog.ServicePlan {
	ret := make([]servicecatalog.ServicePlan, len(plans))
	for i, plan := range plans {
		ret[i] = servicecatalog.ServicePlan{
			Name:    plan.Name,
			OSBGUID: plan.ID,
			// OSBMetadata: plan.Metadata,
			OSBFree: plan.Free,
		}
	}
	return ret
}
<commit_msg>Stop creating broker that's already created<commit_after>/*
Copyright 2016 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 controller

import (
	"github.com/golang/glog"
	"github.com/kubernetes-incubator/service-catalog/pkg/apis/servicecatalog"
	"github.com/kubernetes-incubator/service-catalog/pkg/brokerapi"
	"github.com/kubernetes-incubator/service-catalog/pkg/controller/apiclient"
	"github.com/kubernetes-incubator/service-catalog/pkg/controller/injector"
	"github.com/satori/go.uuid"
)

const (
	catalogURLFormatString      = "%s/v2/catalog"
	serviceInstanceFormatString = "%s/v2/service_instances/%s"
	bindingFormatString         = "%s/v2/service_instances/%s/service_bindings/%s"
	defaultNamespace            = "default"
)

// Handler defines an interface used as a facade for data access operations.
// The controller uses the functions of this interface as callbacks for various
// events.
type Handler interface {
	// CreateServiceInstance takes in a (possibly incomplete)
	// ServiceInstance and will either create or update an
	// existing one.
	CreateServiceInstance(*servicecatalog.Instance) (*servicecatalog.Instance, error)

	// CreateServiceBinding takes in a (possibly incomplete)
	// ServiceBinding and will either create or update an
	// existing one.
	CreateServiceBinding(*servicecatalog.Binding) (*servicecatalog.Binding, error)

	// CreateServiceBroker takes in a (possibly incomplete)
	// ServiceBroker and will either create or update an
	// existing one.
	CreateServiceBroker(*servicecatalog.Broker) (*servicecatalog.Broker, error)
}

type handler struct {
	apiClient     apiclient.APIClient
	injector      injector.BindingInjector
	newClientFunc func(*servicecatalog.Broker) brokerapi.BrokerClient
}

func createHandler(client apiclient.APIClient, injector injector.BindingInjector, newClientFn brokerapi.CreateFunc) *handler {
	return &handler{
		apiClient:     client,
		injector:      injector,
		newClientFunc: newClientFn,
	}
}

func (h *handler) updateServiceInstance(in *servicecatalog.Instance) error {
	// Currently there's no difference between create / update,
	// but for prepping for future, split these into two different
	// methods for now.
	return h.createServiceInstance(in)
}

func (h *handler) createServiceInstance(in *servicecatalog.Instance) error {
	broker, err := apiclient.GetBrokerByServiceClassName(h.apiClient.Brokers(), h.apiClient.ServiceClasses(), in.Spec.ServiceClassName)
	if err != nil {
		return err
	}
	client := h.newClientFunc(broker)

	// TODO: uncomment parameters line once parameters types are refactored.
	// Make the request to instantiate.
	createReq := &brokerapi.CreateServiceInstanceRequest{
		ServiceID: in.Spec.OSBServiceID,
		PlanID:    in.Spec.OSBPlanID,
		// Parameters: in.Spec.Parameters,
	}
	_, err = client.CreateServiceInstance(in.Spec.OSBGUID, createReq)
	return err
}

///////////////////////////////////////////////////////////////////////////////
// All the methods implementing the Handler interface go here for clarity sake.
///////////////////////////////////////////////////////////////////////////////
func (h *handler) CreateServiceInstance(in *servicecatalog.Instance) (*servicecatalog.Instance, error) {
	serviceID, planID, planName, err := apiclient.GetServicePlanInfo(
		h.apiClient.ServiceClasses(),
		in.Spec.ServiceClassName,
		in.Spec.PlanName,
	)
	if err != nil {
		glog.Errorf("Error fetching service ID: %v", err)
		return nil, err
	}
	in.Spec.OSBServiceID = serviceID
	in.Spec.OSBPlanID = planID
	in.Spec.PlanName = planName
	if in.Spec.OSBGUID == "" {
		in.Spec.OSBGUID = uuid.NewV4().String()
	}

	glog.Infof("Instantiating service %s using service/plan %s : %s", in.Name, serviceID, planID)

	err = h.createServiceInstance(in)
	in.Status = servicecatalog.InstanceStatus{}
	if err != nil {
		in.Status.Conditions = []servicecatalog.InstanceCondition{
			{
				Type:   servicecatalog.InstanceConditionProvisionFailed,
				Status: servicecatalog.ConditionTrue,
				Reason: err.Error(),
			},
		}
		glog.Errorf("Failed to create service instance: %v", err)
	} else {
		in.Status.Conditions = []servicecatalog.InstanceCondition{
			{
				Type:   servicecatalog.InstanceConditionReady,
				Status: servicecatalog.ConditionTrue,
			},
		}
	}

	glog.Infof("Updating Service %s with State\n%v", in.Name, in.Status.Conditions[0].Type)
	return h.apiClient.Instances(in.ObjectMeta.Namespace).Update(in)
}

func (h *handler) CreateServiceBinding(in *servicecatalog.Binding) (*servicecatalog.Binding, error) {
	glog.Infof("Creating Service Binding: %v", in)

	// Get instance information for service being bound to.
	instance, err := h.apiClient.Instances(in.Spec.InstanceRef.Namespace).Get(in.Spec.InstanceRef.Name)
	if err != nil {
		glog.Errorf("Service instance does not exist %v: %v", in.Spec.InstanceRef, err)
		return nil, err
	}

	// Get the serviceclass for the instance.
	sc, err := h.apiClient.ServiceClasses().Get(instance.Spec.ServiceClassName)
	if err != nil {
		glog.Errorf("Failed to fetch service type %s : %v", instance.Spec.ServiceClassName, err)
		return nil, err
	}

	// Get the broker for the serviceclass.
	broker, err := h.apiClient.Brokers().Get(sc.BrokerName)
	if err != nil {
		glog.Errorf("Error fetching broker for service: %s : %v", sc.BrokerName, err)
		return nil, err
	}
	client := h.newClientFunc(broker)

	// Assign UUID to binding.
	in.Spec.OSBGUID = uuid.NewV4().String()

	// TODO: uncomment parameters line once parameters types are refactored.
	// Make the request to bind.
	createReq := &brokerapi.BindingRequest{
		ServiceID: instance.Spec.OSBServiceID,
		PlanID:    instance.Spec.OSBPlanID,
		// Parameters: in.Spec.Parameters,
	}
	sbr, err := client.CreateServiceBinding(instance.Spec.OSBGUID, in.Spec.OSBGUID, createReq)

	in.Status = servicecatalog.BindingStatus{}
	if err != nil {
		in.Status.Conditions = []servicecatalog.BindingCondition{
			{
				Type:   servicecatalog.BindingConditionFailed,
				Status: servicecatalog.ConditionTrue,
				Reason: err.Error(),
			},
		}
		glog.Errorf("Failed to create service instance: %v", err)
	} else {
		// Now try injection
		err := h.injector.Inject(in, &sbr.Credentials)
		if err != nil {
			in.Status.Conditions = []servicecatalog.BindingCondition{
				{
					Type:   servicecatalog.BindingConditionFailed,
					Status: servicecatalog.ConditionTrue,
					Reason: err.Error(),
				},
			}
			glog.Errorf("Failed to create service instance: %v", err)
		} else {
			in.Status.Conditions = []servicecatalog.BindingCondition{
				{
					Type:   servicecatalog.BindingConditionReady,
					Status: servicecatalog.ConditionTrue,
				},
			}
		}
	}

	glog.Infof("Updating Service Binding %s with State\n%v", in.Name, in.Status.Conditions[0].Type)
	return h.apiClient.Bindings(in.ObjectMeta.Namespace).Update(in)
}

func (h *handler) CreateServiceBroker(in *servicecatalog.Broker) (*servicecatalog.Broker, error) {
	client := h.newClientFunc(in)
	sbcat, err := client.GetCatalog()
	if err != nil {
		return nil, err
	}
	catalog, err := convertCatalog(sbcat)
	if err != nil {
		return nil, err
	}

	glog.Infof("Adding a broker %s catalog:\n%v\n", in.Name, catalog)
	for _, sc := range catalog {
		sc.BrokerName = in.Name
		if _, err := h.apiClient.ServiceClasses().Create(sc); err != nil {
			return nil, err
		}
	}

	in.Status.Conditions = []servicecatalog.BrokerCondition{
		{
			Type:   servicecatalog.BrokerConditionReady,
			Status: servicecatalog.ConditionTrue,
		},
	}

	glog.Infof("Updating Service Broker %s with State\n%v", in.Name, in.Status.Conditions[0].Type)
	return h.apiClient.Brokers().Update(in)
}

// convertCatalog converts a service broker catalog into an array of ServiceClasses
func convertCatalog(in *brokerapi.Catalog) ([]*servicecatalog.ServiceClass, error) {
	ret := make([]*servicecatalog.ServiceClass, len(in.Services))
	for i, svc := range in.Services {
		plans := convertServicePlans(svc.Plans)
		ret[i] = &servicecatalog.ServiceClass{
			Bindable:      svc.Bindable,
			Plans:         plans,
			PlanUpdatable: svc.PlanUpdateable,
			OSBGUID:       svc.ID,
			OSBTags:       svc.Tags,
			OSBRequires:   svc.Requires,
			// OSBMetadata:   svc.Metadata,
		}
		ret[i].SetName(svc.Name)
	}
	return ret, nil
}

func convertServicePlans(plans []brokerapi.ServicePlan) []servicecatalog.ServicePlan {
	ret := make([]servicecatalog.ServicePlan, len(plans))
	for i, plan := range plans {
		ret[i] = servicecatalog.ServicePlan{
			Name:    plan.Name,
			OSBGUID: plan.ID,
			// OSBMetadata: plan.Metadata,
			OSBFree: plan.Free,
		}
	}
	return ret
}
<|endoftext|>


<commit_before>package daemon

import (
	"fmt"
	"syscall"
	"testing"
	"time"

	"src.elv.sh/pkg/daemon/client"
	"src.elv.sh/pkg/daemon/daemondefs"
	"src.elv.sh/pkg/daemon/internal/api"
	. "src.elv.sh/pkg/prog/progtest"
	"src.elv.sh/pkg/store/storetest"
	"src.elv.sh/pkg/testutil"
)

func TestProgram_TerminatesIfCannotListen(t *testing.T) {
	setup(t)
	testutil.MustCreateEmpty("sock")

	Test(t, Program,
		ThatElvish("-daemon", "-sock", "sock", "-db", "db").
			ExitsWith(2).
			WritesStdoutContaining("failed to listen on sock"),
	)
}

func TestProgram_ServesClientRequests(t *testing.T) {
	setup(t)
	client := startServerClientPair(t)

	// Test server state requests.
	gotVersion, err := client.Version()
	if gotVersion != api.Version || err != nil {
		t.Errorf(".Version() -> (%v, %v), want (%v, nil)", gotVersion, err, api.Version)
	}

	gotPid, err := client.Pid()
	wantPid := syscall.Getpid()
	if gotPid != wantPid || err != nil {
		t.Errorf(".Pid() -> (%v, %v), want (%v, nil)", gotPid, err, wantPid)
	}

	// Test store requests.
	storetest.TestCmd(t, client)
	storetest.TestDir(t, client)
	storetest.TestSharedVar(t, client)
}

func TestProgram_StillServesIfCannotOpenDB(t *testing.T) {
	setup(t)
	testutil.MustWriteFile("db", "not a valid bolt database")
	client := startServerClientPair(t)

	_, err := client.AddCmd("cmd")
	if err == nil {
		t.Errorf("got nil error, want non-nil")
	}
}

func TestProgram_BadCLI(t *testing.T) {
	Test(t, Program,
		ThatElvish().
			ExitsWith(2).
			WritesStderr("internal error: no suitable subprogram\n"),

		ThatElvish("-daemon", "x").
			ExitsWith(2).
			WritesStderrContaining("arguments are not allowed with -daemon"),
	)
}

func setup(t *testing.T) {
	testutil.Umask(t, 0)
	testutil.InTempDir(t)
}

func startServerClientPair(t *testing.T) daemondefs.Client {
	go startServer(t)
	client, err := startClient(t)
	if err != nil {
		t.Fatal(err)
	}
	return client
}

func startServer(t *testing.T) {
	exit, stdout, stderr := Run(Program, "elvish", "-daemon", "-sock", "sock", "-db", "db")
	if exit != 0 {
		fmt.Println("daemon exited with", exit)
		fmt.Print("stdout:\n", stdout)
		fmt.Print("stderr:\n", stderr)
	}
}

func startClient(t *testing.T) (daemondefs.Client, error) {
	client := client.NewClient("sock")
	t.Cleanup(func() { client.Close() })
	for i := 0; i < 100; i++ {
		client.ResetConn()
		_, err := client.Version()
		if err == nil {
			return client, nil
		}
		if i < 99 {
			time.Sleep(testutil.ScaledMs(10))
		}
	}
	return nil, fmt.Errorf("Failed to connect after %v", testutil.ScaledMs(1000))
}
<commit_msg>pkg/daemon/daemon_test.go: Return more detailed error from startClient.<commit_after>package daemon

import (
	"fmt"
	"syscall"
	"testing"
	"time"

	"src.elv.sh/pkg/daemon/client"
	"src.elv.sh/pkg/daemon/daemondefs"
	"src.elv.sh/pkg/daemon/internal/api"
	. "src.elv.sh/pkg/prog/progtest"
	"src.elv.sh/pkg/store/storetest"
	"src.elv.sh/pkg/testutil"
)

func TestProgram_TerminatesIfCannotListen(t *testing.T) {
	setup(t)
	testutil.MustCreateEmpty("sock")

	Test(t, Program,
		ThatElvish("-daemon", "-sock", "sock", "-db", "db").
			ExitsWith(2).
			WritesStdoutContaining("failed to listen on sock"),
	)
}

func TestProgram_ServesClientRequests(t *testing.T) {
	setup(t)
	client := startServerClientPair(t)

	// Test server state requests.
	gotVersion, err := client.Version()
	if gotVersion != api.Version || err != nil {
		t.Errorf(".Version() -> (%v, %v), want (%v, nil)", gotVersion, err, api.Version)
	}

	gotPid, err := client.Pid()
	wantPid := syscall.Getpid()
	if gotPid != wantPid || err != nil {
		t.Errorf(".Pid() -> (%v, %v), want (%v, nil)", gotPid, err, wantPid)
	}

	// Test store requests.
	storetest.TestCmd(t, client)
	storetest.TestDir(t, client)
	storetest.TestSharedVar(t, client)
}

func TestProgram_StillServesIfCannotOpenDB(t *testing.T) {
	setup(t)
	testutil.MustWriteFile("db", "not a valid bolt database")
	client := startServerClientPair(t)

	_, err := client.AddCmd("cmd")
	if err == nil {
		t.Errorf("got nil error, want non-nil")
	}
}

func TestProgram_BadCLI(t *testing.T) {
	Test(t, Program,
		ThatElvish().
			ExitsWith(2).
			WritesStderr("internal error: no suitable subprogram\n"),

		ThatElvish("-daemon", "x").
			ExitsWith(2).
			WritesStderrContaining("arguments are not allowed with -daemon"),
	)
}

func setup(t *testing.T) {
	testutil.Umask(t, 0)
	testutil.InTempDir(t)
}

func startServerClientPair(t *testing.T) daemondefs.Client {
	go startServer(t)
	client, err := startClient(t)
	if err != nil {
		t.Fatal(err)
	}
	return client
}

func startServer(t *testing.T) {
	exit, stdout, stderr := Run(Program, "elvish", "-daemon", "-sock", "sock", "-db", "db")
	if exit != 0 {
		fmt.Println("daemon exited with", exit)
		fmt.Print("stdout:\n", stdout)
		fmt.Print("stderr:\n", stderr)
	}
}

func startClient(t *testing.T) (daemondefs.Client, error) {
	client := client.NewClient("sock")
	t.Cleanup(func() { client.Close() })
	start := time.Now()
	timeout := testutil.ScaledMs(1000)
	for {
		client.ResetConn()
		_, err := client.Version()
		if err == nil {
			return client, nil
		}
		if time.Since(start) > timeout {
			return nil, fmt.Errorf("Failed to connect after %v: %v", timeout, err)
		}
		time.Sleep(testutil.ScaledMs(10))
	}
}
<|endoftext|>


<commit_before>package jobs

import (
	"context"
	"strconv"
	"strings"
	"sync"
	"testing"
	"time"

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

func TestProperSerial(t *testing.T) {
	infos := NewJobInfos(&JobRequest{
		Domain:     "cozy.tools:8080",
		WorkerType: "",
	})
	storage := newCouchStorage(infos.Domain)
	j := &Job{
		infos:   infos,
		storage: storage,
	}
	storage.Create(infos)
	err := j.AckConsumed()
	assert.NoError(t, err)
	j2, err := storage.Get(j.infos.ID())
	assert.NoError(t, err)
	assert.Equal(t, State(Running), j2.State)
}

func TestInMemoryJobs(t *testing.T) {
	n := 10
	v := 100

	var w sync.WaitGroup

	var workersTestList = WorkersList{
		"test": {
			Concurrency: 4,
			WorkerFunc: func(ctx context.Context, m *Message) error {
				var msg string
				err := m.Unmarshal(&msg)
				if !assert.NoError(t, err) {
					return err
				}
				if strings.HasPrefix(msg, "a-") {
					_, err := strconv.Atoi(msg[len("a-"):])
					assert.NoError(t, err)
				} else if strings.HasPrefix(msg, "b-") {
					_, err := strconv.Atoi(msg[len("b-"):])
					assert.NoError(t, err)
				} else {
					t.Fatal()
				}
				w.Done()
				return nil
			},
		},
	}

	broker1 := NewMemBroker(4)
	broker2 := NewMemBroker(4)
	broker1.Start(workersTestList)
	broker2.Start(workersTestList)
	w.Add(2)

	go func() {
		for i := 0; i < n; i++ {
			w.Add(1)
			msg, _ := NewMessage(JSONEncoding, "a-"+strconv.Itoa(i+1))
			_, err := broker1.PushJob(&JobRequest{
				Domain:     "cozy.local",
				WorkerType: "test",
				Message:    msg,
			})
			assert.NoError(t, err)
			time.Sleep(randomMicro(0, v))
		}
		w.Done()
	}()

	go func() {
		for i := 0; i < n; i++ {
			w.Add(1)
			msg, _ := NewMessage(JSONEncoding, "b-"+strconv.Itoa(i+1))
			_, err := broker2.PushJob(&JobRequest{
				Domain:     "cozy.local",
				WorkerType: "test",
				Message:    msg,
			})
			assert.NoError(t, err)
			time.Sleep(randomMicro(0, v))
		}
		w.Done()
	}()

	w.Wait()
}

func TestUnknownWorkerError(t *testing.T) {
	broker := NewMemBroker(1)
	broker.Start(WorkersList{})
	_, err := broker.PushJob(&JobRequest{
		Domain:     "cozy.local",
		WorkerType: "nope",
		Message:    nil,
	})
	assert.Error(t, err)
	assert.Equal(t, ErrUnknownWorker, err)
}

func TestUnknownMessageType(t *testing.T) {
	var w sync.WaitGroup

	broker := NewMemBroker(4)
	broker.Start(WorkersList{
		"test": {
			Concurrency: 4,
			WorkerFunc: func(ctx context.Context, m *Message) error {
				var msg string
				err := m.Unmarshal(&msg)
				assert.Error(t, err)
				assert.Equal(t, ErrUnknownMessageType, err)
				w.Done()
				return nil
			},
		},
	})

	w.Add(1)
	_, err := broker.PushJob(&JobRequest{
		WorkerType: "test",
		Domain:     "cozy.local",
		Message: &Message{
			Type: "unknown",
			Data: nil,
		},
	})

	assert.NoError(t, err)
	w.Wait()
}

func TestTimeout(t *testing.T) {
	var w sync.WaitGroup

	broker := NewMemBroker(1)
	broker.Start(WorkersList{
		"timeout": {
			Concurrency:  1,
			MaxExecCount: 1,
			Timeout:      1 * time.Millisecond,
			WorkerFunc: func(ctx context.Context, _ *Message) error {
				<-ctx.Done()
				w.Done()
				return ctx.Err()
			},
		},
	})

	w.Add(1)
	_, err := broker.PushJob(&JobRequest{
		WorkerType: "timeout",
		Domain:     "cozy.local",
		Message: &Message{
			Type: "timeout",
			Data: nil,
		},
	})

	assert.NoError(t, err)
	w.Wait()
}

func TestRetry(t *testing.T) {
	var w sync.WaitGroup

	maxExecCount := 4

	var count int
	broker := NewMemBroker(1)
	broker.Start(WorkersList{
		"test": {
			Concurrency:  1,
			MaxExecCount: maxExecCount,
			Timeout:      1 * time.Millisecond,
			RetryDelay:   1 * time.Millisecond,
			WorkerFunc: func(ctx context.Context, _ *Message) error {
				<-ctx.Done()
				w.Done()
				count++
				if count < maxExecCount {
					return ctx.Err()
				}
				return nil
			},
		},
	})

	w.Add(maxExecCount)
	_, err := broker.PushJob(&JobRequest{
		Domain:     "cozy.local",
		WorkerType: "test",
		Message:    nil,
	})

	assert.NoError(t, err)
	w.Wait()
}

func TestPanicRetried(t *testing.T) {
	var w sync.WaitGroup

	maxExecCount := 4

	broker := NewMemBroker(1)
	broker.Start(WorkersList{
		"panic": {
			Concurrency:  1,
			MaxExecCount: maxExecCount,
			RetryDelay:   1 * time.Millisecond,
			WorkerFunc: func(ctx context.Context, _ *Message) error {
				w.Done()
				panic("oops")
			},
		},
	})

	w.Add(maxExecCount)
	_, err := broker.PushJob(&JobRequest{
		Domain:     "cozy.local",
		WorkerType: "panic",
		Message:    nil,
	})

	assert.NoError(t, err)
	w.Wait()
}

func TestPanic(t *testing.T) {
	var w sync.WaitGroup

	even, _ := NewMessage("json", 0)
	odd, _ := NewMessage("json", 1)

	broker := NewMemBroker(1)
	broker.Start(WorkersList{
		"panic2": {
			Concurrency:  1,
			MaxExecCount: 1,
			RetryDelay:   1 * time.Millisecond,
			WorkerFunc: func(ctx context.Context, m *Message) error {
				var i int
				if err := m.Unmarshal(&i); err != nil {
					return err
				}
				if i%2 != 0 {
					panic("oops")
				}
				w.Done()
				return nil
			},
		},
	})
	w.Add(2)
	var err error
	_, err = broker.PushJob(&JobRequest{Domain: "cozy.local", WorkerType: "panic2", Message: odd})
	assert.NoError(t, err)
	_, err = broker.PushJob(&JobRequest{Domain: "cozy.local", WorkerType: "panic2", Message: even})
	assert.NoError(t, err)
	_, err = broker.PushJob(&JobRequest{Domain: "cozy.local", WorkerType: "panic2", Message: odd})
	assert.NoError(t, err)
	_, err = broker.PushJob(&JobRequest{Domain: "cozy.local", WorkerType: "panic2", Message: even})
	assert.NoError(t, err)
	w.Wait()
}
<commit_msg>Add logs to debug tests in travis<commit_after>package jobs

import (
	"context"
	"fmt"
	"strconv"
	"strings"
	"sync"
	"testing"
	"time"

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

func TestProperSerial(t *testing.T) {
	infos := NewJobInfos(&JobRequest{
		Domain:     "cozy.tools:8080",
		WorkerType: "",
	})
	storage := newCouchStorage(infos.Domain)
	j := &Job{
		infos:   infos,
		storage: storage,
	}
	storage.Create(infos)
	err := j.AckConsumed()
	assert.NoError(t, err)
	j2, err := storage.Get(j.infos.ID())
	assert.NoError(t, err)
	assert.Equal(t, State(Running), j2.State)
}

func TestInMemoryJobs(t *testing.T) {
	n := 10
	v := 100

	var w sync.WaitGroup

	var workersTestList = WorkersList{
		"test": {
			Concurrency: 4,
			WorkerFunc: func(ctx context.Context, m *Message) error {
				var msg string
				err := m.Unmarshal(&msg)
				if !assert.NoError(t, err) {
					return err
				}
				fmt.Println(">>> worker msg=", msg)
				if strings.HasPrefix(msg, "a-") {
					_, err := strconv.Atoi(msg[len("a-"):])
					assert.NoError(t, err)
				} else if strings.HasPrefix(msg, "b-") {
					_, err := strconv.Atoi(msg[len("b-"):])
					assert.NoError(t, err)
				} else {
					t.Fatal()
				}
				w.Done()
				return nil
			},
		},
	}

	broker1 := NewMemBroker(4)
	broker2 := NewMemBroker(4)
	broker1.Start(workersTestList)
	broker2.Start(workersTestList)
	w.Add(2)

	go func() {
		for i := 0; i < n; i++ {
			w.Add(1)
			msg, _ := NewMessage(JSONEncoding, "a-"+strconv.Itoa(i+1))
			_, err := broker1.PushJob(&JobRequest{
				Domain:     "cozy.local",
				WorkerType: "test",
				Message:    msg,
			})
			fmt.Println(">> send 1=", string(msg.Data), err)
			assert.NoError(t, err)
			time.Sleep(randomMicro(0, v))
		}
		fmt.Println(">> send done 1")
		w.Done()
	}()

	go func() {
		for i := 0; i < n; i++ {
			w.Add(1)
			msg, _ := NewMessage(JSONEncoding, "b-"+strconv.Itoa(i+1))
			_, err := broker2.PushJob(&JobRequest{
				Domain:     "cozy.local",
				WorkerType: "test",
				Message:    msg,
			})
			fmt.Println(">> send 2=", string(msg.Data), err)
			assert.NoError(t, err)
			time.Sleep(randomMicro(0, v))
		}
		fmt.Println(">> send done 2")
		w.Done()
	}()

	w.Wait()
}

func TestUnknownWorkerError(t *testing.T) {
	broker := NewMemBroker(1)
	broker.Start(WorkersList{})
	_, err := broker.PushJob(&JobRequest{
		Domain:     "cozy.local",
		WorkerType: "nope",
		Message:    nil,
	})
	assert.Error(t, err)
	assert.Equal(t, ErrUnknownWorker, err)
}

func TestUnknownMessageType(t *testing.T) {
	var w sync.WaitGroup

	broker := NewMemBroker(4)
	broker.Start(WorkersList{
		"test": {
			Concurrency: 4,
			WorkerFunc: func(ctx context.Context, m *Message) error {
				var msg string
				err := m.Unmarshal(&msg)
				assert.Error(t, err)
				assert.Equal(t, ErrUnknownMessageType, err)
				w.Done()
				return nil
			},
		},
	})

	w.Add(1)
	_, err := broker.PushJob(&JobRequest{
		WorkerType: "test",
		Domain:     "cozy.local",
		Message: &Message{
			Type: "unknown",
			Data: nil,
		},
	})

	assert.NoError(t, err)
	w.Wait()
}

func TestTimeout(t *testing.T) {
	var w sync.WaitGroup

	broker := NewMemBroker(1)
	broker.Start(WorkersList{
		"timeout": {
			Concurrency:  1,
			MaxExecCount: 1,
			Timeout:      1 * time.Millisecond,
			WorkerFunc: func(ctx context.Context, _ *Message) error {
				<-ctx.Done()
				w.Done()
				return ctx.Err()
			},
		},
	})

	w.Add(1)
	_, err := broker.PushJob(&JobRequest{
		WorkerType: "timeout",
		Domain:     "cozy.local",
		Message: &Message{
			Type: "timeout",
			Data: nil,
		},
	})

	assert.NoError(t, err)
	w.Wait()
}

func TestRetry(t *testing.T) {
	var w sync.WaitGroup

	maxExecCount := 4

	var count int
	broker := NewMemBroker(1)
	broker.Start(WorkersList{
		"test": {
			Concurrency:  1,
			MaxExecCount: maxExecCount,
			Timeout:      1 * time.Millisecond,
			RetryDelay:   1 * time.Millisecond,
			WorkerFunc: func(ctx context.Context, _ *Message) error {
				<-ctx.Done()
				w.Done()
				count++
				if count < maxExecCount {
					return ctx.Err()
				}
				return nil
			},
		},
	})

	w.Add(maxExecCount)
	_, err := broker.PushJob(&JobRequest{
		Domain:     "cozy.local",
		WorkerType: "test",
		Message:    nil,
	})

	assert.NoError(t, err)
	w.Wait()
}

func TestPanicRetried(t *testing.T) {
	var w sync.WaitGroup

	maxExecCount := 4

	broker := NewMemBroker(1)
	broker.Start(WorkersList{
		"panic": {
			Concurrency:  1,
			MaxExecCount: maxExecCount,
			RetryDelay:   1 * time.Millisecond,
			WorkerFunc: func(ctx context.Context, _ *Message) error {
				w.Done()
				panic("oops")
			},
		},
	})

	w.Add(maxExecCount)
	_, err := broker.PushJob(&JobRequest{
		Domain:     "cozy.local",
		WorkerType: "panic",
		Message:    nil,
	})

	assert.NoError(t, err)
	w.Wait()
}

func TestPanic(t *testing.T) {
	var w sync.WaitGroup

	even, _ := NewMessage("json", 0)
	odd, _ := NewMessage("json", 1)

	broker := NewMemBroker(1)
	broker.Start(WorkersList{
		"panic2": {
			Concurrency:  1,
			MaxExecCount: 1,
			RetryDelay:   1 * time.Millisecond,
			WorkerFunc: func(ctx context.Context, m *Message) error {
				var i int
				if err := m.Unmarshal(&i); err != nil {
					return err
				}
				if i%2 != 0 {
					panic("oops")
				}
				w.Done()
				return nil
			},
		},
	})
	w.Add(2)
	var err error
	_, err = broker.PushJob(&JobRequest{Domain: "cozy.local", WorkerType: "panic2", Message: odd})
	assert.NoError(t, err)
	_, err = broker.PushJob(&JobRequest{Domain: "cozy.local", WorkerType: "panic2", Message: even})
	assert.NoError(t, err)
	_, err = broker.PushJob(&JobRequest{Domain: "cozy.local", WorkerType: "panic2", Message: odd})
	assert.NoError(t, err)
	_, err = broker.PushJob(&JobRequest{Domain: "cozy.local", WorkerType: "panic2", Message: even})
	assert.NoError(t, err)
	w.Wait()
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Skaffold 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 sync

import (
	"context"
	"fmt"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/watch"
	"github.com/bmatcuk/doublestar"
	registry_v1 "github.com/google/go-containerregistry/pkg/v1"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	v1 "k8s.io/api/core/v1"
	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var (
	// WorkingDir is here for testing
	WorkingDir = retrieveWorkingDir
)

type Syncer interface {
	Sync(context.Context, *Item) error
}

type Item struct {
	Image  string
	Copy   map[string]string
	Delete map[string]string
}

func NewItem(a *latest.Artifact, e watch.Events, builds []build.Artifact, insecureRegistries map[string]bool) (*Item, error) {
	// If there are no changes, short circuit and don't sync anything
	if !e.HasChanged() || len(a.Sync) == 0 {
		return nil, nil
	}

	tag := latestTag(a.ImageName, builds)
	if tag == "" {
		return nil, fmt.Errorf("could not find latest tag for image %s in builds: %v", a.ImageName, builds)
	}

	wd, err := WorkingDir(tag, insecureRegistries)
	if err != nil {
		return nil, errors.Wrapf(err, "retrieving working dir for %s", tag)
	}

	toCopy, err := intersect(a.Workspace, a.Sync, append(e.Added, e.Modified...), wd)
	if err != nil {
		return nil, errors.Wrap(err, "intersecting sync map and added, modified files")
	}

	toDelete, err := intersect(a.Workspace, a.Sync, e.Deleted, wd)
	if err != nil {
		return nil, errors.Wrap(err, "intersecting sync map and deleted files")
	}

	// Something went wrong, don't sync, rebuild.
	if toCopy == nil || toDelete == nil {
		return nil, nil
	}

	return &Item{
		Image:  tag,
		Copy:   toCopy,
		Delete: toDelete,
	}, nil
}

func retrieveWorkingDir(tagged string, insecureRegistries map[string]bool) (string, error) {
	var cf *registry_v1.ConfigFile
	var err error

	localDocker, err := docker.NewAPIClient(false, insecureRegistries)
	if err != nil {
		// No local Docker is available
		cf, err = docker.RetrieveRemoteConfig(tagged, insecureRegistries)
	} else {
		cf, err = localDocker.ConfigFile(context.Background(), tagged)
	}
	if err != nil {
		return "", errors.Wrap(err, "retrieving image config")
	}

	if cf.Config.WorkingDir == "" {
		return "/", nil
	}
	return cf.Config.WorkingDir, nil
}

func latestTag(image string, builds []build.Artifact) string {
	for _, build := range builds {
		if build.ImageName == image {
			return build.Tag
		}
	}
	return ""
}

// Note that we always use Unix-style paths in our destination.
func slashJoin(pfx, sfx string) string {
	if pfx == "." || pfx == "" {
		return sfx
	}
	elems := []string{
		strings.TrimSuffix(pfx, "/"),
		sfx,
	}
	return strings.Join(elems, "/")
}

func intersect(context string, syncMap map[string]string, files []string, workingDir string) (map[string]string, error) {
	ret := map[string]string{}

	tripleStarSyncMap, otherSyncMap := segregateSyncMaps(syncMap)
	for _, f := range files {
		relPath, err := filepath.Rel(context, f)
		if err != nil {
			return nil, errors.Wrapf(err, "changed file %s can't be found relative to context %s", f, context)
		}

		var match bool

		// First try all tripleStarSyncMaps.
		match, dst, err := matchTripleStarSyncMap(tripleStarSyncMap, relPath)
		if err != nil {
			return nil, err
		}

		if !match {
			// Try matching the other rules.
			match, dst, err = matchOtherSyncMap(otherSyncMap, relPath)
			if err != nil {
				return nil, err
			}
		}

		if !match {
			logrus.Infof("Changed file %s does not match any sync pattern. Skipping sync", relPath)
			return nil, nil
		}

		// Convert relative destinations to absolute via the workingDir.
		if dst[0] != '/' {
			dst = slashJoin(workingDir, dst)
		}

		// Record the final destination.
		ret[f] = dst
	}

	return ret, nil
}

func segregateSyncMaps(syncMap map[string]string) (tripleStarPattern, doubleStarPattern map[string]string) {
	tripleStarPattern = make(map[string]string)
	doubleStarPattern = make(map[string]string)
	for p, dst := range syncMap {
		if strings.Contains(p, "***") {
			tripleStarPattern[p] = dst
		} else {
			doubleStarPattern[p] = dst
		}
	}
	return
}

func matchTripleStarSyncMap(syncMap map[string]string, relPath string) (bool, string, error) {
	for p, dst := range syncMap {
		pat := strings.Replace(p, "***", "**", -1)
		match, err := doublestar.PathMatch(filepath.FromSlash(pat), relPath)
		if err != nil {
			return false, "", errors.Wrapf(err, "pattern error for %s", relPath)
		}

		if match {
			// Map the paths as a tree from the prefix.
			subtreePrefix := strings.Split(p, "***")[0]
			subPath := strings.TrimPrefix(filepath.ToSlash(relPath), subtreePrefix)
			return true, slashJoin(dst, subPath), nil
		}
	}
	return false, "", nil
}

func matchOtherSyncMap(syncMap map[string]string, relPath string) (bool, string, error) {
	for p, dst := range syncMap {
		match, err := doublestar.PathMatch(filepath.FromSlash(p), relPath)
		if err != nil {
			return false, "", errors.Wrapf(err, "pattern error for %s", relPath)
		}

		if match {
			// Collapse the paths.
			subPath := filepath.Base(relPath)
			return true, slashJoin(dst, filepath.ToSlash(subPath)), nil
		}
	}
	return false, "", nil
}

func Perform(ctx context.Context, image string, files map[string]string, cmdFn func(context.Context, v1.Pod, v1.Container, map[string]string) []*exec.Cmd, namespaces []string) error {
	if len(files) == 0 {
		return nil
	}

	client, err := kubernetes.Client()
	if err != nil {
		return errors.Wrap(err, "getting k8s client")
	}

	numSynced := 0
	for _, ns := range namespaces {
		pods, err := client.CoreV1().Pods(ns).List(meta_v1.ListOptions{})
		if err != nil {
			return errors.Wrap(err, "getting pods for namespace "+ns)
		}

		for _, p := range pods.Items {
			for _, c := range p.Spec.Containers {
				if c.Image != image {
					continue
				}

				cmds := cmdFn(ctx, p, c, files)
				for _, cmd := range cmds {
					buf := &bytes.Buffer{}
					cmd.Stdout = buf
					cmd.Stderr = buf
					if err := util.RunCmd(cmd); err != nil {
						logrus.Warnf("Sync failed: %s", buf.String())
						return err
					}
					numSynced++
				}
			}
		}
	}

	if numSynced == 0 {
		return errors.New("didn't sync any files")
	}

	return nil
}
<commit_msg>Changing to handle both deletefile and copyfile command<commit_after>/*
Copyright 2019 The Skaffold 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 sync

import (
	"bytes"
	"context"
	"fmt"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/watch"
	"github.com/bmatcuk/doublestar"
	registry_v1 "github.com/google/go-containerregistry/pkg/v1"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	v1 "k8s.io/api/core/v1"
	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var (
	// WorkingDir is here for testing
	WorkingDir = retrieveWorkingDir
)

type Syncer interface {
	Sync(context.Context, *Item) error
}

type Item struct {
	Image  string
	Copy   map[string]string
	Delete map[string]string
}

func NewItem(a *latest.Artifact, e watch.Events, builds []build.Artifact, insecureRegistries map[string]bool) (*Item, error) {
	// If there are no changes, short circuit and don't sync anything
	if !e.HasChanged() || len(a.Sync) == 0 {
		return nil, nil
	}

	tag := latestTag(a.ImageName, builds)
	if tag == "" {
		return nil, fmt.Errorf("could not find latest tag for image %s in builds: %v", a.ImageName, builds)
	}

	wd, err := WorkingDir(tag, insecureRegistries)
	if err != nil {
		return nil, errors.Wrapf(err, "retrieving working dir for %s", tag)
	}

	toCopy, err := intersect(a.Workspace, a.Sync, append(e.Added, e.Modified...), wd)
	if err != nil {
		return nil, errors.Wrap(err, "intersecting sync map and added, modified files")
	}

	toDelete, err := intersect(a.Workspace, a.Sync, e.Deleted, wd)
	if err != nil {
		return nil, errors.Wrap(err, "intersecting sync map and deleted files")
	}

	// Something went wrong, don't sync, rebuild.
	if toCopy == nil || toDelete == nil {
		return nil, nil
	}

	return &Item{
		Image:  tag,
		Copy:   toCopy,
		Delete: toDelete,
	}, nil
}

func retrieveWorkingDir(tagged string, insecureRegistries map[string]bool) (string, error) {
	var cf *registry_v1.ConfigFile
	var err error

	localDocker, err := docker.NewAPIClient(false, insecureRegistries)
	if err != nil {
		// No local Docker is available
		cf, err = docker.RetrieveRemoteConfig(tagged, insecureRegistries)
	} else {
		cf, err = localDocker.ConfigFile(context.Background(), tagged)
	}
	if err != nil {
		return "", errors.Wrap(err, "retrieving image config")
	}

	if cf.Config.WorkingDir == "" {
		return "/", nil
	}
	return cf.Config.WorkingDir, nil
}

func latestTag(image string, builds []build.Artifact) string {
	for _, build := range builds {
		if build.ImageName == image {
			return build.Tag
		}
	}
	return ""
}

// Note that we always use Unix-style paths in our destination.
func slashJoin(pfx, sfx string) string {
	if pfx == "." || pfx == "" {
		return sfx
	}
	elems := []string{
		strings.TrimSuffix(pfx, "/"),
		sfx,
	}
	return strings.Join(elems, "/")
}

func intersect(context string, syncMap map[string]string, files []string, workingDir string) (map[string]string, error) {
	ret := map[string]string{}

	tripleStarSyncMap, otherSyncMap := segregateSyncMaps(syncMap)
	for _, f := range files {
		relPath, err := filepath.Rel(context, f)
		if err != nil {
			return nil, errors.Wrapf(err, "changed file %s can't be found relative to context %s", f, context)
		}

		var match bool

		// First try all tripleStarSyncMaps.
		match, dst, err := matchTripleStarSyncMap(tripleStarSyncMap, relPath)
		if err != nil {
			return nil, err
		}

		if !match {
			// Try matching the other rules.
			match, dst, err = matchOtherSyncMap(otherSyncMap, relPath)
			if err != nil {
				return nil, err
			}
		}

		if !match {
			logrus.Infof("Changed file %s does not match any sync pattern. Skipping sync", relPath)
			return nil, nil
		}

		// Convert relative destinations to absolute via the workingDir.
		if dst[0] != '/' {
			dst = slashJoin(workingDir, dst)
		}

		// Record the final destination.
		ret[f] = dst
	}

	return ret, nil
}

func segregateSyncMaps(syncMap map[string]string) (tripleStarPattern, doubleStarPattern map[string]string) {
	tripleStarPattern = make(map[string]string)
	doubleStarPattern = make(map[string]string)
	for p, dst := range syncMap {
		if strings.Contains(p, "***") {
			tripleStarPattern[p] = dst
		} else {
			doubleStarPattern[p] = dst
		}
	}
	return
}

func matchTripleStarSyncMap(syncMap map[string]string, relPath string) (bool, string, error) {
	for p, dst := range syncMap {
		pat := strings.Replace(p, "***", "**", -1)
		match, err := doublestar.PathMatch(filepath.FromSlash(pat), relPath)
		if err != nil {
			return false, "", errors.Wrapf(err, "pattern error for %s", relPath)
		}

		if match {
			// Map the paths as a tree from the prefix.
			subtreePrefix := strings.Split(p, "***")[0]
			subPath := strings.TrimPrefix(filepath.ToSlash(relPath), subtreePrefix)
			return true, slashJoin(dst, subPath), nil
		}
	}
	return false, "", nil
}

func matchOtherSyncMap(syncMap map[string]string, relPath string) (bool, string, error) {
	for p, dst := range syncMap {
		match, err := doublestar.PathMatch(filepath.FromSlash(p), relPath)
		if err != nil {
			return false, "", errors.Wrapf(err, "pattern error for %s", relPath)
		}

		if match {
			// Collapse the paths.
			subPath := filepath.Base(relPath)
			return true, slashJoin(dst, filepath.ToSlash(subPath)), nil
		}
	}
	return false, "", nil
}

func Perform(ctx context.Context, image string, files map[string]string, cmdFn func(context.Context, v1.Pod, v1.Container, map[string]string) []*exec.Cmd, namespaces []string) error {
	if len(files) == 0 {
		return nil
	}

	client, err := kubernetes.Client()
	if err != nil {
		return errors.Wrap(err, "getting k8s client")
	}

	numSynced := 0
	for _, ns := range namespaces {
		pods, err := client.CoreV1().Pods(ns).List(meta_v1.ListOptions{})
		if err != nil {
			return errors.Wrap(err, "getting pods for namespace "+ns)
		}

		for _, p := range pods.Items {
			for _, c := range p.Spec.Containers {
				if c.Image != image {
					continue
				}

				cmds := cmdFn(ctx, p, c, files)
				for _, cmd := range cmds {
					buf := &bytes.Buffer{}
					cmd.Stdout = buf
					cmd.Stderr = buf
					if err := util.RunCmd(cmd); err != nil {
						logrus.Warnf("Sync failed: %s", buf.String())
						return err
					}
					numSynced++
				}
			}
		}
	}

	if numSynced == 0 {
		return errors.New("didn't sync any files")
	}

	return nil
}
<|endoftext|>


<commit_before>/*
 * Copyright 2019, EnMasse authors.
 * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
 */

package install

import (
	"github.com/enmasseproject/enmasse/pkg/apis/enmasse/v1beta1"
	"github.com/enmasseproject/enmasse/pkg/util/images"

	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
)

func CreateDefaultLabels(labels map[string]string, component string, name string) map[string]string {

	if labels == nil {
		labels = make(map[string]string)
	}

	labels["component"] = component
	labels["app"] = "enmasse"
	labels["name"] = name

	return labels
}

// Apply standard set of labels
func ApplyDefaultLabels(meta *v1.ObjectMeta, component string, name string) {
	meta.Labels = CreateDefaultLabels(meta.Labels, component, name)
}

// Apply some default service values
func ApplyServiceDefaults(service *corev1.Service, component string, name string) {

	ApplyDefaultLabels(&service.ObjectMeta, component, name)
	if service.CreationTimestamp.IsZero() {
		service.Spec.Selector = CreateDefaultLabels(nil, component, name)
	}

}

// Apply some default deployment values
func ApplyDeploymentDefaults(deployment *appsv1.Deployment, component string, name string) {

	ApplyDefaultLabels(&deployment.ObjectMeta, component, name)

	if deployment.CreationTimestamp.IsZero() {
		deployment.Spec.Selector = &v1.LabelSelector{
			MatchLabels: CreateDefaultLabels(nil, component, name),
		}
	}

	deployment.Spec.Template.ObjectMeta.Labels = CreateDefaultLabels(deployment.Spec.Template.ObjectMeta.Labels, component, name)

}

func ApplyContainer(deployment *appsv1.Deployment, name string, mutator func(*corev1.Container)) {
	// call "with error", and eat up the error
	_ = ApplyContainerWithError(deployment, name, func(container *corev1.Container) error {
		mutator(container)
		return nil
	})
}

func ApplyContainerWithError(deployment *appsv1.Deployment, name string, mutator func(*corev1.Container) error) error {

	if deployment.Spec.Template.Spec.Containers == nil {
		deployment.Spec.Template.Spec.Containers = make([]corev1.Container, 0)
	}

	for i, c := range deployment.Spec.Template.Spec.Containers {
		if c.Name == name {
			return mutator(&deployment.Spec.Template.Spec.Containers[i])
		}
	}

	c := &corev1.Container{
		Name: name,
	}

	err := mutator(c)
	if err == nil {
		deployment.Spec.Template.Spec.Containers = append(deployment.Spec.Template.Spec.Containers, *c)
	}

	return err
}

func ApplyInitContainer(deployment *appsv1.Deployment, name string, mutator func(*corev1.Container)) {
	// call "with error", and eat up the error
	_ = ApplyInitContainerWithError(deployment, name, func(container *corev1.Container) error {
		mutator(container)
		return nil
	})
}

func ApplyInitContainerWithError(deployment *appsv1.Deployment, name string, mutator func(*corev1.Container) error) error {

	if deployment.Spec.Template.Spec.InitContainers == nil {
		deployment.Spec.Template.Spec.InitContainers = make([]corev1.Container, 0)
	}

	for i, c := range deployment.Spec.Template.Spec.InitContainers {
		if c.Name == name {
			return mutator(&deployment.Spec.Template.Spec.InitContainers[i])
		}
	}

	c := &corev1.Container{
		Name: name,
	}

	err := mutator(c)
	if err == nil {
		deployment.Spec.Template.Spec.InitContainers = append(deployment.Spec.Template.Spec.InitContainers, *c)
	}

	return err
}

func ApplyPersistentVolume(deployment *appsv1.Deployment, name string, claimName string) {
	ApplyVolume(deployment, name, func(volume *corev1.Volume) {
		if volume.PersistentVolumeClaim == nil {
			volume.PersistentVolumeClaim = &corev1.PersistentVolumeClaimVolumeSource{}
		}
		volume.PersistentVolumeClaim.ClaimName = claimName
	})
}

func ApplyConfigMapVolume(deployment *appsv1.Deployment, name string, configMapName string) {
	ApplyVolume(deployment, name, func(volume *corev1.Volume) {
		if volume.ConfigMap == nil {
			volume.ConfigMap = &corev1.ConfigMapVolumeSource{}
		}
		volume.ConfigMap.Name = configMapName
	})
}

func ApplySecretVolume(deployment *appsv1.Deployment, name string, secretName string) {
	ApplyVolume(deployment, name, func(volume *corev1.Volume) {
		if volume.Secret == nil {
			volume.Secret = &corev1.SecretVolumeSource{}
		}
		volume.Secret.SecretName = secretName
	})
}

func ApplyEmptyDirVolume(deployment *appsv1.Deployment, name string) {
	ApplyVolume(deployment, name, func(volume *corev1.Volume) {
		if volume.EmptyDir == nil {
			volume.EmptyDir = &corev1.EmptyDirVolumeSource{}
		}
	})
}

func ApplyVolume(deployment *appsv1.Deployment, name string, mutator func(*corev1.Volume)) {
	// call "with error", and eat up the error
	_ = ApplyVolumeWithError(deployment, name, func(volume *corev1.Volume) error {
		mutator(volume)
		return nil
	})
}

func ApplyVolumeWithError(deployment *appsv1.Deployment, name string, mutator func(*corev1.Volume) error) error {

	if deployment.Spec.Template.Spec.Volumes == nil {
		deployment.Spec.Template.Spec.Volumes = make([]corev1.Volume, 0)
	}

	for i, c := range deployment.Spec.Template.Spec.Volumes {
		if c.Name == name {
			return mutator(&deployment.Spec.Template.Spec.Volumes[i])
		}
	}

	v := &corev1.Volume{
		Name: name,
	}

	err := mutator(v)
	if err == nil {
		deployment.Spec.Template.Spec.Volumes = append(deployment.Spec.Template.Spec.Volumes, *v)
	}

	return err
}

func DropVolume(deployment *appsv1.Deployment, name string) {
	if deployment.Spec.Template.Spec.Volumes == nil {
		return
	}

	// removing an entry from an array in go is tricky ...

	for i := len(deployment.Spec.Template.Spec.Volumes) - 1; i >= 0; i-- {
		v := deployment.Spec.Template.Spec.Volumes[i]
		if v.Name == name {
			deployment.Spec.Template.Spec.Volumes = append(
				deployment.Spec.Template.Spec.Volumes[:i],
				deployment.Spec.Template.Spec.Volumes[i+1:]...,
			)
		}
	}
}

func ApplyContainerImage(container *corev1.Container, imageName string, override *v1beta1.ImageOverride) error {

	resolved, err := images.GetImage(imageName)
	if err != nil {
		return err
	}

	var pullPolicy corev1.PullPolicy

	if override != nil {
		if override.Name != "" {
			resolved = override.Name
		}
		if override.PullPolicy != "" {
			pullPolicy = override.PullPolicy
		}
	}

	container.Image = resolved
	if pullPolicy != "" {
		container.ImagePullPolicy = pullPolicy
	} else {
		container.ImagePullPolicy = images.PullPolicyFromImageName(resolved)
	}

	return nil
}

func SetContainerImage(container *corev1.Container, imageName string, overrides v1beta1.ImageOverridesProvider) error {

	resolved, err := images.GetImage(imageName)
	if err != nil {
		return err
	}

	var pullPolicy corev1.PullPolicy

	overrideMap := overrides.GetImageOverrides()
	if overrideMap != nil {
		val, ok := overrideMap[imageName]
		if ok {
			if val.Name != "" {
				resolved = val.Name
			}
			if val.PullPolicy != "" {
				pullPolicy = val.PullPolicy
			}
		}
	}

	container.Image = resolved
	if pullPolicy != "" {
		container.ImagePullPolicy = pullPolicy
	} else {
		container.ImagePullPolicy = images.PullPolicyFromImageName(resolved)
	}

	return nil
}

// Apply a simple HTTP probe
func ApplyHttpProbe(probe *corev1.Probe, initialDelaySeconds int32, path string, port uint16) *corev1.Probe {
	if probe == nil {
		probe = &corev1.Probe{}
	}

	probe.InitialDelaySeconds = initialDelaySeconds
	probe.Exec = nil
	probe.TCPSocket = nil
	probe.HTTPGet = &corev1.HTTPGetAction{
		Path:   path,
		Port:   intstr.FromInt(int(port)),
		Scheme: corev1.URISchemeHTTP,
	}

	return probe
}

func ApplyVolumeMountWithError(container *corev1.Container, name string, mutator func(mount *corev1.VolumeMount) error) error {

	if container.VolumeMounts == nil {
		container.VolumeMounts = make([]corev1.VolumeMount, 0)
	}

	for i, v := range container.VolumeMounts {
		if v.Name == name {
			return mutator(&container.VolumeMounts[i])
		}
	}

	v := &corev1.VolumeMount{
		Name: name,
	}

	err := mutator(v)
	if err == nil {
		container.VolumeMounts = append(container.VolumeMounts, *v)
	}

	return err
}

func ApplyVolumeMount(container *corev1.Container, name string, mutator func(mount *corev1.VolumeMount)) {
	// call "with error", and eat up the error
	_ = ApplyVolumeMountWithError(container, name, func(mount *corev1.VolumeMount) error {
		mutator(mount)
		return nil
	})
}

func ApplyVolumeMountSimple(container *corev1.Container, name string, path string, readOnly bool) {
	ApplyVolumeMount(container, name, func(mount *corev1.VolumeMount) {
		mount.MountPath = path
		mount.ReadOnly = readOnly
	})
}

func DropVolumeMount(container *corev1.Container, name string) {
	if container.VolumeMounts == nil {
		return
	}

	// removing an entry from an array in go is tricky ...

	for i := len(container.VolumeMounts) - 1; i >= 0; i-- {
		v := container.VolumeMounts[i]
		if v.Name == name {
			container.VolumeMounts = append(
				container.VolumeMounts[:i], container.VolumeMounts[i+1:]...,
			)
		}
	}
}

func ApplyEnvWithError(container *corev1.Container, name string, mutator func(envvar *corev1.EnvVar) error) error {

	if container.Env == nil {
		container.Env = make([]corev1.EnvVar, 0)
	}

	for i, e := range container.Env {
		if e.Name == name {
			return mutator(&container.Env[i])
		}
	}

	e := &corev1.EnvVar{
		Name: name,
	}

	err := mutator(e)
	if err == nil {
		container.Env = append(container.Env, *e)
	}

	return err
}

func ApplyEnv(container *corev1.Container, name string, mutator func(envvar *corev1.EnvVar)) {
	_ = ApplyEnvWithError(container, name, func(envvar *corev1.EnvVar) error {
		mutator(envvar)
		return nil
	})
}

func ApplyEnvSimple(container *corev1.Container, name string, value string) {
	ApplyEnv(container, name, func(envvar *corev1.EnvVar) {
		envvar.ValueFrom = nil
		envvar.Value = value
	})
}

func ApplyEnvSecret(container *corev1.Container, name string, secretKey string, secretName string) {
	ApplyEnv(container, name, func(envvar *corev1.EnvVar) {
		envvar.Value = ""
		envvar.ValueFrom = &corev1.EnvVarSource{
			SecretKeyRef: &corev1.SecretKeySelector{
				Key: secretKey,
				LocalObjectReference: corev1.LocalObjectReference{
					Name: secretName,
				},
			},
		}
	})
}

func ApplyEnvConfigMap(container *corev1.Container, name string, configMapKey string, configMapName string) {
	ApplyEnv(container, name, func(envvar *corev1.EnvVar) {
		envvar.Value = ""
		envvar.ValueFrom = &corev1.EnvVarSource{
			ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
				Key: configMapKey,
				LocalObjectReference: corev1.LocalObjectReference{
					Name: configMapName,
				},
			},
		}
	})
}

func ApplyTlsSecret(secret *corev1.Secret, key []byte, certificate []byte) {
	secret.Type = corev1.SecretTypeTLS
	secret.Data = map[string][]byte{
		"tls.key": key,
		"tls.crt": certificate,
	}
}
<commit_msg>Set default replicas to 1 (#2663)<commit_after>/*
 * Copyright 2019, EnMasse authors.
 * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
 */

package install

import (
	"github.com/enmasseproject/enmasse/pkg/apis/enmasse/v1beta1"
	"github.com/enmasseproject/enmasse/pkg/util/images"

	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
)

func CreateDefaultLabels(labels map[string]string, component string, name string) map[string]string {

	if labels == nil {
		labels = make(map[string]string)
	}

	labels["component"] = component
	labels["app"] = "enmasse"
	labels["name"] = name

	return labels
}

// Apply standard set of labels
func ApplyDefaultLabels(meta *v1.ObjectMeta, component string, name string) {
	meta.Labels = CreateDefaultLabels(meta.Labels, component, name)
}

// Apply some default service values
func ApplyServiceDefaults(service *corev1.Service, component string, name string) {

	ApplyDefaultLabels(&service.ObjectMeta, component, name)
	if service.CreationTimestamp.IsZero() {
		service.Spec.Selector = CreateDefaultLabels(nil, component, name)
	}

}

// Apply some default deployment values
func ApplyDeploymentDefaults(deployment *appsv1.Deployment, component string, name string) {

	ApplyDefaultLabels(&deployment.ObjectMeta, component, name)

	if deployment.CreationTimestamp.IsZero() {
		deployment.Spec.Selector = &v1.LabelSelector{
			MatchLabels: CreateDefaultLabels(nil, component, name),
		}
	}

	replicas := int32(1)
	deployment.Spec.Replicas = &replicas
	deployment.Spec.Template.ObjectMeta.Labels = CreateDefaultLabels(deployment.Spec.Template.ObjectMeta.Labels, component, name)

}

func ApplyContainer(deployment *appsv1.Deployment, name string, mutator func(*corev1.Container)) {
	// call "with error", and eat up the error
	_ = ApplyContainerWithError(deployment, name, func(container *corev1.Container) error {
		mutator(container)
		return nil
	})
}

func ApplyContainerWithError(deployment *appsv1.Deployment, name string, mutator func(*corev1.Container) error) error {

	if deployment.Spec.Template.Spec.Containers == nil {
		deployment.Spec.Template.Spec.Containers = make([]corev1.Container, 0)
	}

	for i, c := range deployment.Spec.Template.Spec.Containers {
		if c.Name == name {
			return mutator(&deployment.Spec.Template.Spec.Containers[i])
		}
	}

	c := &corev1.Container{
		Name: name,
	}

	err := mutator(c)
	if err == nil {
		deployment.Spec.Template.Spec.Containers = append(deployment.Spec.Template.Spec.Containers, *c)
	}

	return err
}

func ApplyInitContainer(deployment *appsv1.Deployment, name string, mutator func(*corev1.Container)) {
	// call "with error", and eat up the error
	_ = ApplyInitContainerWithError(deployment, name, func(container *corev1.Container) error {
		mutator(container)
		return nil
	})
}

func ApplyInitContainerWithError(deployment *appsv1.Deployment, name string, mutator func(*corev1.Container) error) error {

	if deployment.Spec.Template.Spec.InitContainers == nil {
		deployment.Spec.Template.Spec.InitContainers = make([]corev1.Container, 0)
	}

	for i, c := range deployment.Spec.Template.Spec.InitContainers {
		if c.Name == name {
			return mutator(&deployment.Spec.Template.Spec.InitContainers[i])
		}
	}

	c := &corev1.Container{
		Name: name,
	}

	err := mutator(c)
	if err == nil {
		deployment.Spec.Template.Spec.InitContainers = append(deployment.Spec.Template.Spec.InitContainers, *c)
	}

	return err
}

func ApplyPersistentVolume(deployment *appsv1.Deployment, name string, claimName string) {
	ApplyVolume(deployment, name, func(volume *corev1.Volume) {
		if volume.PersistentVolumeClaim == nil {
			volume.PersistentVolumeClaim = &corev1.PersistentVolumeClaimVolumeSource{}
		}
		volume.PersistentVolumeClaim.ClaimName = claimName
	})
}

func ApplyConfigMapVolume(deployment *appsv1.Deployment, name string, configMapName string) {
	ApplyVolume(deployment, name, func(volume *corev1.Volume) {
		if volume.ConfigMap == nil {
			volume.ConfigMap = &corev1.ConfigMapVolumeSource{}
		}
		volume.ConfigMap.Name = configMapName
	})
}

func ApplySecretVolume(deployment *appsv1.Deployment, name string, secretName string) {
	ApplyVolume(deployment, name, func(volume *corev1.Volume) {
		if volume.Secret == nil {
			volume.Secret = &corev1.SecretVolumeSource{}
		}
		volume.Secret.SecretName = secretName
	})
}

func ApplyEmptyDirVolume(deployment *appsv1.Deployment, name string) {
	ApplyVolume(deployment, name, func(volume *corev1.Volume) {
		if volume.EmptyDir == nil {
			volume.EmptyDir = &corev1.EmptyDirVolumeSource{}
		}
	})
}

func ApplyVolume(deployment *appsv1.Deployment, name string, mutator func(*corev1.Volume)) {
	// call "with error", and eat up the error
	_ = ApplyVolumeWithError(deployment, name, func(volume *corev1.Volume) error {
		mutator(volume)
		return nil
	})
}

func ApplyVolumeWithError(deployment *appsv1.Deployment, name string, mutator func(*corev1.Volume) error) error {

	if deployment.Spec.Template.Spec.Volumes == nil {
		deployment.Spec.Template.Spec.Volumes = make([]corev1.Volume, 0)
	}

	for i, c := range deployment.Spec.Template.Spec.Volumes {
		if c.Name == name {
			return mutator(&deployment.Spec.Template.Spec.Volumes[i])
		}
	}

	v := &corev1.Volume{
		Name: name,
	}

	err := mutator(v)
	if err == nil {
		deployment.Spec.Template.Spec.Volumes = append(deployment.Spec.Template.Spec.Volumes, *v)
	}

	return err
}

func DropVolume(deployment *appsv1.Deployment, name string) {
	if deployment.Spec.Template.Spec.Volumes == nil {
		return
	}

	// removing an entry from an array in go is tricky ...

	for i := len(deployment.Spec.Template.Spec.Volumes) - 1; i >= 0; i-- {
		v := deployment.Spec.Template.Spec.Volumes[i]
		if v.Name == name {
			deployment.Spec.Template.Spec.Volumes = append(
				deployment.Spec.Template.Spec.Volumes[:i],
				deployment.Spec.Template.Spec.Volumes[i+1:]...,
			)
		}
	}
}

func ApplyContainerImage(container *corev1.Container, imageName string, override *v1beta1.ImageOverride) error {

	resolved, err := images.GetImage(imageName)
	if err != nil {
		return err
	}

	var pullPolicy corev1.PullPolicy

	if override != nil {
		if override.Name != "" {
			resolved = override.Name
		}
		if override.PullPolicy != "" {
			pullPolicy = override.PullPolicy
		}
	}

	container.Image = resolved
	if pullPolicy != "" {
		container.ImagePullPolicy = pullPolicy
	} else {
		container.ImagePullPolicy = images.PullPolicyFromImageName(resolved)
	}

	return nil
}

func SetContainerImage(container *corev1.Container, imageName string, overrides v1beta1.ImageOverridesProvider) error {

	resolved, err := images.GetImage(imageName)
	if err != nil {
		return err
	}

	var pullPolicy corev1.PullPolicy

	overrideMap := overrides.GetImageOverrides()
	if overrideMap != nil {
		val, ok := overrideMap[imageName]
		if ok {
			if val.Name != "" {
				resolved = val.Name
			}
			if val.PullPolicy != "" {
				pullPolicy = val.PullPolicy
			}
		}
	}

	container.Image = resolved
	if pullPolicy != "" {
		container.ImagePullPolicy = pullPolicy
	} else {
		container.ImagePullPolicy = images.PullPolicyFromImageName(resolved)
	}

	return nil
}

// Apply a simple HTTP probe
func ApplyHttpProbe(probe *corev1.Probe, initialDelaySeconds int32, path string, port uint16) *corev1.Probe {
	if probe == nil {
		probe = &corev1.Probe{}
	}

	probe.InitialDelaySeconds = initialDelaySeconds
	probe.Exec = nil
	probe.TCPSocket = nil
	probe.HTTPGet = &corev1.HTTPGetAction{
		Path:   path,
		Port:   intstr.FromInt(int(port)),
		Scheme: corev1.URISchemeHTTP,
	}

	return probe
}

func ApplyVolumeMountWithError(container *corev1.Container, name string, mutator func(mount *corev1.VolumeMount) error) error {

	if container.VolumeMounts == nil {
		container.VolumeMounts = make([]corev1.VolumeMount, 0)
	}

	for i, v := range container.VolumeMounts {
		if v.Name == name {
			return mutator(&container.VolumeMounts[i])
		}
	}

	v := &corev1.VolumeMount{
		Name: name,
	}

	err := mutator(v)
	if err == nil {
		container.VolumeMounts = append(container.VolumeMounts, *v)
	}

	return err
}

func ApplyVolumeMount(container *corev1.Container, name string, mutator func(mount *corev1.VolumeMount)) {
	// call "with error", and eat up the error
	_ = ApplyVolumeMountWithError(container, name, func(mount *corev1.VolumeMount) error {
		mutator(mount)
		return nil
	})
}

func ApplyVolumeMountSimple(container *corev1.Container, name string, path string, readOnly bool) {
	ApplyVolumeMount(container, name, func(mount *corev1.VolumeMount) {
		mount.MountPath = path
		mount.ReadOnly = readOnly
	})
}

func DropVolumeMount(container *corev1.Container, name string) {
	if container.VolumeMounts == nil {
		return
	}

	// removing an entry from an array in go is tricky ...

	for i := len(container.VolumeMounts) - 1; i >= 0; i-- {
		v := container.VolumeMounts[i]
		if v.Name == name {
			container.VolumeMounts = append(
				container.VolumeMounts[:i], container.VolumeMounts[i+1:]...,
			)
		}
	}
}

func ApplyEnvWithError(container *corev1.Container, name string, mutator func(envvar *corev1.EnvVar) error) error {

	if container.Env == nil {
		container.Env = make([]corev1.EnvVar, 0)
	}

	for i, e := range container.Env {
		if e.Name == name {
			return mutator(&container.Env[i])
		}
	}

	e := &corev1.EnvVar{
		Name: name,
	}

	err := mutator(e)
	if err == nil {
		container.Env = append(container.Env, *e)
	}

	return err
}

func ApplyEnv(container *corev1.Container, name string, mutator func(envvar *corev1.EnvVar)) {
	_ = ApplyEnvWithError(container, name, func(envvar *corev1.EnvVar) error {
		mutator(envvar)
		return nil
	})
}

func ApplyEnvSimple(container *corev1.Container, name string, value string) {
	ApplyEnv(container, name, func(envvar *corev1.EnvVar) {
		envvar.ValueFrom = nil
		envvar.Value = value
	})
}

func ApplyEnvSecret(container *corev1.Container, name string, secretKey string, secretName string) {
	ApplyEnv(container, name, func(envvar *corev1.EnvVar) {
		envvar.Value = ""
		envvar.ValueFrom = &corev1.EnvVarSource{
			SecretKeyRef: &corev1.SecretKeySelector{
				Key: secretKey,
				LocalObjectReference: corev1.LocalObjectReference{
					Name: secretName,
				},
			},
		}
	})
}

func ApplyEnvConfigMap(container *corev1.Container, name string, configMapKey string, configMapName string) {
	ApplyEnv(container, name, func(envvar *corev1.EnvVar) {
		envvar.Value = ""
		envvar.ValueFrom = &corev1.EnvVarSource{
			ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
				Key: configMapKey,
				LocalObjectReference: corev1.LocalObjectReference{
					Name: configMapName,
				},
			},
		}
	})
}

func ApplyTlsSecret(secret *corev1.Secret, key []byte, certificate []byte) {
	secret.Type = corev1.SecretTypeTLS
	secret.Data = map[string][]byte{
		"tls.key": key,
		"tls.crt": certificate,
	}
}
<|endoftext|>


<commit_before>package symlink

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

type SL struct {
	dst  string
	path string
}

func New(link, dst string) (*SL, error) {
	var err error
	if dst, err = dirAbsPath(dst); err != nil {
		return nil, err
	}
	exist, _, err := dirExists(dst)
	if err != nil {
		return nil, err
	}
	if !exist {
		return nil, fmt.Errorf("Unknown destination '%s'", dst)
	}
	return nil, nil
}

// a/b => c:\path\to\a\b\
func dirAbsPath(path string) (string, error) {
	path = filepath.FromSlash(path)
	var err error
	path, err = filepath.Abs(path)
	if err != nil {
		return "", err
	}
	sep := string(filepath.Separator)
	if strings.HasSuffix(path, sep) == false {
		path = path + sep
	}
	return path, nil
}

func dirExists(path string) (bool, string, error) {
	fi, err := os.Stat(path)
	if fi == nil {
		return false, "", err
	}
	// sys := fi.Sys().(*syscall.Win32FileAttributeData)
	if err == nil {
		return true, "", nil
	}
	if strings.HasPrefix(err.Error(), "readlink ") == false {
		return false, "", err
	}
	// This is a symlink (JUNCTION on Windows)
	dir := filepath.Dir(path)
	base := filepath.Base(dir)
	dir = filepath.Dir(dir)
	sdir := ""
	if sdir, err = execcmd("dir", ".", dir); err != nil {
		return false, "", err
	}
	r := regexp.MustCompile(fmt.Sprintf(`(?m)<J[UO]NCTION>\s+%s\s+\[([^\]]+)\]\s*$`, base))
	n := r.FindAllStringSubmatch(sdir, -1)
	if len(n) == 1 {
		return true, n[0][1], nil
	}
	return false, "", fmt.Errorf("Unable to list content of symlink parent dir '%s' for '%s'", dir, base)
}

func execcmd(exe, cmd string, dir string) (string, error) {
	args := strings.Split(cmd, " ")
	args = append([]string{"/c", exe}, args...)
	c := exec.Command("cmd", args...)
	c.Dir = dir
	var bout bytes.Buffer
	c.Stdout = &bout
	var berr bytes.Buffer
	c.Stderr = &berr
	err := c.Run()
	if err != nil {
		return bout.String(), fmt.Errorf("Unable to run '%s %s' in '%s': err '%s'\n'%s'", exe, cmd, dir, err.Error(), berr.String())
	} else if berr.String() != "" {
		return bout.String(), fmt.Errorf("Warning on run '%s %s' in '%s': '%s'", exe, cmd, dir, berr.String())
	}
	return bout.String(), nil
}
<commit_msg>symlink.go: dirExists false can be with or without an error<commit_after>package symlink

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

type SL struct {
	dst  string
	path string
}

func New(link, dst string) (*SL, error) {
	var err error
	if dst, err = dirAbsPath(dst); err != nil {
		return nil, err
	}
	exist, _, err := dirExists(dst)
	msgerr := ""
	if err != nil {
		msgerr = fmt.Sprintf("\rError: '%+v'", err)
	}
	if !exist {
		return nil, fmt.Errorf("Unknown destination '%s'%s", dst, msgerr)
	}
	return nil, nil
}

// a/b => c:\path\to\a\b\
func dirAbsPath(path string) (string, error) {
	path = filepath.FromSlash(path)
	var err error
	path, err = filepath.Abs(path)
	if err != nil {
		return "", err
	}
	sep := string(filepath.Separator)
	if strings.HasSuffix(path, sep) == false {
		path = path + sep
	}
	return path, nil
}

func dirExists(path string) (bool, string, error) {
	fi, err := os.Stat(path)
	if fi == nil {
		return false, "", err
	}
	// sys := fi.Sys().(*syscall.Win32FileAttributeData)
	if err == nil {
		return true, "", nil
	}
	if strings.HasPrefix(err.Error(), "readlink ") == false {
		return false, "", err
	}
	// This is a symlink (JUNCTION on Windows)
	dir := filepath.Dir(path)
	base := filepath.Base(dir)
	dir = filepath.Dir(dir)
	sdir := ""
	if sdir, err = execcmd("dir", ".", dir); err != nil {
		return false, "", err
	}
	r := regexp.MustCompile(fmt.Sprintf(`(?m)<J[UO]NCTION>\s+%s\s+\[([^\]]+)\]\s*$`, base))
	n := r.FindAllStringSubmatch(sdir, -1)
	if len(n) == 1 {
		return true, n[0][1], nil
	}
	return false, "", fmt.Errorf("Unable to list content of symlink parent dir '%s' for '%s'", dir, base)
}

func execcmd(exe, cmd string, dir string) (string, error) {
	args := strings.Split(cmd, " ")
	args = append([]string{"/c", exe}, args...)
	c := exec.Command("cmd", args...)
	c.Dir = dir
	var bout bytes.Buffer
	c.Stdout = &bout
	var berr bytes.Buffer
	c.Stderr = &berr
	err := c.Run()
	if err != nil {
		return bout.String(), fmt.Errorf("Unable to run '%s %s' in '%s': err '%s'\n'%s'", exe, cmd, dir, err.Error(), berr.String())
	} else if berr.String() != "" {
		return bout.String(), fmt.Errorf("Warning on run '%s %s' in '%s': '%s'", exe, cmd, dir, berr.String())
	}
	return bout.String(), nil
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/http/cgi"
	"os"
	"regexp"
	"syscall"

	"gitorious.org/gitorious/gitorious-proto/api"
	"gitorious.org/gitorious/gitorious-proto/common"
)

func say(w http.ResponseWriter, status int, s string, args ...interface{}) {
	http.Error(w, fmt.Sprintf(s, args...), status)
}

func requestBasicAuth(w http.ResponseWriter, s string) {
	w.Header().Set("WWW-Authenticate", `Basic realm="Gitorious"`)
	say(w, http.StatusUnauthorized, s)
}

var pathRegexp = regexp.MustCompile("^/(.+\\.git)(/.+)$")

func parsePath(path string) (string, string, error) {
	matches := pathRegexp.FindStringSubmatch(path)
	if matches == nil {
		return "", "", errors.New(fmt.Sprintf(`invalid path "%v"`, path))
	}

	return matches[1], matches[2], nil
}

func createHttpEnv(username, repoPath string, repoConfig *api.RepoConfig, translatedPath string) []string {
	env := common.CreateEnv("http", username, repoPath, repoConfig)

	env = append(env, "REMOTE_USER="+username) // enables "receive-pack" service (push) in git-http-backend
	env = append(env, "GIT_HTTP_EXPORT_ALL=1") // enables clones without "git-daemon-export-ok" magic file
	env = append(env, "PATH_TRANSLATED="+translatedPath)

	return env
}

func execGitHttpBackend(env []string, w http.ResponseWriter, req *http.Request) {
	cgiHandler := &cgi.Handler{
		Path: "/bin/sh",
		Args: []string{"-c", "git http-backend"},
		Dir:  ".",
		Env:  env,
	}

	cgiHandler.ServeHTTP(w, req)
}

type Handler struct {
	logger          *log.Logger
	internalApi     api.InternalApi
	repositoryStore common.RepositoryStore
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	logger := &common.SessionLogger{h.logger, req.RemoteAddr}

	logger.Printf("client connected")

	var username string

	if usernameOrEmail, password, ok := BasicAuth(req); ok {
		user, err := h.internalApi.AuthenticateUser(usernameOrEmail, password)
		if err != nil {
			say(w, http.StatusInternalServerError, "Error occured, please contact support")
			logger.Printf("%v, disconnecting...", err)
			return
		}

		if user != nil {
			username = user.Username
		} else {
			requestBasicAuth(w, "Invalid username or password")
			logger.Printf("invalid credentials, disconnecting...")
			return
		}
	}

	repoPath, slug, err := parsePath(req.URL.Path)
	if err != nil {
		say(w, http.StatusBadRequest, "Invalid command")
		logger.Printf("%v, disconnecting...", err)
		return
	}

	repoConfig, err := h.internalApi.GetRepoConfig(repoPath, username)
	if err != nil {
		if httpErr, ok := err.(*api.HttpError); ok {
			if httpErr.StatusCode == 403 {
				requestBasicAuth(w, "Access denied")
				logger.Printf("%v, disconnecting...", err)
				return
			} else if httpErr.StatusCode == 404 {
				say(w, http.StatusNotFound, "Invalid repository path")
				logger.Printf("%v, disconnecting...", err)
				return
			}
		}

		say(w, http.StatusInternalServerError, "Error occured, please contact support")
		logger.Printf("%v, disconnecting...", err)
		return
	}

	logger.Printf("real repo path: %v", repoConfig.RealPath)

	fullRepoPath, err := h.repositoryStore.GetFullRepoPath(repoConfig.RealPath)
	if err != nil {
		say(w, http.StatusInternalServerError, "Error occurred, please contact support")
		logger.Printf("%v, disconnecting...", err)
		return
	}

	translatedPath := fullRepoPath + slug
	env := createHttpEnv(username, repoPath, repoConfig, translatedPath)

	logger.Printf(`invoking git-http-backend with translated path "%v"`, translatedPath)

	execGitHttpBackend(env, w, req)

	logger.Printf("done")
}

func main() {
	syscall.Umask(0022) // set umask for pushes

	var (
		reposRootPath  = flag.String("r", ".", "Directory containing git repositories")
		internalApiUrl = flag.String("u", "http://localhost:3000/api/internal", "...")
		addr           = flag.String("l", ":80", "Address/port to listen on")
	)
	flag.Parse()

	logger := log.New(os.Stdout, "", log.LstdFlags)
	internalApi := &api.GitoriousInternalApi{*internalApiUrl}
	repositoryStore := &common.GitoriousRepositoryStore{*reposRootPath}

	http.Handle("/", &Handler{logger, internalApi, repositoryStore})
	log.Fatal(http.ListenAndServe(*addr, nil))
}
<commit_msg>Print address server is listening on<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/http/cgi"
	"os"
	"regexp"
	"syscall"

	"gitorious.org/gitorious/gitorious-proto/api"
	"gitorious.org/gitorious/gitorious-proto/common"
)

func say(w http.ResponseWriter, status int, s string, args ...interface{}) {
	http.Error(w, fmt.Sprintf(s, args...), status)
}

func requestBasicAuth(w http.ResponseWriter, s string) {
	w.Header().Set("WWW-Authenticate", `Basic realm="Gitorious"`)
	say(w, http.StatusUnauthorized, s)
}

var pathRegexp = regexp.MustCompile("^/(.+\\.git)(/.+)$")

func parsePath(path string) (string, string, error) {
	matches := pathRegexp.FindStringSubmatch(path)
	if matches == nil {
		return "", "", errors.New(fmt.Sprintf(`invalid path "%v"`, path))
	}

	return matches[1], matches[2], nil
}

func createHttpEnv(username, repoPath string, repoConfig *api.RepoConfig, translatedPath string) []string {
	env := common.CreateEnv("http", username, repoPath, repoConfig)

	env = append(env, "REMOTE_USER="+username) // enables "receive-pack" service (push) in git-http-backend
	env = append(env, "GIT_HTTP_EXPORT_ALL=1") // enables clones without "git-daemon-export-ok" magic file
	env = append(env, "PATH_TRANSLATED="+translatedPath)

	return env
}

func execGitHttpBackend(env []string, w http.ResponseWriter, req *http.Request) {
	cgiHandler := &cgi.Handler{
		Path: "/bin/sh",
		Args: []string{"-c", "git http-backend"},
		Dir:  ".",
		Env:  env,
	}

	cgiHandler.ServeHTTP(w, req)
}

type Handler struct {
	logger          *log.Logger
	internalApi     api.InternalApi
	repositoryStore common.RepositoryStore
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	logger := &common.SessionLogger{h.logger, req.RemoteAddr}

	logger.Printf("client connected")

	var username string

	if usernameOrEmail, password, ok := BasicAuth(req); ok {
		user, err := h.internalApi.AuthenticateUser(usernameOrEmail, password)
		if err != nil {
			say(w, http.StatusInternalServerError, "Error occured, please contact support")
			logger.Printf("%v, disconnecting...", err)
			return
		}

		if user != nil {
			username = user.Username
		} else {
			requestBasicAuth(w, "Invalid username or password")
			logger.Printf("invalid credentials, disconnecting...")
			return
		}
	}

	repoPath, slug, err := parsePath(req.URL.Path)
	if err != nil {
		say(w, http.StatusBadRequest, "Invalid command")
		logger.Printf("%v, disconnecting...", err)
		return
	}

	repoConfig, err := h.internalApi.GetRepoConfig(repoPath, username)
	if err != nil {
		if httpErr, ok := err.(*api.HttpError); ok {
			if httpErr.StatusCode == 403 {
				requestBasicAuth(w, "Access denied")
				logger.Printf("%v, disconnecting...", err)
				return
			} else if httpErr.StatusCode == 404 {
				say(w, http.StatusNotFound, "Invalid repository path")
				logger.Printf("%v, disconnecting...", err)
				return
			}
		}

		say(w, http.StatusInternalServerError, "Error occured, please contact support")
		logger.Printf("%v, disconnecting...", err)
		return
	}

	logger.Printf("real repo path: %v", repoConfig.RealPath)

	fullRepoPath, err := h.repositoryStore.GetFullRepoPath(repoConfig.RealPath)
	if err != nil {
		say(w, http.StatusInternalServerError, "Error occurred, please contact support")
		logger.Printf("%v, disconnecting...", err)
		return
	}

	translatedPath := fullRepoPath + slug
	env := createHttpEnv(username, repoPath, repoConfig, translatedPath)

	logger.Printf(`invoking git-http-backend with translated path "%v"`, translatedPath)

	execGitHttpBackend(env, w, req)

	logger.Printf("done")
}

func main() {
	syscall.Umask(0022) // set umask for pushes

	var (
		reposRootPath  = flag.String("r", ".", "Directory containing git repositories")
		internalApiUrl = flag.String("u", "http://localhost:3000/api/internal", "...")
		addr           = flag.String("l", ":80", "Address/port to listen on")
	)
	flag.Parse()

	logger := log.New(os.Stdout, "", log.LstdFlags)
	internalApi := &api.GitoriousInternalApi{*internalApiUrl}
	repositoryStore := &common.GitoriousRepositoryStore{*reposRootPath}

	logger.Printf("listening on %v", *addr)

	http.Handle("/", &Handler{logger, internalApi, repositoryStore})
	log.Fatal(http.ListenAndServe(*addr, nil))
}
<|endoftext|>


<commit_before>package mysql

import (
	_ "github.com/go-sql-driver/mysql"
	"github.com/jinzhu/gorm"
)

type GormConf struct {
	Driver        string
	Setting       string
	SingularTable bool
	LogMode       bool
}

var X *gorm.DB

func (gc *GormConf) InitGorm() error {
	var err error
	//"root:root@tcp(localhost:3306)/plucron?charset=utf8&parseTime=True&loc=Local"
	X, err = gorm.Open(gc.Driver, gc.Setting)
	if err != nil {
		return err
	}
	X.SingularTable(gc.SingularTable)
	X.LogMode(gc.LogMode)
	return nil
}
<commit_msg>增加gorm e.x<commit_after>package mysql

import (
	_ "github.com/go-sql-driver/mysql"
	"github.com/jinzhu/gorm"
)

type GormConf struct {
	Driver        string
	Setting       string
	SingularTable bool
	LogMode       bool
}

var X *gorm.DB

func (gc *GormConf) InitGorm() error {
	var err error
	//"root:root@tcp(localhost:3306)/plucron?charset=utf8&parseTime=True&loc=Local"
	X, err = gorm.Open(gc.Driver, gc.Setting)
	if err != nil {
		return err
	}
	X.SingularTable(gc.SingularTable)
	X.LogMode(gc.LogMode)
	return nil
}

/*
func Insert(cron Cronlist) (uint64, error) {
	res := core.X.Create(&cron)
	if res.Error != nil {
		return 0, res.Error
	}
	return cron.ID, nil
}

func Update(cron Cronlist, id []uint64) error {
	res := core.X.Table("cronlist").Where("id IN (?)", id).Updates(cron)
	if res.Error != nil {
		return res.Error
	}
	return nil
}

func Delete(id []uint64) error {
	res := core.X.Delete(Cronlist{}, "id IN (?)", id)
	if res.Error != nil {
		return res.Error
	}
	return nil
}

func Select(id []uint64) (cronlist Cronlist, err error) {
	sql := `
SELECT	 id, name, type
FROM  	  cronlist
WHERE 	id IN (?)
`
	res := core.X.Raw(sql, id).Scan(&cronlist)
	if res.Error != nil {
		return cronlist, res.Error
	}
	return cronlist, nil
}

//transaction
func Transact() error {
	tx := core.X.Begin()
	cronlist := Cronlist{
		Name: "Iversion",
		Type: 2,
	}
	res := core.X.Create(&cronlist)
	if res.Error != nil {
		tx.Rollback()
		return res.Error
	}

	res = core.X.Delete(Cronlist{}, "id IN (?)", []uint64{361})
	if res.Error != nil {
		tx.Rollback()
		return res.Error
	}
	tx.Commit()
	return nil
}
*/
<|endoftext|>