<commit_before>package policy

import (
	"errors"
	"fmt"
	"io"
	"strings"

	"github.com/spf13/cobra"

	kapi "k8s.io/kubernetes/pkg/api"
	kapierrors "k8s.io/kubernetes/pkg/api/errors"
	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	kutilerrors "k8s.io/kubernetes/pkg/util/errors"
	"k8s.io/kubernetes/pkg/util/sets"

	authorizationapi "github.com/openshift/origin/pkg/authorization/api"
	"github.com/openshift/origin/pkg/client"
	"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy"
	cmdutil "github.com/openshift/origin/pkg/cmd/util"
	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
	uservalidation "github.com/openshift/origin/pkg/user/api/validation"
)

// ReconcileClusterRoleBindingsRecommendedName is the recommended command name
const ReconcileClusterRoleBindingsRecommendedName = "reconcile-cluster-role-bindings"

// ReconcileClusterRoleBindingsOptions contains all the necessary functionality for the OpenShift cli reconcile-cluster-role-bindings command
type ReconcileClusterRoleBindingsOptions struct {
	// RolesToReconcile says which roles should have their default bindings reconciled.
	// An empty or nil slice means reconcile all of them.
	RolesToReconcile []string

	Confirmed bool
	Union     bool

	ExcludeSubjects []kapi.ObjectReference

	Out    io.Writer
	Err    io.Writer
	Output string

	RoleBindingClient client.ClusterRoleBindingInterface
}

const (
	reconcileBindingsLong = `
Update cluster role bindings to match the recommended bootstrap policy

This command will inspect the cluster role bindings against the recommended bootstrap policy.
Any cluster role binding that does not match will be replaced by the recommended bootstrap role binding.
This command will not remove any additional cluster role bindings.

You can see which recommended cluster role bindings have changed by choosing an output type.`

	reconcileBindingsExample = `  # Display the names of cluster role bindings that would be modified
  %[1]s -o name

  # Display the cluster role bindings that would be modified, removing any extra subjects
  %[1]s --additive-only=false

  # Update cluster role bindings that don't match the current defaults
  %[1]s --confirm

  # Update cluster role bindings that don't match the current defaults, avoid adding roles to the system:authenticated group
  %[1]s --confirm --exclude-groups=system:authenticated

  # Update cluster role bindings that don't match the current defaults, removing any extra subjects from the binding
  %[1]s --confirm --additive-only=false`
)

// NewCmdReconcileClusterRoleBindings implements the OpenShift cli reconcile-cluster-role-bindings command
func NewCmdReconcileClusterRoleBindings(name, fullName string, f *clientcmd.Factory, out, err io.Writer) *cobra.Command {
	o := &ReconcileClusterRoleBindingsOptions{
		Out:   out,
		Err:   err,
		Union: true,
	}

	excludeUsers := []string{}
	excludeGroups := []string{}

	cmd := &cobra.Command{
		Use:     name + " [ClusterRoleName]...",
		Short:   "Update cluster role bindings to match the recommended bootstrap policy",
		Long:    reconcileBindingsLong,
		Example: fmt.Sprintf(reconcileBindingsExample, fullName),
		Run: func(cmd *cobra.Command, args []string) {
			if err := o.Complete(cmd, f, args, excludeUsers, excludeGroups); err != nil {
				kcmdutil.CheckErr(err)
			}

			if err := o.Validate(); err != nil {
				kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error()))
			}

			if err := o.RunReconcileClusterRoleBindings(cmd, f); err != nil {
				kcmdutil.CheckErr(err)
			}
		},
	}

	cmd.Flags().BoolVar(&o.Confirmed, "confirm", o.Confirmed, "Specify that cluster role bindings should be modified. Defaults to false, displaying what would be replaced but not actually replacing anything.")
	cmd.Flags().BoolVar(&o.Union, "additive-only", o.Union, "Preserves extra subjects in cluster role bindings.")
	cmd.Flags().StringSliceVar(&excludeUsers, "exclude-users", excludeUsers, "Do not add cluster role bindings for these user names.")
	cmd.Flags().StringSliceVar(&excludeGroups, "exclude-groups", excludeGroups, "Do not add cluster role bindings for these group names.")
	kcmdutil.AddPrinterFlags(cmd)
	cmd.Flags().Lookup("output").DefValue = "yaml"
	cmd.Flags().Lookup("output").Value.Set("yaml")

	return cmd
}

func (o *ReconcileClusterRoleBindingsOptions) Complete(cmd *cobra.Command, f *clientcmd.Factory, args []string, excludeUsers, excludeGroups []string) error {
	oclient, _, err := f.Clients()
	if err != nil {
		return err
	}
	o.RoleBindingClient = oclient.ClusterRoleBindings()

	o.Output = kcmdutil.GetFlagString(cmd, "output")

	o.ExcludeSubjects = authorizationapi.BuildSubjects(excludeUsers, excludeGroups, uservalidation.ValidateUserName, uservalidation.ValidateGroupName)

	mapper, _ := f.Object(false)
	for _, resourceString := range args {
		resource, name, err := cmdutil.ResolveResource(authorizationapi.Resource("clusterroles"), resourceString, mapper)
		if err != nil {
			return err
		}
		if resource != authorizationapi.Resource("clusterroles") {
			return fmt.Errorf("%v is not a valid resource type for this command", resource)
		}
		if len(name) == 0 {
			return fmt.Errorf("%s did not contain a name", resourceString)
		}

		o.RolesToReconcile = append(o.RolesToReconcile, name)
	}

	return nil
}

func (o *ReconcileClusterRoleBindingsOptions) Validate() error {
	if o.RoleBindingClient == nil {
		return errors.New("a role binding client is required")
	}
	return nil
}

func (o *ReconcileClusterRoleBindingsOptions) RunReconcileClusterRoleBindings(cmd *cobra.Command, f *clientcmd.Factory) error {
	changedClusterRoleBindings, fetchErr := o.ChangedClusterRoleBindings()
	if fetchErr != nil && !IsClusterRoleBindingLookupError(fetchErr) {
		// we got an error that isn't due to a partial match, so we can't continue
		return fetchErr
	}

	if len(changedClusterRoleBindings) == 0 {
		return fetchErr
	}

	if (len(o.Output) != 0) && !o.Confirmed {
		list := &kapi.List{}
		for _, item := range changedClusterRoleBindings {
			list.Items = append(list.Items, item)
		}
		mapper, _ := f.Object(false)
		fn := cmdutil.VersionedPrintObject(f.PrintObject, cmd, mapper, o.Out)
		if err := fn(list); err != nil {
			return kutilerrors.NewAggregate([]error{fetchErr, err})
		}
	}

	if o.Confirmed {
		if err := o.ReplaceChangedRoleBindings(changedClusterRoleBindings); err != nil {
			return kutilerrors.NewAggregate([]error{fetchErr, err})
		}
	}

	return fetchErr
}

// ChangedClusterRoleBindings returns the role bindings that must be created and/or updated to
// match the recommended bootstrap policy. If roles to reconcile are provided, but not all are
// found, all partial results are returned.
func (o *ReconcileClusterRoleBindingsOptions) ChangedClusterRoleBindings() ([]*authorizationapi.ClusterRoleBinding, error) {
	changedRoleBindings := []*authorizationapi.ClusterRoleBinding{}

	rolesToReconcile := sets.NewString(o.RolesToReconcile...)
	rolesNotFound := sets.NewString(o.RolesToReconcile...)
	bootstrapClusterRoleBindings := bootstrappolicy.GetBootstrapClusterRoleBindings()
	for i := range bootstrapClusterRoleBindings {
		expectedClusterRoleBinding := &bootstrapClusterRoleBindings[i]
		if (len(rolesToReconcile) > 0) && !rolesToReconcile.Has(expectedClusterRoleBinding.RoleRef.Name) {
			continue
		}
		rolesNotFound.Delete(expectedClusterRoleBinding.RoleRef.Name)

		actualClusterRoleBinding, err := o.RoleBindingClient.Get(expectedClusterRoleBinding.Name)
		if kapierrors.IsNotFound(err) {
			// Remove excluded subjects from the new role binding
			expectedClusterRoleBinding.Subjects, _ = DiffObjectReferenceLists(expectedClusterRoleBinding.Subjects, o.ExcludeSubjects)
			changedRoleBindings = append(changedRoleBindings, expectedClusterRoleBinding)
			continue
		}
		if err != nil {
			return nil, err
		}

		// Copy any existing labels/annotations, so the displayed update is correct
		// This assumes bootstrap role bindings will not set any labels/annotations
		// These aren't actually used during update; the latest labels/annotations are pulled from the existing object again
		expectedClusterRoleBinding.Labels = actualClusterRoleBinding.Labels
		expectedClusterRoleBinding.Annotations = actualClusterRoleBinding.Annotations

		if updatedClusterRoleBinding, needsUpdating := computeUpdatedBinding(*expectedClusterRoleBinding, *actualClusterRoleBinding, o.ExcludeSubjects, o.Union); needsUpdating {
			changedRoleBindings = append(changedRoleBindings, updatedClusterRoleBinding)
		}
	}

	if len(rolesNotFound) != 0 {
		// return the known changes and the error so that a caller can decide if he wants a partial update
		return changedRoleBindings, NewClusterRoleBindingLookupError(rolesNotFound.List())
	}

	return changedRoleBindings, nil
}

// ReplaceChangedRoleBindings will reconcile all the changed system role bindings back to the recommended bootstrap policy
func (o *ReconcileClusterRoleBindingsOptions) ReplaceChangedRoleBindings(changedRoleBindings []*authorizationapi.ClusterRoleBinding) error {
	for i := range changedRoleBindings {
		roleBinding, err := o.RoleBindingClient.Get(changedRoleBindings[i].Name)
		if err != nil && !kapierrors.IsNotFound(err) {
			return err
		}

		if kapierrors.IsNotFound(err) {
			createdRoleBinding, err := o.RoleBindingClient.Create(changedRoleBindings[i])
			if err != nil {
				return err
			}

			fmt.Fprintf(o.Out, "clusterrolebinding/%s\n", createdRoleBinding.Name)
			continue
		}

		// RoleRef is immutable, to reset this, we have to delete/recreate
		if !kapi.Semantic.DeepEqual(roleBinding.RoleRef, changedRoleBindings[i].RoleRef) {
			roleBinding.RoleRef = changedRoleBindings[i].RoleRef
			roleBinding.Subjects = changedRoleBindings[i].Subjects

			// TODO: for extra credit, determine whether the right to delete/create this rolebinding for the current user came from this rolebinding before deleting it
			err := o.RoleBindingClient.Delete(roleBinding.Name)
			if err != nil {
				return err
			}
			createdRoleBinding, err := o.RoleBindingClient.Create(changedRoleBindings[i])
			if err != nil {
				return err
			}
			fmt.Fprintf(o.Out, "clusterrolebinding/%s\n", createdRoleBinding.Name)
			continue
		}

		roleBinding.Subjects = changedRoleBindings[i].Subjects
		updatedRoleBinding, err := o.RoleBindingClient.Update(roleBinding)
		if err != nil {
			return err
		}

		fmt.Fprintf(o.Out, "clusterrolebinding/%s\n", updatedRoleBinding.Name)
	}

	return nil
}

func computeUpdatedBinding(expected authorizationapi.ClusterRoleBinding, actual authorizationapi.ClusterRoleBinding, excludeSubjects []kapi.ObjectReference, union bool) (*authorizationapi.ClusterRoleBinding, bool) {
	needsUpdating := false

	// Always reset the roleref if it is different
	if !kapi.Semantic.DeepEqual(expected.RoleRef, actual.RoleRef) {
		needsUpdating = true
	}

	// compute the list of subjects we should not add roles for (existing subjects in the exclude list should be preserved)
	doNotAddSubjects, _ := DiffObjectReferenceLists(excludeSubjects, actual.Subjects)
	// remove any excluded subjects that do not exist from our expected subject list (so we don't add them)
	expectedSubjects, _ := DiffObjectReferenceLists(expected.Subjects, doNotAddSubjects)

	missingSubjects, extraSubjects := DiffObjectReferenceLists(expectedSubjects, actual.Subjects)
	// Always add missing expected subjects
	if len(missingSubjects) > 0 {
		needsUpdating = true
	}
	// extra subjects only require a change if we're not unioning
	if len(extraSubjects) > 0 && !union {
		needsUpdating = true
	}

	if !needsUpdating {
		return nil, false
	}

	updated := expected
	updated.Subjects = expectedSubjects
	if union {
		updated.Subjects = append(updated.Subjects, extraSubjects...)
	}
	return &updated, true
}

func contains(list []kapi.ObjectReference, item kapi.ObjectReference) bool {
	for _, listItem := range list {
		if kapi.Semantic.DeepEqual(listItem, item) {
			return true
		}
	}
	return false
}

// DiffObjectReferenceLists returns lists containing the items unique to each provided list:
//   list1Only = list1 - list2
//   list2Only = list2 - list1
// if both returned lists are empty, the provided lists are equal
func DiffObjectReferenceLists(list1 []kapi.ObjectReference, list2 []kapi.ObjectReference) (list1Only []kapi.ObjectReference, list2Only []kapi.ObjectReference) {
	for _, list1Item := range list1 {
		if !contains(list2, list1Item) {
			if !contains(list1Only, list1Item) {
				list1Only = append(list1Only, list1Item)
			}
		}
	}
	for _, list2Item := range list2 {
		if !contains(list1, list2Item) {
			if !contains(list2Only, list2Item) {
				list2Only = append(list2Only, list2Item)
			}
		}
	}
	return
}

func NewClusterRoleBindingLookupError(rolesNotFound []string) error {
	return &clusterRoleBindingLookupError{
		rolesNotFound: rolesNotFound,
	}
}

type clusterRoleBindingLookupError struct {
	rolesNotFound []string
}

func (e *clusterRoleBindingLookupError) Error() string {
	return fmt.Sprintf("did not find requested cluster roles: %s", strings.Join(e.rolesNotFound, ", "))
}

func IsClusterRoleBindingLookupError(err error) bool {
	if err == nil {
		return false
	}

	_, ok := err.(*clusterRoleBindingLookupError)
	return ok
}
<commit_msg>Fix panic in rolebinding reconcile error message<commit_after>package policy

import (
	"errors"
	"fmt"
	"io"
	"strings"

	"github.com/spf13/cobra"

	kapi "k8s.io/kubernetes/pkg/api"
	kapierrors "k8s.io/kubernetes/pkg/api/errors"
	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	kutilerrors "k8s.io/kubernetes/pkg/util/errors"
	"k8s.io/kubernetes/pkg/util/sets"

	authorizationapi "github.com/openshift/origin/pkg/authorization/api"
	"github.com/openshift/origin/pkg/client"
	"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy"
	cmdutil "github.com/openshift/origin/pkg/cmd/util"
	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
	uservalidation "github.com/openshift/origin/pkg/user/api/validation"
)

// ReconcileClusterRoleBindingsRecommendedName is the recommended command name
const ReconcileClusterRoleBindingsRecommendedName = "reconcile-cluster-role-bindings"

// ReconcileClusterRoleBindingsOptions contains all the necessary functionality for the OpenShift cli reconcile-cluster-role-bindings command
type ReconcileClusterRoleBindingsOptions struct {
	// RolesToReconcile says which roles should have their default bindings reconciled.
	// An empty or nil slice means reconcile all of them.
	RolesToReconcile []string

	Confirmed bool
	Union     bool

	ExcludeSubjects []kapi.ObjectReference

	Out    io.Writer
	Err    io.Writer
	Output string

	RoleBindingClient client.ClusterRoleBindingInterface
}

const (
	reconcileBindingsLong = `
Update cluster role bindings to match the recommended bootstrap policy

This command will inspect the cluster role bindings against the recommended bootstrap policy.
Any cluster role binding that does not match will be replaced by the recommended bootstrap role binding.
This command will not remove any additional cluster role bindings.

You can see which recommended cluster role bindings have changed by choosing an output type.`

	reconcileBindingsExample = `  # Display the names of cluster role bindings that would be modified
  %[1]s -o name

  # Display the cluster role bindings that would be modified, removing any extra subjects
  %[1]s --additive-only=false

  # Update cluster role bindings that don't match the current defaults
  %[1]s --confirm

  # Update cluster role bindings that don't match the current defaults, avoid adding roles to the system:authenticated group
  %[1]s --confirm --exclude-groups=system:authenticated

  # Update cluster role bindings that don't match the current defaults, removing any extra subjects from the binding
  %[1]s --confirm --additive-only=false`
)

// NewCmdReconcileClusterRoleBindings implements the OpenShift cli reconcile-cluster-role-bindings command
func NewCmdReconcileClusterRoleBindings(name, fullName string, f *clientcmd.Factory, out, err io.Writer) *cobra.Command {
	o := &ReconcileClusterRoleBindingsOptions{
		Out:   out,
		Err:   err,
		Union: true,
	}

	excludeUsers := []string{}
	excludeGroups := []string{}

	cmd := &cobra.Command{
		Use:     name + " [ClusterRoleName]...",
		Short:   "Update cluster role bindings to match the recommended bootstrap policy",
		Long:    reconcileBindingsLong,
		Example: fmt.Sprintf(reconcileBindingsExample, fullName),
		Run: func(cmd *cobra.Command, args []string) {
			if err := o.Complete(cmd, f, args, excludeUsers, excludeGroups); err != nil {
				kcmdutil.CheckErr(err)
			}

			if err := o.Validate(); err != nil {
				kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error()))
			}

			if err := o.RunReconcileClusterRoleBindings(cmd, f); err != nil {
				kcmdutil.CheckErr(err)
			}
		},
	}

	cmd.Flags().BoolVar(&o.Confirmed, "confirm", o.Confirmed, "Specify that cluster role bindings should be modified. Defaults to false, displaying what would be replaced but not actually replacing anything.")
	cmd.Flags().BoolVar(&o.Union, "additive-only", o.Union, "Preserves extra subjects in cluster role bindings.")
	cmd.Flags().StringSliceVar(&excludeUsers, "exclude-users", excludeUsers, "Do not add cluster role bindings for these user names.")
	cmd.Flags().StringSliceVar(&excludeGroups, "exclude-groups", excludeGroups, "Do not add cluster role bindings for these group names.")
	kcmdutil.AddPrinterFlags(cmd)
	cmd.Flags().Lookup("output").DefValue = "yaml"
	cmd.Flags().Lookup("output").Value.Set("yaml")

	return cmd
}

func (o *ReconcileClusterRoleBindingsOptions) Complete(cmd *cobra.Command, f *clientcmd.Factory, args []string, excludeUsers, excludeGroups []string) error {
	oclient, _, err := f.Clients()
	if err != nil {
		return err
	}
	o.RoleBindingClient = oclient.ClusterRoleBindings()

	o.Output = kcmdutil.GetFlagString(cmd, "output")

	o.ExcludeSubjects = authorizationapi.BuildSubjects(excludeUsers, excludeGroups, uservalidation.ValidateUserName, uservalidation.ValidateGroupName)

	mapper, _ := f.Object(false)
	for _, resourceString := range args {
		resource, name, err := cmdutil.ResolveResource(authorizationapi.Resource("clusterroles"), resourceString, mapper)
		if err != nil {
			return err
		}
		if resource != authorizationapi.Resource("clusterroles") {
			return fmt.Errorf("%v is not a valid resource type for this command", resource)
		}
		if len(name) == 0 {
			return fmt.Errorf("%s did not contain a name", resourceString)
		}

		o.RolesToReconcile = append(o.RolesToReconcile, name)
	}

	return nil
}

func (o *ReconcileClusterRoleBindingsOptions) Validate() error {
	if o.RoleBindingClient == nil {
		return errors.New("a role binding client is required")
	}
	return nil
}

func (o *ReconcileClusterRoleBindingsOptions) RunReconcileClusterRoleBindings(cmd *cobra.Command, f *clientcmd.Factory) error {
	changedClusterRoleBindings, fetchErr := o.ChangedClusterRoleBindings()
	if fetchErr != nil && !IsClusterRoleBindingLookupError(fetchErr) {
		// we got an error that isn't due to a partial match, so we can't continue
		return fetchErr
	}

	if len(changedClusterRoleBindings) == 0 {
		return fetchErr
	}

	errs := []error{}
	if fetchErr != nil {
		errs = append(errs, fetchErr)
	}

	if (len(o.Output) != 0) && !o.Confirmed {
		list := &kapi.List{}
		for _, item := range changedClusterRoleBindings {
			list.Items = append(list.Items, item)
		}
		mapper, _ := f.Object(false)
		fn := cmdutil.VersionedPrintObject(f.PrintObject, cmd, mapper, o.Out)
		if err := fn(list); err != nil {
			errs = append(errs, err)
			return kutilerrors.NewAggregate(errs)
		}
	}

	if o.Confirmed {
		if err := o.ReplaceChangedRoleBindings(changedClusterRoleBindings); err != nil {
			errs = append(errs, err)
			return kutilerrors.NewAggregate(errs)
		}
	}

	return fetchErr
}

// ChangedClusterRoleBindings returns the role bindings that must be created and/or updated to
// match the recommended bootstrap policy. If roles to reconcile are provided, but not all are
// found, all partial results are returned.
func (o *ReconcileClusterRoleBindingsOptions) ChangedClusterRoleBindings() ([]*authorizationapi.ClusterRoleBinding, error) {
	changedRoleBindings := []*authorizationapi.ClusterRoleBinding{}

	rolesToReconcile := sets.NewString(o.RolesToReconcile...)
	rolesNotFound := sets.NewString(o.RolesToReconcile...)
	bootstrapClusterRoleBindings := bootstrappolicy.GetBootstrapClusterRoleBindings()
	for i := range bootstrapClusterRoleBindings {
		expectedClusterRoleBinding := &bootstrapClusterRoleBindings[i]
		if (len(rolesToReconcile) > 0) && !rolesToReconcile.Has(expectedClusterRoleBinding.RoleRef.Name) {
			continue
		}
		rolesNotFound.Delete(expectedClusterRoleBinding.RoleRef.Name)

		actualClusterRoleBinding, err := o.RoleBindingClient.Get(expectedClusterRoleBinding.Name)
		if kapierrors.IsNotFound(err) {
			// Remove excluded subjects from the new role binding
			expectedClusterRoleBinding.Subjects, _ = DiffObjectReferenceLists(expectedClusterRoleBinding.Subjects, o.ExcludeSubjects)
			changedRoleBindings = append(changedRoleBindings, expectedClusterRoleBinding)
			continue
		}
		if err != nil {
			return nil, err
		}

		// Copy any existing labels/annotations, so the displayed update is correct
		// This assumes bootstrap role bindings will not set any labels/annotations
		// These aren't actually used during update; the latest labels/annotations are pulled from the existing object again
		expectedClusterRoleBinding.Labels = actualClusterRoleBinding.Labels
		expectedClusterRoleBinding.Annotations = actualClusterRoleBinding.Annotations

		if updatedClusterRoleBinding, needsUpdating := computeUpdatedBinding(*expectedClusterRoleBinding, *actualClusterRoleBinding, o.ExcludeSubjects, o.Union); needsUpdating {
			changedRoleBindings = append(changedRoleBindings, updatedClusterRoleBinding)
		}
	}

	if len(rolesNotFound) != 0 {
		// return the known changes and the error so that a caller can decide if he wants a partial update
		return changedRoleBindings, NewClusterRoleBindingLookupError(rolesNotFound.List())
	}

	return changedRoleBindings, nil
}

// ReplaceChangedRoleBindings will reconcile all the changed system role bindings back to the recommended bootstrap policy
func (o *ReconcileClusterRoleBindingsOptions) ReplaceChangedRoleBindings(changedRoleBindings []*authorizationapi.ClusterRoleBinding) error {
	for i := range changedRoleBindings {
		roleBinding, err := o.RoleBindingClient.Get(changedRoleBindings[i].Name)
		if err != nil && !kapierrors.IsNotFound(err) {
			return err
		}

		if kapierrors.IsNotFound(err) {
			createdRoleBinding, err := o.RoleBindingClient.Create(changedRoleBindings[i])
			if err != nil {
				return err
			}

			fmt.Fprintf(o.Out, "clusterrolebinding/%s\n", createdRoleBinding.Name)
			continue
		}

		// RoleRef is immutable, to reset this, we have to delete/recreate
		if !kapi.Semantic.DeepEqual(roleBinding.RoleRef, changedRoleBindings[i].RoleRef) {
			roleBinding.RoleRef = changedRoleBindings[i].RoleRef
			roleBinding.Subjects = changedRoleBindings[i].Subjects

			// TODO: for extra credit, determine whether the right to delete/create this rolebinding for the current user came from this rolebinding before deleting it
			err := o.RoleBindingClient.Delete(roleBinding.Name)
			if err != nil {
				return err
			}
			createdRoleBinding, err := o.RoleBindingClient.Create(changedRoleBindings[i])
			if err != nil {
				return err
			}
			fmt.Fprintf(o.Out, "clusterrolebinding/%s\n", createdRoleBinding.Name)
			continue
		}

		roleBinding.Subjects = changedRoleBindings[i].Subjects
		updatedRoleBinding, err := o.RoleBindingClient.Update(roleBinding)
		if err != nil {
			return err
		}

		fmt.Fprintf(o.Out, "clusterrolebinding/%s\n", updatedRoleBinding.Name)
	}

	return nil
}

func computeUpdatedBinding(expected authorizationapi.ClusterRoleBinding, actual authorizationapi.ClusterRoleBinding, excludeSubjects []kapi.ObjectReference, union bool) (*authorizationapi.ClusterRoleBinding, bool) {
	needsUpdating := false

	// Always reset the roleref if it is different
	if !kapi.Semantic.DeepEqual(expected.RoleRef, actual.RoleRef) {
		needsUpdating = true
	}

	// compute the list of subjects we should not add roles for (existing subjects in the exclude list should be preserved)
	doNotAddSubjects, _ := DiffObjectReferenceLists(excludeSubjects, actual.Subjects)
	// remove any excluded subjects that do not exist from our expected subject list (so we don't add them)
	expectedSubjects, _ := DiffObjectReferenceLists(expected.Subjects, doNotAddSubjects)

	missingSubjects, extraSubjects := DiffObjectReferenceLists(expectedSubjects, actual.Subjects)
	// Always add missing expected subjects
	if len(missingSubjects) > 0 {
		needsUpdating = true
	}
	// extra subjects only require a change if we're not unioning
	if len(extraSubjects) > 0 && !union {
		needsUpdating = true
	}

	if !needsUpdating {
		return nil, false
	}

	updated := expected
	updated.Subjects = expectedSubjects
	if union {
		updated.Subjects = append(updated.Subjects, extraSubjects...)
	}
	return &updated, true
}

func contains(list []kapi.ObjectReference, item kapi.ObjectReference) bool {
	for _, listItem := range list {
		if kapi.Semantic.DeepEqual(listItem, item) {
			return true
		}
	}
	return false
}

// DiffObjectReferenceLists returns lists containing the items unique to each provided list:
//   list1Only = list1 - list2
//   list2Only = list2 - list1
// if both returned lists are empty, the provided lists are equal
func DiffObjectReferenceLists(list1 []kapi.ObjectReference, list2 []kapi.ObjectReference) (list1Only []kapi.ObjectReference, list2Only []kapi.ObjectReference) {
	for _, list1Item := range list1 {
		if !contains(list2, list1Item) {
			if !contains(list1Only, list1Item) {
				list1Only = append(list1Only, list1Item)
			}
		}
	}
	for _, list2Item := range list2 {
		if !contains(list1, list2Item) {
			if !contains(list2Only, list2Item) {
				list2Only = append(list2Only, list2Item)
			}
		}
	}
	return
}

func NewClusterRoleBindingLookupError(rolesNotFound []string) error {
	return &clusterRoleBindingLookupError{
		rolesNotFound: rolesNotFound,
	}
}

type clusterRoleBindingLookupError struct {
	rolesNotFound []string
}

func (e *clusterRoleBindingLookupError) Error() string {
	return fmt.Sprintf("did not find requested cluster roles: %s", strings.Join(e.rolesNotFound, ", "))
}

func IsClusterRoleBindingLookupError(err error) bool {
	if err == nil {
		return false
	}

	_, ok := err.(*clusterRoleBindingLookupError)
	return ok
}
<|endoftext|>


<commit_before>package ualert

import (
	"encoding/json"
	"fmt"
	"time"

	"github.com/grafana/grafana/pkg/expr"
	ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
	"github.com/grafana/grafana/pkg/tsdb/graphite"
	"github.com/grafana/grafana/pkg/util"
)

type alertRule struct {
	OrgID           int64 `xorm:"org_id"`
	Title           string
	Condition       string
	Data            []alertQuery
	IntervalSeconds int64
	Version         int64
	UID             string `xorm:"uid"`
	NamespaceUID    string `xorm:"namespace_uid"`
	RuleGroup       string
	NoDataState     string
	ExecErrState    string
	For             duration
	Updated         time.Time
	Annotations     map[string]string
	Labels          map[string]string // (Labels are not Created in the migration)
}

type alertRuleVersion struct {
	RuleOrgID        int64  `xorm:"rule_org_id"`
	RuleUID          string `xorm:"rule_uid"`
	RuleNamespaceUID string `xorm:"rule_namespace_uid"`
	RuleGroup        string
	ParentVersion    int64
	RestoredFrom     int64
	Version          int64

	Created         time.Time
	Title           string
	Condition       string
	Data            []alertQuery
	IntervalSeconds int64
	NoDataState     string
	ExecErrState    string
	// ideally this field should have been apimodels.ApiDuration
	// but this is currently not possible because of circular dependencies
	For         duration
	Annotations map[string]string
	Labels      map[string]string
}

func (a *alertRule) makeVersion() *alertRuleVersion {
	return &alertRuleVersion{
		RuleOrgID:        a.OrgID,
		RuleUID:          a.UID,
		RuleNamespaceUID: a.NamespaceUID,
		RuleGroup:        a.RuleGroup,
		ParentVersion:    0,
		RestoredFrom:     0,
		Version:          1,

		Created:         time.Now().UTC(),
		Title:           a.Title,
		Condition:       a.Condition,
		Data:            a.Data,
		IntervalSeconds: a.IntervalSeconds,
		NoDataState:     a.NoDataState,
		ExecErrState:    a.ExecErrState,
		For:             a.For,
		Annotations:     a.Annotations,
		Labels:          map[string]string{},
	}
}

func addMigrationInfo(da *dashAlert) (map[string]string, map[string]string) {
	lbls := da.ParsedSettings.AlertRuleTags
	if lbls == nil {
		lbls = make(map[string]string)
	}

	annotations := make(map[string]string, 3)
	annotations[ngmodels.DashboardUIDAnnotation] = da.DashboardUID
	annotations[ngmodels.PanelIDAnnotation] = fmt.Sprintf("%v", da.PanelId)
	annotations["__alertId__"] = fmt.Sprintf("%v", da.Id)

	return lbls, annotations
}

func (m *migration) makeAlertRule(cond condition, da dashAlert, folderUID string) (*alertRule, error) {
	lbls, annotations := addMigrationInfo(&da)
	lbls["alertname"] = da.Name
	annotations["message"] = da.Message
	var err error

	data, err := migrateAlertRuleQueries(cond.Data)
	if err != nil {
		return nil, fmt.Errorf("failed to migrate alert rule queries: %w", err)
	}

	ar := &alertRule{
		OrgID:           da.OrgId,
		Title:           da.Name, // TODO: Make sure all names are unique, make new name on constraint insert error.
		UID:             util.GenerateShortUID(),
		Condition:       cond.Condition,
		Data:            data,
		IntervalSeconds: ruleAdjustInterval(da.Frequency),
		Version:         1,
		NamespaceUID:    folderUID, // Folder already created, comes from env var.
		RuleGroup:       da.Name,
		For:             duration(da.For),
		Updated:         time.Now().UTC(),
		Annotations:     annotations,
		Labels:          lbls,
	}

	ar.NoDataState, err = transNoData(da.ParsedSettings.NoDataState)
	if err != nil {
		return nil, err
	}

	ar.ExecErrState, err = transExecErr(da.ParsedSettings.ExecutionErrorState)
	if err != nil {
		return nil, err
	}

	// Label for routing and silences.
	n, v := getLabelForRouteMatching(ar.UID)
	ar.Labels[n] = v

	if err := m.addSilence(da, ar); err != nil {
		m.mg.Logger.Error("alert migration error: failed to create silence", "rule_name", ar.Title, "err", err)
	}

	if err := m.addErrorSilence(da, ar); err != nil {
		m.mg.Logger.Error("alert migration error: failed to create silence for Error", "rule_name", ar.Title, "err", err)
	}

	if err := m.addNoDataSilence(da, ar); err != nil {
		m.mg.Logger.Error("alert migration error: failed to create silence for NoData", "rule_name", ar.Title, "err", err)
	}

	return ar, nil
}

// migrateAlertRuleQueries attempts to fix alert rule queries so they can work in unified alerting. Queries of some data sources are not compatible with unified alerting.
func migrateAlertRuleQueries(data []alertQuery) ([]alertQuery, error) {
	result := make([]alertQuery, 0, len(data))
	for _, d := range data {
		// queries that are expression are not relevant, skip them.
		if d.DatasourceUID == expr.OldDatasourceUID {
			result = append(result, d)
			continue
		}
		var fixedData map[string]json.RawMessage
		err := json.Unmarshal(d.Model, &fixedData)
		if err != nil {
			return nil, err
		}
		fixedData = fixGraphiteReferencedSubQueries(fixedData)
		updatedModel, err := json.Marshal(fixedData)
		if err != nil {
			return nil, err
		}
		d.Model = updatedModel
		result = append(result, d)
	}
	return result, nil
}

// fixGraphiteReferencedSubQueries attempts to fix graphite referenced sub queries, given unified alerting does not support this.
// targetFull of Graphite data source contains the expanded version of field 'target', so let's copy that.
func fixGraphiteReferencedSubQueries(queryData map[string]json.RawMessage) map[string]json.RawMessage {
	fullQuery, ok := queryData[graphite.TargetFullModelField]
	if ok {
		delete(queryData, graphite.TargetFullModelField)
		queryData[graphite.TargetModelField] = fullQuery
	}

	return queryData
}

type alertQuery struct {
	// RefID is the unique identifier of the query, set by the frontend call.
	RefID string `json:"refId"`

	// QueryType is an optional identifier for the type of query.
	// It can be used to distinguish different types of queries.
	QueryType string `json:"queryType"`

	// RelativeTimeRange is the relative Start and End of the query as sent by the frontend.
	RelativeTimeRange relativeTimeRange `json:"relativeTimeRange"`

	DatasourceUID string `json:"datasourceUid"`

	// JSON is the raw JSON query and includes the above properties as well as custom properties.
	Model json.RawMessage `json:"model"`
}

// RelativeTimeRange is the per query start and end time
// for requests.
type relativeTimeRange struct {
	From duration `json:"from"`
	To   duration `json:"to"`
}

// duration is a type used for marshalling durations.
type duration time.Duration

func (d duration) String() string {
	return time.Duration(d).String()
}

func (d duration) MarshalJSON() ([]byte, error) {
	return json.Marshal(time.Duration(d).Seconds())
}

func (d *duration) UnmarshalJSON(b []byte) error {
	var v interface{}
	if err := json.Unmarshal(b, &v); err != nil {
		return err
	}
	switch value := v.(type) {
	case float64:
		*d = duration(time.Duration(value) * time.Second)
		return nil
	default:
		return fmt.Errorf("invalid duration %v", v)
	}
}

func ruleAdjustInterval(freq int64) int64 {
	// 10 corresponds to the SchedulerCfg, but TODO not worrying about fetching for now.
	var baseFreq int64 = 10
	if freq <= baseFreq {
		return 10
	}
	return freq - (freq % baseFreq)
}

func transNoData(s string) (string, error) {
	switch s {
	case "ok":
		return "OK", nil // values from ngalert/models/rule
	case "", "no_data":
		return "NoData", nil
	case "alerting":
		return "Alerting", nil
	case "keep_state":
		return "NoData", nil // "keep last state" translates to no data because we now emit a special alert when the state is "noData". The result is that the evaluation will not return firing and instead we'll raise the special alert.
	}
	return "", fmt.Errorf("unrecognized No Data setting %v", s)
}

func transExecErr(s string) (string, error) {
	switch s {
	case "", "alerting":
		return "Alerting", nil
	case "keep_state":
		// Keep last state is translated to error as we now emit a
		// DatasourceError alert when the state is error
		return "Error", nil
	}
	return "", fmt.Errorf("unrecognized Execution Error setting %v", s)
}
<commit_msg>Alerting: support ok state in alert migration (#45264)<commit_after>package ualert

import (
	"encoding/json"
	"fmt"
	"time"

	"github.com/grafana/grafana/pkg/expr"
	ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
	"github.com/grafana/grafana/pkg/tsdb/graphite"
	"github.com/grafana/grafana/pkg/util"
)

type alertRule struct {
	OrgID           int64 `xorm:"org_id"`
	Title           string
	Condition       string
	Data            []alertQuery
	IntervalSeconds int64
	Version         int64
	UID             string `xorm:"uid"`
	NamespaceUID    string `xorm:"namespace_uid"`
	RuleGroup       string
	NoDataState     string
	ExecErrState    string
	For             duration
	Updated         time.Time
	Annotations     map[string]string
	Labels          map[string]string // (Labels are not Created in the migration)
}

type alertRuleVersion struct {
	RuleOrgID        int64  `xorm:"rule_org_id"`
	RuleUID          string `xorm:"rule_uid"`
	RuleNamespaceUID string `xorm:"rule_namespace_uid"`
	RuleGroup        string
	ParentVersion    int64
	RestoredFrom     int64
	Version          int64

	Created         time.Time
	Title           string
	Condition       string
	Data            []alertQuery
	IntervalSeconds int64
	NoDataState     string
	ExecErrState    string
	// ideally this field should have been apimodels.ApiDuration
	// but this is currently not possible because of circular dependencies
	For         duration
	Annotations map[string]string
	Labels      map[string]string
}

func (a *alertRule) makeVersion() *alertRuleVersion {
	return &alertRuleVersion{
		RuleOrgID:        a.OrgID,
		RuleUID:          a.UID,
		RuleNamespaceUID: a.NamespaceUID,
		RuleGroup:        a.RuleGroup,
		ParentVersion:    0,
		RestoredFrom:     0,
		Version:          1,

		Created:         time.Now().UTC(),
		Title:           a.Title,
		Condition:       a.Condition,
		Data:            a.Data,
		IntervalSeconds: a.IntervalSeconds,
		NoDataState:     a.NoDataState,
		ExecErrState:    a.ExecErrState,
		For:             a.For,
		Annotations:     a.Annotations,
		Labels:          map[string]string{},
	}
}

func addMigrationInfo(da *dashAlert) (map[string]string, map[string]string) {
	lbls := da.ParsedSettings.AlertRuleTags
	if lbls == nil {
		lbls = make(map[string]string)
	}

	annotations := make(map[string]string, 3)
	annotations[ngmodels.DashboardUIDAnnotation] = da.DashboardUID
	annotations[ngmodels.PanelIDAnnotation] = fmt.Sprintf("%v", da.PanelId)
	annotations["__alertId__"] = fmt.Sprintf("%v", da.Id)

	return lbls, annotations
}

func (m *migration) makeAlertRule(cond condition, da dashAlert, folderUID string) (*alertRule, error) {
	lbls, annotations := addMigrationInfo(&da)
	lbls["alertname"] = da.Name
	annotations["message"] = da.Message
	var err error

	data, err := migrateAlertRuleQueries(cond.Data)
	if err != nil {
		return nil, fmt.Errorf("failed to migrate alert rule queries: %w", err)
	}

	ar := &alertRule{
		OrgID:           da.OrgId,
		Title:           da.Name, // TODO: Make sure all names are unique, make new name on constraint insert error.
		UID:             util.GenerateShortUID(),
		Condition:       cond.Condition,
		Data:            data,
		IntervalSeconds: ruleAdjustInterval(da.Frequency),
		Version:         1,
		NamespaceUID:    folderUID, // Folder already created, comes from env var.
		RuleGroup:       da.Name,
		For:             duration(da.For),
		Updated:         time.Now().UTC(),
		Annotations:     annotations,
		Labels:          lbls,
	}

	ar.NoDataState, err = transNoData(da.ParsedSettings.NoDataState)
	if err != nil {
		return nil, err
	}

	ar.ExecErrState, err = transExecErr(da.ParsedSettings.ExecutionErrorState)
	if err != nil {
		return nil, err
	}

	// Label for routing and silences.
	n, v := getLabelForRouteMatching(ar.UID)
	ar.Labels[n] = v

	if err := m.addSilence(da, ar); err != nil {
		m.mg.Logger.Error("alert migration error: failed to create silence", "rule_name", ar.Title, "err", err)
	}

	if err := m.addErrorSilence(da, ar); err != nil {
		m.mg.Logger.Error("alert migration error: failed to create silence for Error", "rule_name", ar.Title, "err", err)
	}

	if err := m.addNoDataSilence(da, ar); err != nil {
		m.mg.Logger.Error("alert migration error: failed to create silence for NoData", "rule_name", ar.Title, "err", err)
	}

	return ar, nil
}

// migrateAlertRuleQueries attempts to fix alert rule queries so they can work in unified alerting. Queries of some data sources are not compatible with unified alerting.
func migrateAlertRuleQueries(data []alertQuery) ([]alertQuery, error) {
	result := make([]alertQuery, 0, len(data))
	for _, d := range data {
		// queries that are expression are not relevant, skip them.
		if d.DatasourceUID == expr.OldDatasourceUID {
			result = append(result, d)
			continue
		}
		var fixedData map[string]json.RawMessage
		err := json.Unmarshal(d.Model, &fixedData)
		if err != nil {
			return nil, err
		}
		fixedData = fixGraphiteReferencedSubQueries(fixedData)
		updatedModel, err := json.Marshal(fixedData)
		if err != nil {
			return nil, err
		}
		d.Model = updatedModel
		result = append(result, d)
	}
	return result, nil
}

// fixGraphiteReferencedSubQueries attempts to fix graphite referenced sub queries, given unified alerting does not support this.
// targetFull of Graphite data source contains the expanded version of field 'target', so let's copy that.
func fixGraphiteReferencedSubQueries(queryData map[string]json.RawMessage) map[string]json.RawMessage {
	fullQuery, ok := queryData[graphite.TargetFullModelField]
	if ok {
		delete(queryData, graphite.TargetFullModelField)
		queryData[graphite.TargetModelField] = fullQuery
	}

	return queryData
}

type alertQuery struct {
	// RefID is the unique identifier of the query, set by the frontend call.
	RefID string `json:"refId"`

	// QueryType is an optional identifier for the type of query.
	// It can be used to distinguish different types of queries.
	QueryType string `json:"queryType"`

	// RelativeTimeRange is the relative Start and End of the query as sent by the frontend.
	RelativeTimeRange relativeTimeRange `json:"relativeTimeRange"`

	DatasourceUID string `json:"datasourceUid"`

	// JSON is the raw JSON query and includes the above properties as well as custom properties.
	Model json.RawMessage `json:"model"`
}

// RelativeTimeRange is the per query start and end time
// for requests.
type relativeTimeRange struct {
	From duration `json:"from"`
	To   duration `json:"to"`
}

// duration is a type used for marshalling durations.
type duration time.Duration

func (d duration) String() string {
	return time.Duration(d).String()
}

func (d duration) MarshalJSON() ([]byte, error) {
	return json.Marshal(time.Duration(d).Seconds())
}

func (d *duration) UnmarshalJSON(b []byte) error {
	var v interface{}
	if err := json.Unmarshal(b, &v); err != nil {
		return err
	}
	switch value := v.(type) {
	case float64:
		*d = duration(time.Duration(value) * time.Second)
		return nil
	default:
		return fmt.Errorf("invalid duration %v", v)
	}
}

func ruleAdjustInterval(freq int64) int64 {
	// 10 corresponds to the SchedulerCfg, but TODO not worrying about fetching for now.
	var baseFreq int64 = 10
	if freq <= baseFreq {
		return 10
	}
	return freq - (freq % baseFreq)
}

func transNoData(s string) (string, error) {
	switch s {
	case "ok":
		return "OK", nil // values from ngalert/models/rule
	case "", "no_data":
		return "NoData", nil
	case "alerting":
		return "Alerting", nil
	case "keep_state":
		return "NoData", nil // "keep last state" translates to no data because we now emit a special alert when the state is "noData". The result is that the evaluation will not return firing and instead we'll raise the special alert.
	}
	return "", fmt.Errorf("unrecognized No Data setting %v", s)
}

func transExecErr(s string) (string, error) {
	switch s {
	case "", "alerting":
		return "Alerting", nil
	case "keep_state":
		// Keep last state is translated to error as we now emit a
		// DatasourceError alert when the state is error
		return "Error", nil
	case "ok":
		return "OK", nil
	}
	return "", fmt.Errorf("unrecognized Execution Error setting %v", s)
}
<|endoftext|>


<commit_before>package imgscale

import (
	"fmt"
	"net/http"
	"regexp"
	"strconv"
)

var supportedExts = map[string]string{"jpg": "image/jpeg", "png": "image/png"}

type Handler interface {
	// http.Handler
	ServeHTTP(res http.ResponseWriter, req *http.Request)
	// http.HandleFunc
	HandleFunc(res http.ResponseWriter, req *http.Request)
}

type handler struct {
	config        *Config
	formats       map[string]*Format
	regexp        *regexp.Regexp
	supportedExts map[string]string
}

func (h *handler) match(url string) (bool, *ImageInfo) {
	matches := h.regexp.FindStringSubmatch(url)

	if len(matches) == 0 {
		return false, nil
	}

	return true, h.getImageInfo(matches[1], matches[2], matches[3])
}

func (h *handler) getContentType(ext string) string {
	return h.supportedExts[ext]
}

func (h *handler) getFormat(format string) *Format {
	return h.formats[format]
}

func (h *handler) getImageInfo(format, filename, ext string) *ImageInfo {
	f := h.getFormat(format)
	return &ImageInfo{fmt.Sprintf("%s/%s.%s", h.config.Path, filename, ext), f, ext, h.config.Comment}
}

func (h *handler) serve(res http.ResponseWriter, req *http.Request, info *ImageInfo) {
	img, err := GetImage(info)
	defer img.Destroy()
	if err == nil {
		imgData := img.GetImageBlob()
		res.Header().Set("Content-Type", h.getContentType(info.Ext))
		res.Header().Set("Content-Length", strconv.Itoa(len(imgData)))
		res.Write(imgData)
	}
}

func (h *handler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
	if req.Method != "GET" && req.Method != "HEAD" {
		return
	}
	matched, info := h.match(req.URL.RequestURI())
	if !matched {
		return
	}
	h.serve(res, req, info)
}

func (h *handler) HandleFunc(res http.ResponseWriter, req *http.Request) {
	if req.Method != "GET" && req.Method != "HEAD" {
		return
	}
	matched, info := h.match(req.URL.RequestURI())
	if !matched {
		return
	}
	h.serve(res, req, info)
}
<commit_msg>ServeHTTP and HandleFunc should probably always do the same thing for our case.<commit_after>package imgscale

import (
	"fmt"
	"net/http"
	"regexp"
	"strconv"
)

var supportedExts = map[string]string{"jpg": "image/jpeg", "png": "image/png"}

type Handler interface {
	// http.Handler
	ServeHTTP(res http.ResponseWriter, req *http.Request)
	// http.HandleFunc
	HandleFunc(res http.ResponseWriter, req *http.Request)
}

type handler struct {
	config        *Config
	formats       map[string]*Format
	regexp        *regexp.Regexp
	supportedExts map[string]string
}

func (h *handler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
	h.handle(res, req)
}

func (h *handler) HandleFunc(res http.ResponseWriter, req *http.Request) {
	h.handle(res, req)
}

func (h *handler) match(url string) (bool, *ImageInfo) {
	matches := h.regexp.FindStringSubmatch(url)

	if len(matches) == 0 {
		return false, nil
	}

	return true, h.getImageInfo(matches[1], matches[2], matches[3])
}

func (h *handler) getContentType(ext string) string {
	return h.supportedExts[ext]
}

func (h *handler) getFormat(format string) *Format {
	return h.formats[format]
}

func (h *handler) getImageInfo(format, filename, ext string) *ImageInfo {
	f := h.getFormat(format)
	return &ImageInfo{fmt.Sprintf("%s/%s.%s", h.config.Path, filename, ext), f, ext, h.config.Comment}
}

func (h *handler) serve(res http.ResponseWriter, req *http.Request, info *ImageInfo) {
	img, err := GetImage(info)
	defer img.Destroy()
	if err == nil {
		imgData := img.GetImageBlob()
		res.Header().Set("Content-Type", h.getContentType(info.Ext))
		res.Header().Set("Content-Length", strconv.Itoa(len(imgData)))
		res.Write(imgData)
	}
}

func (h *handler) handle(res http.ResponseWriter, req *http.Request) {
	if req.Method != "GET" && req.Method != "HEAD" {
		return
	}
	matched, info := h.match(req.URL.RequestURI())
	if !matched {
		return
	}
	h.serve(res, req, info)
}
<|endoftext|>


<commit_before>package important

import (
	"fmt"
	_ "github.com/brianm/variant" // imported solely so go get has somethign to do
)

func Greet(name string) (int, error) {
	return fmt.Printf("Hello %s\n", name)
}
<commit_msg>sound more excited<commit_after>package important

import (
	"fmt"
	_ "github.com/brianm/variant" // imported solely so go get has somethign to do
)

func Greet(name string) (int, error) {
	return fmt.Printf("Hello %s!\n", name)
}
<|endoftext|>


<commit_before>package gobot

type eventChannel chan *Event

type eventer struct {
	// map of valid Event names
	eventnames map[string]string

	// new events get put in to the event channel
	in eventChannel

	// map of out channels used by subscribers
	outs map[eventChannel]eventChannel
}

// Eventer is the interface which describes how a Driver or Adaptor
// handles events.
type Eventer interface {
	// Events returns the map of valid Event names.
	Events() (eventnames map[string]string)

	// Event returns an Event string from map of valid Event names.
	// Mostly used to validate that an Event name is valid.
	Event(name string) string

	// AddEvent registers a new Event name.
	AddEvent(name string)

	// DeleteEvent removes a previously registered Event name.
	DeleteEvent(name string)

	// Publish new events to any subscriber
	Publish(name string, data interface{})

	// Subscribe to events
	Subscribe() (events eventChannel)

	// Unsubscribe from an event channel
	Unsubscribe(events eventChannel)

	// Event handler
	On(name string, f func(s interface{})) (err error)

	// Event handler, only executes one time
	Once(name string, f func(s interface{})) (err error)
}

// NewEventer returns a new Eventer.
func NewEventer() Eventer {
	evtr := &eventer{
		eventnames: make(map[string]string),
		in:         make(eventChannel, 1),
		outs:       make(map[eventChannel]eventChannel),
	}

	// goroutine to cascade "in" events to all "out" event channels
	go func() {
		for {
			select {
			case evt := <-evtr.in:
				for _, out := range evtr.outs {
					out <- evt
				}
			}
		}
	}()

	return evtr
}

// Events returns the map of valid Event names.
func (e *eventer) Events() map[string]string {
	return e.eventnames
}

// Event returns an Event string from map of valid Event names.
// Mostly used to validate that an Event name is valid.
func (e *eventer) Event(name string) string {
	return e.eventnames[name]
}

// AddEvent registers a new Event name.
func (e *eventer) AddEvent(name string) {
	e.eventnames[name] = name
}

// DeleteEvent removes a previously registered Event name.
func (e *eventer) DeleteEvent(name string) {
	delete(e.eventnames, name)
}

// Publish new events to anyone that is subscribed
func (e *eventer) Publish(name string, data interface{}) {
	evt := NewEvent(name, data)
	e.in <- evt
}

// Subscribe to any events from this eventer
func (e *eventer) Subscribe() eventChannel {
	out := make(eventChannel)
	e.outs[out] = out
	return out
}

// Unsubscribe from the event channel
func (e *eventer) Unsubscribe(events eventChannel) {
	delete(e.outs, events)
}

// On executes the event handler f when e is Published to.
func (e *eventer) On(n string, f func(s interface{})) (err error) {
	out := e.Subscribe()
	go func() {
		for {
			select {
			case evt := <-out:
				if evt.Name == n {
					f(evt.Data)
				}
			}
		}
	}()

	return
}

// Once is similar to On except that it only executes f one time.
func (e *eventer) Once(n string, f func(s interface{})) (err error) {
	out := e.Subscribe()
	go func() {
	ProcessEvents:
		for {
			select {
			case evt := <-out:
				if evt.Name == n {
					f(evt.Data)
					e.Unsubscribe(out)
					break ProcessEvents
				}
			}
		}
	}()

	return
}
<commit_msg>Ranges over channel instead of using select<commit_after>package gobot

type eventChannel chan *Event

type eventer struct {
	// map of valid Event names
	eventnames map[string]string

	// new events get put in to the event channel
	in eventChannel

	// map of out channels used by subscribers
	outs map[eventChannel]eventChannel
}

// Eventer is the interface which describes how a Driver or Adaptor
// handles events.
type Eventer interface {
	// Events returns the map of valid Event names.
	Events() (eventnames map[string]string)

	// Event returns an Event string from map of valid Event names.
	// Mostly used to validate that an Event name is valid.
	Event(name string) string

	// AddEvent registers a new Event name.
	AddEvent(name string)

	// DeleteEvent removes a previously registered Event name.
	DeleteEvent(name string)

	// Publish new events to any subscriber
	Publish(name string, data interface{})

	// Subscribe to events
	Subscribe() (events eventChannel)

	// Unsubscribe from an event channel
	Unsubscribe(events eventChannel)

	// Event handler
	On(name string, f func(s interface{})) (err error)

	// Event handler, only executes one time
	Once(name string, f func(s interface{})) (err error)
}

// NewEventer returns a new Eventer.
func NewEventer() Eventer {
	evtr := &eventer{
		eventnames: make(map[string]string),
		in:         make(eventChannel, 1),
		outs:       make(map[eventChannel]eventChannel),
	}

	// goroutine to cascade "in" events to all "out" event channels
	go func() {
		for {
			select {
			case evt := <-evtr.in:
				for _, out := range evtr.outs {
					out <- evt
				}
			}
		}
	}()

	return evtr
}

// Events returns the map of valid Event names.
func (e *eventer) Events() map[string]string {
	return e.eventnames
}

// Event returns an Event string from map of valid Event names.
// Mostly used to validate that an Event name is valid.
func (e *eventer) Event(name string) string {
	return e.eventnames[name]
}

// AddEvent registers a new Event name.
func (e *eventer) AddEvent(name string) {
	e.eventnames[name] = name
}

// DeleteEvent removes a previously registered Event name.
func (e *eventer) DeleteEvent(name string) {
	delete(e.eventnames, name)
}

// Publish new events to anyone that is subscribed
func (e *eventer) Publish(name string, data interface{}) {
	evt := NewEvent(name, data)
	e.in <- evt
}

// Subscribe to any events from this eventer
func (e *eventer) Subscribe() eventChannel {
	out := make(eventChannel)
	e.outs[out] = out
	return out
}

// Unsubscribe from the event channel
func (e *eventer) Unsubscribe(events eventChannel) {
	delete(e.outs, events)
}

// On executes the event handler f when e is Published to.
func (e *eventer) On(n string, f func(s interface{})) (err error) {
	out := e.Subscribe()
	go func() {
		for {
			select {
			case evt := <-out:
				if evt.Name == n {
					f(evt.Data)
				}
			}
		}
	}()

	return
}

// Once is similar to On except that it only executes f one time.
func (e *eventer) Once(n string, f func(s interface{})) (err error) {
	out := e.Subscribe()
	go func() {
	ProcessEvents:
		for evt := range out {
			if evt.Name == n {
				f(evt.Data)
				e.Unsubscribe(out)
				break ProcessEvents
			}
		}
	}()

	return
}
<|endoftext|>


<commit_before>package merkledag_test

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"testing"

	blockservice "github.com/jbenet/go-ipfs/blockservice"
	imp "github.com/jbenet/go-ipfs/importer"
	chunk "github.com/jbenet/go-ipfs/importer/chunk"
	. "github.com/jbenet/go-ipfs/merkledag"
	uio "github.com/jbenet/go-ipfs/unixfs/io"
	u "github.com/jbenet/go-ipfs/util"
)

func TestNode(t *testing.T) {

	n1 := &Node{Data: []byte("beep")}
	n2 := &Node{Data: []byte("boop")}
	n3 := &Node{Data: []byte("beep boop")}
	if err := n3.AddNodeLink("beep-link", n1); err != nil {
		t.Error(err)
	}
	if err := n3.AddNodeLink("boop-link", n2); err != nil {
		t.Error(err)
	}

	printn := func(name string, n *Node) {
		fmt.Println(">", name)
		fmt.Println("data:", string(n.Data))

		fmt.Println("links:")
		for _, l := range n.Links {
			fmt.Println("-", l.Name, l.Size, l.Hash)
		}

		e, err := n.Encoded(false)
		if err != nil {
			t.Error(err)
		} else {
			fmt.Println("encoded:", e)
		}

		h, err := n.Multihash()
		if err != nil {
			t.Error(err)
		} else {
			fmt.Println("hash:", h)
		}

		k, err := n.Key()
		if err != nil {
			t.Error(err)
		} else if k != u.Key(h) {
			t.Error("Key is not equivalent to multihash")
		} else {
			fmt.Println("key: ", k)
		}
	}

	printn("beep", n1)
	printn("boop", n2)
	printn("beep boop", n3)
}

func makeTestDag(t *testing.T) *Node {
	read := io.LimitReader(u.NewTimeSeededRand(), 1024*32)
	spl := &chunk.SizeSplitter{512}
	root, err := imp.NewDagFromReaderWithSplitter(read, spl)
	if err != nil {
		t.Fatal(err)
	}
	return root
}

type devZero struct{}

func (_ devZero) Read(b []byte) (int, error) {
	for i, _ := range b {
		b[i] = 0
	}
	return len(b), nil
}

func makeZeroDag(t *testing.T) *Node {
	read := io.LimitReader(devZero{}, 1024*32)
	spl := &chunk.SizeSplitter{512}
	root, err := imp.NewDagFromReaderWithSplitter(read, spl)
	if err != nil {
		t.Fatal(err)
	}
	return root
}

func TestBatchFetch(t *testing.T) {
	var dagservs []DAGService
	for _, bsi := range blockservice.Mocks(t, 5) {
		dagservs = append(dagservs, NewDAGService(bsi))
	}
	t.Log("finished setup.")

	root := makeTestDag(t)
	read, err := uio.NewDagReader(root, nil)
	if err != nil {
		t.Fatal(err)
	}
	expected, err := ioutil.ReadAll(read)
	if err != nil {
		t.Fatal(err)
	}

	err = dagservs[0].AddRecursive(root)
	if err != nil {
		t.Fatal(err)
	}

	t.Log("Added file to first node.")

	k, err := root.Key()
	if err != nil {
		t.Fatal(err)
	}

	done := make(chan struct{})
	for i := 1; i < len(dagservs); i++ {
		go func(i int) {
			first, err := dagservs[i].Get(k)
			if err != nil {
				t.Fatal(err)
			}
			fmt.Println("Got first node back.")

			read, err := uio.NewDagReader(first, dagservs[i])
			if err != nil {
				t.Fatal(err)
			}
			datagot, err := ioutil.ReadAll(read)
			if err != nil {
				t.Fatal(err)
			}

			if !bytes.Equal(datagot, expected) {
				t.Fatal("Got bad data back!")
			}
			done <- struct{}{}
		}(i)
	}

	for i := 1; i < len(dagservs); i++ {
		<-done
	}
}

func TestBatchFetchDupBlock(t *testing.T) {
	var dagservs []DAGService
	for _, bsi := range blockservice.Mocks(t, 5) {
		dagservs = append(dagservs, NewDAGService(bsi))
	}
	t.Log("finished setup.")

	root := makeZeroDag(t)
	read, err := uio.NewDagReader(root, nil)
	if err != nil {
		t.Fatal(err)
	}
	expected, err := ioutil.ReadAll(read)
	if err != nil {
		t.Fatal(err)
	}

	err = dagservs[0].AddRecursive(root)
	if err != nil {
		t.Fatal(err)
	}

	t.Log("Added file to first node.")

	k, err := root.Key()
	if err != nil {
		t.Fatal(err)
	}

	done := make(chan struct{})
	for i := 1; i < len(dagservs); i++ {
		go func(i int) {
			first, err := dagservs[i].Get(k)
			if err != nil {
				t.Fatal(err)
			}
			fmt.Println("Got first node back.")

			read, err := uio.NewDagReader(first, dagservs[i])
			if err != nil {
				t.Fatal(err)
			}
			datagot, err := ioutil.ReadAll(read)
			if err != nil {
				t.Fatal(err)
			}

			if !bytes.Equal(datagot, expected) {
				t.Fatal("Got bad data back!")
			}
			done <- struct{}{}
		}(i)
	}

	for i := 1; i < len(dagservs); i++ {
		<-done
	}
}
<commit_msg>some cleanup, use WaitGroup over channel ugliness<commit_after>package merkledag_test

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"sync"
	"testing"

	blockservice "github.com/jbenet/go-ipfs/blockservice"
	imp "github.com/jbenet/go-ipfs/importer"
	chunk "github.com/jbenet/go-ipfs/importer/chunk"
	. "github.com/jbenet/go-ipfs/merkledag"
	uio "github.com/jbenet/go-ipfs/unixfs/io"
	u "github.com/jbenet/go-ipfs/util"
)

func TestNode(t *testing.T) {

	n1 := &Node{Data: []byte("beep")}
	n2 := &Node{Data: []byte("boop")}
	n3 := &Node{Data: []byte("beep boop")}
	if err := n3.AddNodeLink("beep-link", n1); err != nil {
		t.Error(err)
	}
	if err := n3.AddNodeLink("boop-link", n2); err != nil {
		t.Error(err)
	}

	printn := func(name string, n *Node) {
		fmt.Println(">", name)
		fmt.Println("data:", string(n.Data))

		fmt.Println("links:")
		for _, l := range n.Links {
			fmt.Println("-", l.Name, l.Size, l.Hash)
		}

		e, err := n.Encoded(false)
		if err != nil {
			t.Error(err)
		} else {
			fmt.Println("encoded:", e)
		}

		h, err := n.Multihash()
		if err != nil {
			t.Error(err)
		} else {
			fmt.Println("hash:", h)
		}

		k, err := n.Key()
		if err != nil {
			t.Error(err)
		} else if k != u.Key(h) {
			t.Error("Key is not equivalent to multihash")
		} else {
			fmt.Println("key: ", k)
		}
	}

	printn("beep", n1)
	printn("boop", n2)
	printn("beep boop", n3)
}

func makeTestDag(t *testing.T) *Node {
	read := io.LimitReader(u.NewTimeSeededRand(), 1024*32)
	spl := &chunk.SizeSplitter{512}
	root, err := imp.NewDagFromReaderWithSplitter(read, spl)
	if err != nil {
		t.Fatal(err)
	}
	return root
}

type devZero struct{}

func (_ devZero) Read(b []byte) (int, error) {
	for i, _ := range b {
		b[i] = 0
	}
	return len(b), nil
}

func makeZeroDag(t *testing.T) *Node {
	read := io.LimitReader(devZero{}, 1024*32)
	spl := &chunk.SizeSplitter{512}
	root, err := imp.NewDagFromReaderWithSplitter(read, spl)
	if err != nil {
		t.Fatal(err)
	}
	return root
}

func TestBatchFetch(t *testing.T) {
	root := makeTestDag(t)
	runBatchFetchTest(t, root)
}

func TestBatchFetchDupBlock(t *testing.T) {
	root := makeZeroDag(t)
	runBatchFetchTest(t, root)
}

func runBatchFetchTest(t *testing.T, root *Node) {
	var dagservs []DAGService
	for _, bsi := range blockservice.Mocks(t, 5) {
		dagservs = append(dagservs, NewDAGService(bsi))
	}
	t.Log("finished setup.")

	read, err := uio.NewDagReader(root, nil)
	if err != nil {
		t.Fatal(err)
	}
	expected, err := ioutil.ReadAll(read)
	if err != nil {
		t.Fatal(err)
	}

	err = dagservs[0].AddRecursive(root)
	if err != nil {
		t.Fatal(err)
	}

	t.Log("Added file to first node.")

	k, err := root.Key()
	if err != nil {
		t.Fatal(err)
	}

	wg := sync.WaitGroup{}
	for i := 1; i < len(dagservs); i++ {
		wg.Add(1)
		go func(i int) {
			defer wg.Done()
			first, err := dagservs[i].Get(k)
			if err != nil {
				t.Fatal(err)
			}
			fmt.Println("Got first node back.")

			read, err := uio.NewDagReader(first, dagservs[i])
			if err != nil {
				t.Fatal(err)
			}
			datagot, err := ioutil.ReadAll(read)
			if err != nil {
				t.Fatal(err)
			}

			if !bytes.Equal(datagot, expected) {
				t.Fatal("Got bad data back!")
			}
		}(i)
	}

	wg.Done()
}
<|endoftext|>


<commit_before>// Copyright ©2014 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package fd

import (
	"math"
	"runtime"
	"sync"

	"github.com/gonum/floats"
)

// A Point is a stencil location in a difference method.
type Point struct {
	Loc   float64
	Coeff float64
}

// Method is a specific finite difference method. Method specifies the stencil,
// that is, the function locations (relative to x) which will be used to estimate
// the derivative. It also specifies the order of derivative it estimates. Order = 1
// represents the derivative, Order = 2 represents the curvature, etc.
type Method struct {
	Stencil []Point
	Order   int // The order of the difference method (first derivative, second derivative, etc.)
}

// Settings is the settings structure for computing finite differences.
type Settings struct {
	OriginKnown bool    // Flag that the value at the origin x is known
	OriginValue float64 // Value at the origin (only used if OriginKnown is true)
	Step        float64 // step size
	Concurrent  bool    // Should the function calls be executed concurrently
	Workers     int     // Maximum number of concurrent executions when evaluating concurrently
	Method      Method  // Finite difference method to use
}

// DefaultSettings is a basic set of settings for computing finite differences.
// Computes a central difference approximation for the first derivative
// of the function.
func DefaultSettings() *Settings {
	return &Settings{
		Step:    1e-6,
		Method:  Central,
		Workers: runtime.GOMAXPROCS(0),
	}
}

// Derivative estimates the derivative of the function f at the given location.
// The order of derivative, sample locations, and other options are specified
// by settings.
func Derivative(f func(float64) float64, x float64, settings *Settings) float64 {
	if settings == nil {
		settings = DefaultSettings()
	}
	var deriv float64
	method := settings.Method
	if !settings.Concurrent {
		for _, pt := range method.Stencil {
			if settings.OriginKnown && pt.Loc == 0 {
				deriv += pt.Coeff * settings.OriginValue
				continue
			}
			deriv += pt.Coeff * f(x+settings.Step*pt.Loc)
		}
		return deriv / math.Pow(settings.Step, float64(method.Order))
	}

	wg := &sync.WaitGroup{}
	mux := &sync.Mutex{}
	for _, pt := range method.Stencil {
		if settings.OriginKnown && pt.Loc == 0 {
			mux.Lock()
			deriv += pt.Coeff * settings.OriginValue
			mux.Unlock()
			continue
		}
		wg.Add(1)
		go func(pt Point) {
			defer wg.Done()
			fofx := f(x + settings.Step*pt.Loc)
			mux.Lock()
			defer mux.Unlock()
			deriv += pt.Coeff * fofx
		}(pt)
	}
	wg.Wait()
	return deriv / math.Pow(settings.Step, float64(method.Order))
}

// Gradient estimates the derivative of a vector-valued function f at the location
// x. The resulting estimate is stored in-place into gradient. The order of derivative,
// sample locations, and other options are specified by settings. Gradient panics
// if len(deriv) != len(x).
func Gradient(f func([]float64) float64, x []float64, settings *Settings, gradient []float64) {
	if len(gradient) != len(x) {
		panic("fd: location and gradient length mismatch")
	}
	if settings == nil {
		settings = DefaultSettings()
	}
	if !settings.Concurrent {
		xcopy := make([]float64, len(x)) // So that x is not modified during the call
		copy(xcopy, x)
		for i := range xcopy {
			var deriv float64
			for _, pt := range settings.Method.Stencil {
				if settings.OriginKnown && pt.Loc == 0 {
					deriv += pt.Coeff * settings.OriginValue
					continue
				}
				xcopy[i] += pt.Loc * settings.Step
				deriv += pt.Coeff * f(xcopy)
				xcopy[i] = x[i]
			}
			gradient[i] = deriv / math.Pow(settings.Step, float64(settings.Method.Order))
		}
		return
	}

	nWorkers := settings.Workers
	expect := len(settings.Method.Stencil) * len(x)
	if nWorkers > expect {
		nWorkers = expect
	}

	quit := make(chan struct{})
	defer close(quit)
	sendChan := make(chan fdrun, expect)
	ansChan := make(chan fdrun, expect)

	// Launch workers. Workers receive an index and a step, and compute the answer
	for i := 0; i < settings.Workers; i++ {
		go func(sendChan <-chan fdrun, ansChan chan<- fdrun, quit <-chan struct{}) {
			xcopy := make([]float64, len(x))
			copy(xcopy, x)
			for {
				select {
				case <-quit:
					return
				case run := <-sendChan:
					xcopy[run.idx] += run.pt.Loc * settings.Step
					run.result = f(xcopy)
					xcopy[run.idx] = x[run.idx]
					ansChan <- run
				}
			}
		}(sendChan, ansChan, quit)
	}

	// Launch the distributor. Distributor sends the cases to be computed
	go func(sendChan chan<- fdrun, ansChan chan<- fdrun) {
		for i := range x {
			for _, pt := range settings.Method.Stencil {
				if settings.OriginKnown && pt.Loc == 0 {
					// Answer already known. Send the answer on the answer channel
					ansChan <- fdrun{
						idx:    i,
						pt:     pt,
						result: settings.OriginValue,
					}
					continue
				}
				// Answer not known, send the answer to be computed
				sendChan <- fdrun{
					idx: i,
					pt:  pt,
				}
			}
		}
	}(sendChan, ansChan)

	for i := range gradient {
		gradient[i] = 0
	}
	// Read in all of the results
	for i := 0; i < expect; i++ {
		run := <-ansChan
		gradient[run.idx] += run.pt.Coeff * run.result
	}
	floats.Scale(1/math.Pow(settings.Step, float64(settings.Method.Order)), gradient)
}

type fdrun struct {
	idx    int
	pt     Point
	result float64
}

// Forward represents a first-order forward difference.
var Forward = Method{
	Stencil: []Point{{Loc: 0, Coeff: -1}, {Loc: 1, Coeff: 1}},
	Order:   1,
}

// Backward represents a first-order backward difference
var Backward = Method{
	Stencil: []Point{{Loc: -1, Coeff: -1}, {Loc: 0, Coeff: 1}},
	Order:   1,
}

// Central represents a first-order central difference.
var Central = Method{
	Stencil: []Point{{Loc: -1, Coeff: -0.5}, {Loc: 1, Coeff: 0.5}},
	Order:   1,
}

// Central2nd represents a secord-order central difference.
var Central2nd = Method{
	Stencil: []Point{{Loc: -1, Coeff: 1}, {Loc: 0, Coeff: -2}, {Loc: 1, Coeff: 1}},
	Order:   2,
}
<commit_msg>fixed Gradient documentation<commit_after>// Copyright ©2014 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package fd

import (
	"math"
	"runtime"
	"sync"

	"github.com/gonum/floats"
)

// A Point is a stencil location in a difference method.
type Point struct {
	Loc   float64
	Coeff float64
}

// Method is a specific finite difference method. Method specifies the stencil,
// that is, the function locations (relative to x) which will be used to estimate
// the derivative. It also specifies the order of derivative it estimates. Order = 1
// represents the derivative, Order = 2 represents the curvature, etc.
type Method struct {
	Stencil []Point
	Order   int // The order of the difference method (first derivative, second derivative, etc.)
}

// Settings is the settings structure for computing finite differences.
type Settings struct {
	OriginKnown bool    // Flag that the value at the origin x is known
	OriginValue float64 // Value at the origin (only used if OriginKnown is true)
	Step        float64 // step size
	Concurrent  bool    // Should the function calls be executed concurrently
	Workers     int     // Maximum number of concurrent executions when evaluating concurrently
	Method      Method  // Finite difference method to use
}

// DefaultSettings is a basic set of settings for computing finite differences.
// Computes a central difference approximation for the first derivative
// of the function.
func DefaultSettings() *Settings {
	return &Settings{
		Step:    1e-6,
		Method:  Central,
		Workers: runtime.GOMAXPROCS(0),
	}
}

// Derivative estimates the derivative of the function f at the given location.
// The order of derivative, sample locations, and other options are specified
// by settings.
func Derivative(f func(float64) float64, x float64, settings *Settings) float64 {
	if settings == nil {
		settings = DefaultSettings()
	}
	var deriv float64
	method := settings.Method
	if !settings.Concurrent {
		for _, pt := range method.Stencil {
			if settings.OriginKnown && pt.Loc == 0 {
				deriv += pt.Coeff * settings.OriginValue
				continue
			}
			deriv += pt.Coeff * f(x+settings.Step*pt.Loc)
		}
		return deriv / math.Pow(settings.Step, float64(method.Order))
	}

	wg := &sync.WaitGroup{}
	mux := &sync.Mutex{}
	for _, pt := range method.Stencil {
		if settings.OriginKnown && pt.Loc == 0 {
			mux.Lock()
			deriv += pt.Coeff * settings.OriginValue
			mux.Unlock()
			continue
		}
		wg.Add(1)
		go func(pt Point) {
			defer wg.Done()
			fofx := f(x + settings.Step*pt.Loc)
			mux.Lock()
			defer mux.Unlock()
			deriv += pt.Coeff * fofx
		}(pt)
	}
	wg.Wait()
	return deriv / math.Pow(settings.Step, float64(method.Order))
}

// Gradient estimates the derivative of a multivariate function f at the location
// x. The resulting estimate is stored in-place into gradient. The order of derivative,
// sample locations, and other options are specified by settings. Gradient panics
// if len(deriv) != len(x).
func Gradient(f func([]float64) float64, x []float64, settings *Settings, gradient []float64) {
	if len(gradient) != len(x) {
		panic("fd: location and gradient length mismatch")
	}
	if settings == nil {
		settings = DefaultSettings()
	}
	if !settings.Concurrent {
		xcopy := make([]float64, len(x)) // So that x is not modified during the call
		copy(xcopy, x)
		for i := range xcopy {
			var deriv float64
			for _, pt := range settings.Method.Stencil {
				if settings.OriginKnown && pt.Loc == 0 {
					deriv += pt.Coeff * settings.OriginValue
					continue
				}
				xcopy[i] += pt.Loc * settings.Step
				deriv += pt.Coeff * f(xcopy)
				xcopy[i] = x[i]
			}
			gradient[i] = deriv / math.Pow(settings.Step, float64(settings.Method.Order))
		}
		return
	}

	nWorkers := settings.Workers
	expect := len(settings.Method.Stencil) * len(x)
	if nWorkers > expect {
		nWorkers = expect
	}

	quit := make(chan struct{})
	defer close(quit)
	sendChan := make(chan fdrun, expect)
	ansChan := make(chan fdrun, expect)

	// Launch workers. Workers receive an index and a step, and compute the answer
	for i := 0; i < settings.Workers; i++ {
		go func(sendChan <-chan fdrun, ansChan chan<- fdrun, quit <-chan struct{}) {
			xcopy := make([]float64, len(x))
			copy(xcopy, x)
			for {
				select {
				case <-quit:
					return
				case run := <-sendChan:
					xcopy[run.idx] += run.pt.Loc * settings.Step
					run.result = f(xcopy)
					xcopy[run.idx] = x[run.idx]
					ansChan <- run
				}
			}
		}(sendChan, ansChan, quit)
	}

	// Launch the distributor. Distributor sends the cases to be computed
	go func(sendChan chan<- fdrun, ansChan chan<- fdrun) {
		for i := range x {
			for _, pt := range settings.Method.Stencil {
				if settings.OriginKnown && pt.Loc == 0 {
					// Answer already known. Send the answer on the answer channel
					ansChan <- fdrun{
						idx:    i,
						pt:     pt,
						result: settings.OriginValue,
					}
					continue
				}
				// Answer not known, send the answer to be computed
				sendChan <- fdrun{
					idx: i,
					pt:  pt,
				}
			}
		}
	}(sendChan, ansChan)

	for i := range gradient {
		gradient[i] = 0
	}
	// Read in all of the results
	for i := 0; i < expect; i++ {
		run := <-ansChan
		gradient[run.idx] += run.pt.Coeff * run.result
	}
	floats.Scale(1/math.Pow(settings.Step, float64(settings.Method.Order)), gradient)
}

type fdrun struct {
	idx    int
	pt     Point
	result float64
}

// Forward represents a first-order forward difference.
var Forward = Method{
	Stencil: []Point{{Loc: 0, Coeff: -1}, {Loc: 1, Coeff: 1}},
	Order:   1,
}

// Backward represents a first-order backward difference
var Backward = Method{
	Stencil: []Point{{Loc: -1, Coeff: -1}, {Loc: 0, Coeff: 1}},
	Order:   1,
}

// Central represents a first-order central difference.
var Central = Method{
	Stencil: []Point{{Loc: -1, Coeff: -0.5}, {Loc: 1, Coeff: 0.5}},
	Order:   1,
}

// Central2nd represents a secord-order central difference.
var Central2nd = Method{
	Stencil: []Point{{Loc: -1, Coeff: 1}, {Loc: 0, Coeff: -2}, {Loc: 1, Coeff: 1}},
	Order:   2,
}
<|endoftext|>


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

package main

import (
	"fmt"
	"os"
	"testing"

	"github.com/coreos/rkt/tests/testutils"
)

func TestAppUserGroup(t *testing.T) {
	ctx := testutils.NewRktRunCtx()
	defer ctx.Cleanup()

	imageDummy := patchTestACI("rkt-inspect-dummy.aci", "--name=dummy")
	defer os.Remove(imageDummy)

	for _, tt := range []struct {
		imageParams []string
		rktParams   string
		expected    string
	}{
		{
			expected: "User: uid=0 euid=0 gid=0 egid=0",
		},
		{
			rktParams: "--user=200",
			expected:  "User: uid=200 euid=200 gid=0 egid=0",
		},
		{
			rktParams: "--group=300",
			expected:  "User: uid=0 euid=0 gid=300 egid=300",
		},
		{
			rktParams: "--user=200 --group=300",
			expected:  "User: uid=200 euid=200 gid=300 egid=300",
		},
		{
			rktParams: "--user=user1 --group=300",
			expected:  "User: uid=1000 euid=1000 gid=300 egid=300",
		},
		{
			rktParams: "--user=200 --group=group1",
			expected:  "User: uid=200 euid=200 gid=100 egid=100",
		},
		{
			imageParams: []string{"--user=400", "--group=500"},
			expected:    "User: uid=400 euid=400 gid=500 egid=500",
		},
		{
			imageParams: []string{"--user=400", "--group=500"},
			rktParams:   "--user=200",
			expected:    "User: uid=200 euid=200 gid=500 egid=500",
		},
		{
			imageParams: []string{"--user=400", "--group=500"},
			rktParams:   "--group=300",
			expected:    "User: uid=400 euid=400 gid=300 egid=300",
		},
		{
			imageParams: []string{"--user=400", "--group=500"},
			rktParams:   "--user=200 --group=300",
			expected:    "User: uid=200 euid=200 gid=300 egid=300",
		},
		{
			imageParams: []string{"--user=400", "--group=500"},
			rktParams:   "--user=user1 --group=group1",
			expected:    "User: uid=1000 euid=1000 gid=100 egid=100",
		},
	} {
		func() {
			tt.imageParams = append(tt.imageParams, "--exec=/inspect --print-user")
			image := patchTestACI("rkt-inspect-user-group.aci", tt.imageParams...)
			defer os.Remove(image)

			// run the user/group overriden app first
			rktCmd := fmt.Sprintf(
				"%s --insecure-options=image run %s %s %s",
				ctx.Cmd(),
				image, tt.rktParams,
				imageDummy,
			)
			runRktAndCheckOutput(t, rktCmd, tt.expected, false)

			// run the user/group overriden app last
			rktCmd = fmt.Sprintf(
				"%s --insecure-options=image run %s %s %s",
				ctx.Cmd(),
				imageDummy,
				image, tt.rktParams,
			)
			runRktAndCheckOutput(t, rktCmd, tt.expected, false)
		}()
	}
}
<commit_msg>tests/TestAppUserGroup: cleanup ctx after each test<commit_after>// Copyright 2016 The rkt Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"os"
	"testing"

	"github.com/coreos/rkt/tests/testutils"
)

func TestAppUserGroup(t *testing.T) {
	imageDummy := patchTestACI("rkt-inspect-dummy.aci", "--name=dummy")
	defer os.Remove(imageDummy)

	for _, tt := range []struct {
		imageParams []string
		rktParams   string
		expected    string
	}{
		{
			expected: "User: uid=0 euid=0 gid=0 egid=0",
		},
		{
			rktParams: "--user=200",
			expected:  "User: uid=200 euid=200 gid=0 egid=0",
		},
		{
			rktParams: "--group=300",
			expected:  "User: uid=0 euid=0 gid=300 egid=300",
		},
		{
			rktParams: "--user=200 --group=300",
			expected:  "User: uid=200 euid=200 gid=300 egid=300",
		},
		{
			rktParams: "--user=user1 --group=300",
			expected:  "User: uid=1000 euid=1000 gid=300 egid=300",
		},
		{
			rktParams: "--user=200 --group=group1",
			expected:  "User: uid=200 euid=200 gid=100 egid=100",
		},
		{
			imageParams: []string{"--user=400", "--group=500"},
			expected:    "User: uid=400 euid=400 gid=500 egid=500",
		},
		{
			imageParams: []string{"--user=400", "--group=500"},
			rktParams:   "--user=200",
			expected:    "User: uid=200 euid=200 gid=500 egid=500",
		},
		{
			imageParams: []string{"--user=400", "--group=500"},
			rktParams:   "--group=300",
			expected:    "User: uid=400 euid=400 gid=300 egid=300",
		},
		{
			imageParams: []string{"--user=400", "--group=500"},
			rktParams:   "--user=200 --group=300",
			expected:    "User: uid=200 euid=200 gid=300 egid=300",
		},
		{
			imageParams: []string{"--user=400", "--group=500"},
			rktParams:   "--user=user1 --group=group1",
			expected:    "User: uid=1000 euid=1000 gid=100 egid=100",
		},
	} {
		func() {
			ctx := testutils.NewRktRunCtx()
			defer ctx.Cleanup()

			tt.imageParams = append(tt.imageParams, "--exec=/inspect --print-user")
			image := patchTestACI("rkt-inspect-user-group.aci", tt.imageParams...)
			defer os.Remove(image)

			// run the user/group overriden app first
			rktCmd := fmt.Sprintf(
				"%s --insecure-options=image run %s %s %s",
				ctx.Cmd(),
				image, tt.rktParams,
				imageDummy,
			)
			runRktAndCheckOutput(t, rktCmd, tt.expected, false)

			// run the user/group overriden app last
			rktCmd = fmt.Sprintf(
				"%s --insecure-options=image run %s %s %s",
				ctx.Cmd(),
				imageDummy,
				image, tt.rktParams,
			)
			runRktAndCheckOutput(t, rktCmd, tt.expected, false)
		}()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/codegangsta/cli"
	"github.com/keybase/client/go/engine"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	keybase_1 "github.com/keybase/client/protocol/go"
	"github.com/maxtaco/go-framed-msgpack-rpc/rpc2"
	"os"
)

func NewCmdPGPExport(cl *libcmdline.CommandLine) cli.Command {
	return cli.Command{
		Name:        "export",
		Usage:       "keybase pgp export [-o <file>] [-q <query>] [-s]",
		Description: "export a PGP key from keybase",
		Action: func(c *cli.Context) {
			cl.ChooseCommand(&CmdPGPExport{}, "export", c)
		},
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "o, outfile",
				Usage: "specify an outfile (stdout by default)",
			},
			cli.BoolFlag{
				Name:  "s, secret",
				Usage: "export secret key",
			},
			cli.StringFlag{
				Name:  "q, query",
				Usage: "only export keys matching that query",
			},
		},
	}
}

type CmdPGPExport struct {
	UnixFilter
	arg     keybase_1.PgpExportArg
	outfile string
}

func (s *CmdPGPExport) ParseArgv(ctx *cli.Context) error {
	nargs := len(ctx.Args())
	var err error

	s.arg.Secret = ctx.Bool("secret")
	s.arg.Query = ctx.String("query")
	s.outfile = ctx.String("outfile")

	if nargs > 0 {
		err = fmt.Errorf("export doesn't take args")
	}

	return err
}

func (s *CmdPGPExport) RunClient() (err error) {
	var cli keybase_1.PgpClient
	protocols := []rpc2.Protocol{
		NewLogUIProtocol(),
		NewSecretUIProtocol(),
	}

	if cli, err = GetPGPClient(); err != nil {
	} else if err = RegisterProtocols(protocols); err != nil {
	} else {
		err = s.finish(cli.PgpExport(s.arg))
	}
	return err
}

func (s *CmdPGPExport) finish(res []keybase_1.FingerprintAndKey, err error) error {
	if err != nil {
		return err
	}
	if len(res) > 1 {
		G.Log.Warning("Found several matches:")
		for _, k := range res {
			os.Stderr.Write([]byte(k.Desc + "\n"))
		}
		err = fmt.Errorf("Specify a key to export")
	} else if len(res) == 0 {
		err = fmt.Errorf("No matching keys found")
	} else {
		snk := initSink(s.outfile)
		if err := snk.Open(); err != nil {
			return err
		}
		snk.Write([]byte(res[0].Key))
		snk.Close()
	}
	return nil
}

func (s *CmdPGPExport) Run() (err error) {
	ctx := engine.Context{
		SecretUI: G_UI.GetSecretUI(),
		LogUI:    G_UI.GetLogUI(),
	}
	eng := engine.NewPGPKeyExportEngine(s.arg)
	err = engine.RunEngine(eng, &ctx)
	err = s.finish(eng.Results(), err)
	return err
}

func (v *CmdPGPExport) GetUsage() libkb.Usage {
	return libkb.Usage{
		Config:    true,
		API:       true,
		KbKeyring: true,
	}
}
<commit_msg>somewhat rough, but it works<commit_after>package main

import (
	"fmt"

	"github.com/codegangsta/cli"
	"github.com/keybase/client/go/engine"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	keybase_1 "github.com/keybase/client/protocol/go"
	"github.com/maxtaco/go-framed-msgpack-rpc/rpc2"
	"os"
)

func NewCmdPGPExport(cl *libcmdline.CommandLine) cli.Command {
	return cli.Command{
		Name:        "export",
		Usage:       "keybase pgp export [-o <file>] [-q <query>] [-s]",
		Description: "export a PGP key from keybase",
		Action: func(c *cli.Context) {
			cl.ChooseCommand(&CmdPGPExport{}, "export", c)
		},
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "o, outfile",
				Usage: "specify an outfile (stdout by default)",
			},
			cli.BoolFlag{
				Name:  "s, secret",
				Usage: "export secret key",
			},
			cli.StringFlag{
				Name:  "q, query",
				Usage: "only export keys matching that query",
			},
		},
	}
}

type CmdPGPExport struct {
	UnixFilter
	arg     keybase_1.PgpExportArg
	outfile string
}

func (s *CmdPGPExport) ParseArgv(ctx *cli.Context) error {
	nargs := len(ctx.Args())
	var err error

	s.arg.Secret = ctx.Bool("secret")
	s.arg.Query = ctx.String("query")
	s.outfile = ctx.String("outfile")

	if nargs > 0 {
		err = fmt.Errorf("export doesn't take args")
	}

	return err
}

func (s *CmdPGPExport) RunClient() (err error) {
	var cli keybase_1.PgpClient
	protocols := []rpc2.Protocol{
		NewLogUIProtocol(),
		NewSecretUIProtocol(),
	}

	if cli, err = GetPGPClient(); err != nil {
	} else if err = RegisterProtocols(protocols); err != nil {
	} else {
		err = s.finish(cli.PgpExport(s.arg))
	}
	return err
}

func (s *CmdPGPExport) finish(res []keybase_1.FingerprintAndKey, err error) error {
	if err != nil {
		return err
	}
	if len(res) > 1 {
		G.Log.Warning("Found several matches:")
		for _, k := range res {
			os.Stderr.Write([]byte(k.Desc + "\n\n"))
		}
		err = fmt.Errorf("Specify a key to export")
	} else if len(res) == 0 {
		err = fmt.Errorf("No matching keys found")
	} else {
		snk := initSink(s.outfile)
		if err = snk.Open(); err == nil {
			snk.Write([]byte(res[0].Key))
			err = snk.Close()
		}
	}
	return err
}

func (s *CmdPGPExport) Run() (err error) {
	ctx := engine.Context{
		SecretUI: G_UI.GetSecretUI(),
		LogUI:    G_UI.GetLogUI(),
	}
	eng := engine.NewPGPKeyExportEngine(s.arg)
	err = engine.RunEngine(eng, &ctx)
	err = s.finish(eng.Results(), err)
	return err
}

func (v *CmdPGPExport) GetUsage() libkb.Usage {
	return libkb.Usage{
		Config:    true,
		API:       true,
		KbKeyring: true,
	}
}
<|endoftext|>