<commit_before>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package delete

import (
	"fmt"
	"net/url"
	"strings"
	"time"

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

	"k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/cli-runtime/pkg/genericclioptions"
	"k8s.io/cli-runtime/pkg/printers"
	"k8s.io/cli-runtime/pkg/resource"
	"k8s.io/client-go/dynamic"
	cmdutil "k8s.io/kubectl/pkg/cmd/util"
	cmdwait "k8s.io/kubectl/pkg/cmd/wait"
	"k8s.io/kubectl/pkg/rawhttp"
	"k8s.io/kubectl/pkg/util/i18n"
	"k8s.io/kubectl/pkg/util/templates"
)

var (
	deleteLong = templates.LongDesc(i18n.T(`
		Delete resources by filenames, stdin, resources and names, or by resources and label selector.

		JSON and YAML formats are accepted. Only one type of the arguments may be specified: filenames,
		resources and names, or resources and label selector.

		Some resources, such as pods, support graceful deletion. These resources define a default period
		before they are forcibly terminated (the grace period) but you may override that value with
		the --grace-period flag, or pass --now to set a grace-period of 1. Because these resources often
		represent entities in the cluster, deletion may not be acknowledged immediately. If the node
		hosting a pod is down or cannot reach the API server, termination may take significantly longer
		than the grace period. To force delete a resource, you must pass a grace period of 0 and specify
		the --force flag.

		IMPORTANT: Force deleting pods does not wait for confirmation that the pod's processes have been
		terminated, which can leave those processes running until the node detects the deletion and
		completes graceful deletion. If your processes use shared storage or talk to a remote API and
		depend on the name of the pod to identify themselves, force deleting those pods may result in
		multiple processes running on different machines using the same identification which may lead
		to data corruption or inconsistency. Only force delete pods when you are sure the pod is
		terminated, or if your application can tolerate multiple copies of the same pod running at once.
		Also, if you force delete pods the scheduler may place new pods on those nodes before the node
		has released those resources and causing those pods to be evicted immediately.

		Note that the delete command does NOT do resource version checks, so if someone submits an
		update to a resource right when you submit a delete, their update will be lost along with the
		rest of the resource.`))

	deleteExample = templates.Examples(i18n.T(`
		# Delete a pod using the type and name specified in pod.json.
		kubectl delete -f ./pod.json

		# Delete resources from a directory containing kustomization.yaml - e.g. dir/kustomization.yaml.
		kubectl delete -k dir

		# Delete a pod based on the type and name in the JSON passed into stdin.
		cat pod.json | kubectl delete -f -

		# Delete pods and services with same names "baz" and "foo"
		kubectl delete pod,service baz foo

		# Delete pods and services with label name=myLabel.
		kubectl delete pods,services -l name=myLabel

		# Delete a pod with minimal delay
		kubectl delete pod foo --now

		# Force delete a pod on a dead node
		kubectl delete pod foo --grace-period=0 --force

		# Delete all pods
		kubectl delete pods --all`))
)

type DeleteOptions struct {
	resource.FilenameOptions

	LabelSelector       string
	FieldSelector       string
	DeleteAll           bool
	DeleteAllNamespaces bool
	IgnoreNotFound      bool
	Cascade             bool
	DeleteNow           bool
	ForceDeletion       bool
	WaitForDeletion     bool
	Quiet               bool
	WarnClusterScope    bool
	Raw                 string

	GracePeriod int
	Timeout     time.Duration

	Output string

	DynamicClient dynamic.Interface
	Mapper        meta.RESTMapper
	Result        *resource.Result

	genericclioptions.IOStreams
}

func NewCmdDelete(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
	deleteFlags := NewDeleteCommandFlags("containing the resource to delete.")

	cmd := &cobra.Command{
		Use:                   "delete ([-f FILENAME] | [-k DIRECTORY] | TYPE [(NAME | -l label | --all)])",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Delete resources by filenames, stdin, resources and names, or by resources and label selector"),
		Long:                  deleteLong,
		Example:               deleteExample,
		Run: func(cmd *cobra.Command, args []string) {
			o := deleteFlags.ToOptions(nil, streams)
			cmdutil.CheckErr(o.Complete(f, args, cmd))
			cmdutil.CheckErr(o.Validate())
			cmdutil.CheckErr(o.RunDelete(f))
		},
		SuggestFor: []string{"rm"},
	}

	deleteFlags.AddFlags(cmd)

	return cmd
}

func (o *DeleteOptions) Complete(f cmdutil.Factory, args []string, cmd *cobra.Command) error {
	cmdNamespace, enforceNamespace, err := f.ToRawKubeConfigLoader().Namespace()
	if err != nil {
		return err
	}

	o.WarnClusterScope = enforceNamespace && !o.DeleteAllNamespaces

	if o.DeleteAll || len(o.LabelSelector) > 0 || len(o.FieldSelector) > 0 {
		if f := cmd.Flags().Lookup("ignore-not-found"); f != nil && !f.Changed {
			// If the user didn't explicitly set the option, default to ignoring NotFound errors when used with --all, -l, or --field-selector
			o.IgnoreNotFound = true
		}
	}
	if o.DeleteNow {
		if o.GracePeriod != -1 {
			return fmt.Errorf("--now and --grace-period cannot be specified together")
		}
		o.GracePeriod = 1
	}
	if o.GracePeriod == 0 && !o.ForceDeletion {
		// To preserve backwards compatibility, but prevent accidental data loss, we convert --grace-period=0
		// into --grace-period=1. Users may provide --force to bypass this conversion.
		o.GracePeriod = 1
	}

	if len(o.Raw) == 0 {
		r := f.NewBuilder().
			Unstructured().
			ContinueOnError().
			NamespaceParam(cmdNamespace).DefaultNamespace().
			FilenameParam(enforceNamespace, &o.FilenameOptions).
			LabelSelectorParam(o.LabelSelector).
			FieldSelectorParam(o.FieldSelector).
			SelectAllParam(o.DeleteAll).
			AllNamespaces(o.DeleteAllNamespaces).
			ResourceTypeOrNameArgs(false, args...).RequireObject(false).
			Flatten().
			Do()
		err = r.Err()
		if err != nil {
			return err
		}
		o.Result = r

		o.Mapper, err = f.ToRESTMapper()
		if err != nil {
			return err
		}

		o.DynamicClient, err = f.DynamicClient()
		if err != nil {
			return err
		}
	}

	return nil
}

func (o *DeleteOptions) Validate() error {
	if o.Output != "" && o.Output != "name" {
		return fmt.Errorf("unexpected -o output mode: %v. We only support '-o name'", o.Output)
	}

	if o.DeleteAll && len(o.LabelSelector) > 0 {
		return fmt.Errorf("cannot set --all and --selector at the same time")
	}
	if o.DeleteAll && len(o.FieldSelector) > 0 {
		return fmt.Errorf("cannot set --all and --field-selector at the same time")
	}

	switch {
	case o.GracePeriod == 0 && o.ForceDeletion:
		fmt.Fprintf(o.ErrOut, "warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.\n")
	case o.ForceDeletion:
		fmt.Fprintf(o.ErrOut, "warning: --force is ignored because --grace-period is not 0.\n")
	}

	if len(o.Raw) > 0 {
		if len(o.FilenameOptions.Filenames) > 1 {
			return fmt.Errorf("--raw can only use a single local file or stdin")
		} else if len(o.FilenameOptions.Filenames) == 1 {
			if strings.Index(o.FilenameOptions.Filenames[0], "http://") == 0 || strings.Index(o.FilenameOptions.Filenames[0], "https://") == 0 {
				return fmt.Errorf("--raw cannot read from a url")
			}
		}

		if o.FilenameOptions.Recursive {
			return fmt.Errorf("--raw and --recursive are mutually exclusive")
		}
		if len(o.Output) > 0 {
			return fmt.Errorf("--raw and --output are mutually exclusive")
		}
		if _, err := url.ParseRequestURI(o.Raw); err != nil {
			return fmt.Errorf("--raw must be a valid URL path: %v", err)
		}
	}

	return nil
}

func (o *DeleteOptions) RunDelete(f cmdutil.Factory) error {
	if len(o.Raw) > 0 {
		restClient, err := f.RESTClient()
		if err != nil {
			return err
		}
		if len(o.Filenames) == 0 {
			return rawhttp.RawDelete(restClient, o.IOStreams, o.Raw, "")
		}
		return rawhttp.RawDelete(restClient, o.IOStreams, o.Raw, o.Filenames[0])
	}
	return o.DeleteResult(o.Result)
}

func (o *DeleteOptions) DeleteResult(r *resource.Result) error {
	found := 0
	if o.IgnoreNotFound {
		r = r.IgnoreErrors(errors.IsNotFound)
	}
	warnClusterScope := o.WarnClusterScope
	deletedInfos := []*resource.Info{}
	uidMap := cmdwait.UIDMap{}
	err := r.Visit(func(info *resource.Info, err error) error {
		if err != nil {
			return err
		}
		deletedInfos = append(deletedInfos, info)
		found++

		options := &metav1.DeleteOptions{}
		if o.GracePeriod >= 0 {
			options = metav1.NewDeleteOptions(int64(o.GracePeriod))
		}
		policy := metav1.DeletePropagationBackground
		if !o.Cascade {
			policy = metav1.DeletePropagationOrphan
		}
		options.PropagationPolicy = &policy

		if warnClusterScope && info.Mapping.Scope.Name() == meta.RESTScopeNameRoot {
			fmt.Fprintf(o.ErrOut, "warning: deleting cluster-scoped resources, not scoped to the provided namespace\n")
			warnClusterScope = false
		}
		response, err := o.deleteResource(info, options)
		if err != nil {
			return err
		}
		resourceLocation := cmdwait.ResourceLocation{
			GroupResource: info.Mapping.Resource.GroupResource(),
			Namespace:     info.Namespace,
			Name:          info.Name,
		}
		if status, ok := response.(*metav1.Status); ok && status.Details != nil {
			uidMap[resourceLocation] = status.Details.UID
			return nil
		}
		responseMetadata, err := meta.Accessor(response)
		if err != nil {
			// we don't have UID, but we didn't fail the delete, next best thing is just skipping the UID
			klog.V(1).Info(err)
			return nil
		}
		uidMap[resourceLocation] = responseMetadata.GetUID()

		return nil
	})
	if err != nil {
		return err
	}
	if found == 0 {
		fmt.Fprintf(o.Out, "No resources found\n")
		return nil
	}
	if !o.WaitForDeletion {
		return nil
	}
	// if we don't have a dynamic client, we don't want to wait.  Eventually when delete is cleaned up, this will likely
	// drop out.
	if o.DynamicClient == nil {
		return nil
	}

	effectiveTimeout := o.Timeout
	if effectiveTimeout == 0 {
		// if we requested to wait forever, set it to a week.
		effectiveTimeout = 168 * time.Hour
	}
	waitOptions := cmdwait.WaitOptions{
		ResourceFinder: genericclioptions.ResourceFinderForResult(resource.InfoListVisitor(deletedInfos)),
		UIDMap:         uidMap,
		DynamicClient:  o.DynamicClient,
		Timeout:        effectiveTimeout,

		Printer:     printers.NewDiscardingPrinter(),
		ConditionFn: cmdwait.IsDeleted,
		IOStreams:   o.IOStreams,
	}
	err = waitOptions.RunWait()
	if errors.IsForbidden(err) || errors.IsMethodNotSupported(err) {
		// if we're forbidden from waiting, we shouldn't fail.
		// if the resource doesn't support a verb we need, we shouldn't fail.
		klog.V(1).Info(err)
		return nil
	}
	return err
}

func (o *DeleteOptions) deleteResource(info *resource.Info, deleteOptions *metav1.DeleteOptions) (runtime.Object, error) {
	deleteResponse, err := resource.NewHelper(info.Client, info.Mapping).DeleteWithOptions(info.Namespace, info.Name, deleteOptions)
	if err != nil {
		return nil, cmdutil.AddSourceToErr("deleting", info.Source, err)
	}

	if !o.Quiet {
		o.PrintObj(info)
	}
	return deleteResponse, nil
}

// PrintObj for deleted objects is special because we do not have an object to print.
// This mirrors name printer behavior
func (o *DeleteOptions) PrintObj(info *resource.Info) {
	operation := "deleted"
	groupKind := info.Mapping.GroupVersionKind
	kindString := fmt.Sprintf("%s.%s", strings.ToLower(groupKind.Kind), groupKind.Group)
	if len(groupKind.Group) == 0 {
		kindString = strings.ToLower(groupKind.Kind)
	}

	if o.GracePeriod == 0 {
		operation = "force deleted"
	}

	if o.Output == "name" {
		// -o name: prints resource/name
		fmt.Fprintf(o.Out, "%s/%s\n", kindString, info.Name)
		return
	}

	// understandable output by default
	fmt.Fprintf(o.Out, "%s \"%s\" %s\n", kindString, info.Name, operation)
}
<commit_msg>Add note on the applicability of --grace-period<commit_after>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package delete

import (
	"fmt"
	"net/url"
	"strings"
	"time"

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

	"k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/cli-runtime/pkg/genericclioptions"
	"k8s.io/cli-runtime/pkg/printers"
	"k8s.io/cli-runtime/pkg/resource"
	"k8s.io/client-go/dynamic"
	cmdutil "k8s.io/kubectl/pkg/cmd/util"
	cmdwait "k8s.io/kubectl/pkg/cmd/wait"
	"k8s.io/kubectl/pkg/rawhttp"
	"k8s.io/kubectl/pkg/util/i18n"
	"k8s.io/kubectl/pkg/util/templates"
)

var (
	deleteLong = templates.LongDesc(i18n.T(`
		Delete resources by filenames, stdin, resources and names, or by resources and label selector.

		JSON and YAML formats are accepted. Only one type of the arguments may be specified: filenames,
		resources and names, or resources and label selector.

		Some resources, such as pods, support graceful deletion. These resources define a default period
		before they are forcibly terminated (the grace period) but you may override that value with
		the --grace-period flag, or pass --now to set a grace-period of 1. Because these resources often
		represent entities in the cluster, deletion may not be acknowledged immediately. If the node
		hosting a pod is down or cannot reach the API server, termination may take significantly longer
		than the grace period. To force delete a resource, you must pass a grace period of 0 and specify
		the --force flag.
		Note: only a subset of resources support graceful deletion. In absence of the support, --grace-period is ignored.

		IMPORTANT: Force deleting pods does not wait for confirmation that the pod's processes have been
		terminated, which can leave those processes running until the node detects the deletion and
		completes graceful deletion. If your processes use shared storage or talk to a remote API and
		depend on the name of the pod to identify themselves, force deleting those pods may result in
		multiple processes running on different machines using the same identification which may lead
		to data corruption or inconsistency. Only force delete pods when you are sure the pod is
		terminated, or if your application can tolerate multiple copies of the same pod running at once.
		Also, if you force delete pods the scheduler may place new pods on those nodes before the node
		has released those resources and causing those pods to be evicted immediately.

		Note that the delete command does NOT do resource version checks, so if someone submits an
		update to a resource right when you submit a delete, their update will be lost along with the
		rest of the resource.`))

	deleteExample = templates.Examples(i18n.T(`
		# Delete a pod using the type and name specified in pod.json.
		kubectl delete -f ./pod.json

		# Delete resources from a directory containing kustomization.yaml - e.g. dir/kustomization.yaml.
		kubectl delete -k dir

		# Delete a pod based on the type and name in the JSON passed into stdin.
		cat pod.json | kubectl delete -f -

		# Delete pods and services with same names "baz" and "foo"
		kubectl delete pod,service baz foo

		# Delete pods and services with label name=myLabel.
		kubectl delete pods,services -l name=myLabel

		# Delete a pod with minimal delay
		kubectl delete pod foo --now

		# Force delete a pod on a dead node
		kubectl delete pod foo --grace-period=0 --force

		# Delete all pods
		kubectl delete pods --all`))
)

type DeleteOptions struct {
	resource.FilenameOptions

	LabelSelector       string
	FieldSelector       string
	DeleteAll           bool
	DeleteAllNamespaces bool
	IgnoreNotFound      bool
	Cascade             bool
	DeleteNow           bool
	ForceDeletion       bool
	WaitForDeletion     bool
	Quiet               bool
	WarnClusterScope    bool
	Raw                 string

	GracePeriod int
	Timeout     time.Duration

	Output string

	DynamicClient dynamic.Interface
	Mapper        meta.RESTMapper
	Result        *resource.Result

	genericclioptions.IOStreams
}

func NewCmdDelete(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
	deleteFlags := NewDeleteCommandFlags("containing the resource to delete.")

	cmd := &cobra.Command{
		Use:                   "delete ([-f FILENAME] | [-k DIRECTORY] | TYPE [(NAME | -l label | --all)])",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Delete resources by filenames, stdin, resources and names, or by resources and label selector"),
		Long:                  deleteLong,
		Example:               deleteExample,
		Run: func(cmd *cobra.Command, args []string) {
			o := deleteFlags.ToOptions(nil, streams)
			cmdutil.CheckErr(o.Complete(f, args, cmd))
			cmdutil.CheckErr(o.Validate())
			cmdutil.CheckErr(o.RunDelete(f))
		},
		SuggestFor: []string{"rm"},
	}

	deleteFlags.AddFlags(cmd)

	return cmd
}

func (o *DeleteOptions) Complete(f cmdutil.Factory, args []string, cmd *cobra.Command) error {
	cmdNamespace, enforceNamespace, err := f.ToRawKubeConfigLoader().Namespace()
	if err != nil {
		return err
	}

	o.WarnClusterScope = enforceNamespace && !o.DeleteAllNamespaces

	if o.DeleteAll || len(o.LabelSelector) > 0 || len(o.FieldSelector) > 0 {
		if f := cmd.Flags().Lookup("ignore-not-found"); f != nil && !f.Changed {
			// If the user didn't explicitly set the option, default to ignoring NotFound errors when used with --all, -l, or --field-selector
			o.IgnoreNotFound = true
		}
	}
	if o.DeleteNow {
		if o.GracePeriod != -1 {
			return fmt.Errorf("--now and --grace-period cannot be specified together")
		}
		o.GracePeriod = 1
	}
	if o.GracePeriod == 0 && !o.ForceDeletion {
		// To preserve backwards compatibility, but prevent accidental data loss, we convert --grace-period=0
		// into --grace-period=1. Users may provide --force to bypass this conversion.
		o.GracePeriod = 1
	}

	if len(o.Raw) == 0 {
		r := f.NewBuilder().
			Unstructured().
			ContinueOnError().
			NamespaceParam(cmdNamespace).DefaultNamespace().
			FilenameParam(enforceNamespace, &o.FilenameOptions).
			LabelSelectorParam(o.LabelSelector).
			FieldSelectorParam(o.FieldSelector).
			SelectAllParam(o.DeleteAll).
			AllNamespaces(o.DeleteAllNamespaces).
			ResourceTypeOrNameArgs(false, args...).RequireObject(false).
			Flatten().
			Do()
		err = r.Err()
		if err != nil {
			return err
		}
		o.Result = r

		o.Mapper, err = f.ToRESTMapper()
		if err != nil {
			return err
		}

		o.DynamicClient, err = f.DynamicClient()
		if err != nil {
			return err
		}
	}

	return nil
}

func (o *DeleteOptions) Validate() error {
	if o.Output != "" && o.Output != "name" {
		return fmt.Errorf("unexpected -o output mode: %v. We only support '-o name'", o.Output)
	}

	if o.DeleteAll && len(o.LabelSelector) > 0 {
		return fmt.Errorf("cannot set --all and --selector at the same time")
	}
	if o.DeleteAll && len(o.FieldSelector) > 0 {
		return fmt.Errorf("cannot set --all and --field-selector at the same time")
	}

	switch {
	case o.GracePeriod == 0 && o.ForceDeletion:
		fmt.Fprintf(o.ErrOut, "warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.\n")
	case o.ForceDeletion:
		fmt.Fprintf(o.ErrOut, "warning: --force is ignored because --grace-period is not 0.\n")
	}

	if len(o.Raw) > 0 {
		if len(o.FilenameOptions.Filenames) > 1 {
			return fmt.Errorf("--raw can only use a single local file or stdin")
		} else if len(o.FilenameOptions.Filenames) == 1 {
			if strings.Index(o.FilenameOptions.Filenames[0], "http://") == 0 || strings.Index(o.FilenameOptions.Filenames[0], "https://") == 0 {
				return fmt.Errorf("--raw cannot read from a url")
			}
		}

		if o.FilenameOptions.Recursive {
			return fmt.Errorf("--raw and --recursive are mutually exclusive")
		}
		if len(o.Output) > 0 {
			return fmt.Errorf("--raw and --output are mutually exclusive")
		}
		if _, err := url.ParseRequestURI(o.Raw); err != nil {
			return fmt.Errorf("--raw must be a valid URL path: %v", err)
		}
	}

	return nil
}

func (o *DeleteOptions) RunDelete(f cmdutil.Factory) error {
	if len(o.Raw) > 0 {
		restClient, err := f.RESTClient()
		if err != nil {
			return err
		}
		if len(o.Filenames) == 0 {
			return rawhttp.RawDelete(restClient, o.IOStreams, o.Raw, "")
		}
		return rawhttp.RawDelete(restClient, o.IOStreams, o.Raw, o.Filenames[0])
	}
	return o.DeleteResult(o.Result)
}

func (o *DeleteOptions) DeleteResult(r *resource.Result) error {
	found := 0
	if o.IgnoreNotFound {
		r = r.IgnoreErrors(errors.IsNotFound)
	}
	warnClusterScope := o.WarnClusterScope
	deletedInfos := []*resource.Info{}
	uidMap := cmdwait.UIDMap{}
	err := r.Visit(func(info *resource.Info, err error) error {
		if err != nil {
			return err
		}
		deletedInfos = append(deletedInfos, info)
		found++

		options := &metav1.DeleteOptions{}
		if o.GracePeriod >= 0 {
			options = metav1.NewDeleteOptions(int64(o.GracePeriod))
		}
		policy := metav1.DeletePropagationBackground
		if !o.Cascade {
			policy = metav1.DeletePropagationOrphan
		}
		options.PropagationPolicy = &policy

		if warnClusterScope && info.Mapping.Scope.Name() == meta.RESTScopeNameRoot {
			fmt.Fprintf(o.ErrOut, "warning: deleting cluster-scoped resources, not scoped to the provided namespace\n")
			warnClusterScope = false
		}
		response, err := o.deleteResource(info, options)
		if err != nil {
			return err
		}
		resourceLocation := cmdwait.ResourceLocation{
			GroupResource: info.Mapping.Resource.GroupResource(),
			Namespace:     info.Namespace,
			Name:          info.Name,
		}
		if status, ok := response.(*metav1.Status); ok && status.Details != nil {
			uidMap[resourceLocation] = status.Details.UID
			return nil
		}
		responseMetadata, err := meta.Accessor(response)
		if err != nil {
			// we don't have UID, but we didn't fail the delete, next best thing is just skipping the UID
			klog.V(1).Info(err)
			return nil
		}
		uidMap[resourceLocation] = responseMetadata.GetUID()

		return nil
	})
	if err != nil {
		return err
	}
	if found == 0 {
		fmt.Fprintf(o.Out, "No resources found\n")
		return nil
	}
	if !o.WaitForDeletion {
		return nil
	}
	// if we don't have a dynamic client, we don't want to wait.  Eventually when delete is cleaned up, this will likely
	// drop out.
	if o.DynamicClient == nil {
		return nil
	}

	effectiveTimeout := o.Timeout
	if effectiveTimeout == 0 {
		// if we requested to wait forever, set it to a week.
		effectiveTimeout = 168 * time.Hour
	}
	waitOptions := cmdwait.WaitOptions{
		ResourceFinder: genericclioptions.ResourceFinderForResult(resource.InfoListVisitor(deletedInfos)),
		UIDMap:         uidMap,
		DynamicClient:  o.DynamicClient,
		Timeout:        effectiveTimeout,

		Printer:     printers.NewDiscardingPrinter(),
		ConditionFn: cmdwait.IsDeleted,
		IOStreams:   o.IOStreams,
	}
	err = waitOptions.RunWait()
	if errors.IsForbidden(err) || errors.IsMethodNotSupported(err) {
		// if we're forbidden from waiting, we shouldn't fail.
		// if the resource doesn't support a verb we need, we shouldn't fail.
		klog.V(1).Info(err)
		return nil
	}
	return err
}

func (o *DeleteOptions) deleteResource(info *resource.Info, deleteOptions *metav1.DeleteOptions) (runtime.Object, error) {
	deleteResponse, err := resource.NewHelper(info.Client, info.Mapping).DeleteWithOptions(info.Namespace, info.Name, deleteOptions)
	if err != nil {
		return nil, cmdutil.AddSourceToErr("deleting", info.Source, err)
	}

	if !o.Quiet {
		o.PrintObj(info)
	}
	return deleteResponse, nil
}

// PrintObj for deleted objects is special because we do not have an object to print.
// This mirrors name printer behavior
func (o *DeleteOptions) PrintObj(info *resource.Info) {
	operation := "deleted"
	groupKind := info.Mapping.GroupVersionKind
	kindString := fmt.Sprintf("%s.%s", strings.ToLower(groupKind.Kind), groupKind.Group)
	if len(groupKind.Group) == 0 {
		kindString = strings.ToLower(groupKind.Kind)
	}

	if o.GracePeriod == 0 {
		operation = "force deleted"
	}

	if o.Output == "name" {
		// -o name: prints resource/name
		fmt.Fprintf(o.Out, "%s/%s\n", kindString, info.Name)
		return
	}

	// understandable output by default
	fmt.Fprintf(o.Out, "%s \"%s\" %s\n", kindString, info.Name, operation)
}
<|endoftext|>


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

package maps

import (
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/cilium/cilium/pkg/bpf"
	"github.com/cilium/cilium/pkg/endpoint"
	"github.com/cilium/cilium/pkg/logging"
	"github.com/cilium/cilium/pkg/logging/logfields"
	"github.com/cilium/cilium/pkg/maps/callsmap"
	"github.com/cilium/cilium/pkg/maps/ctmap"
	"github.com/cilium/cilium/pkg/maps/lbmap"
	"github.com/cilium/cilium/pkg/maps/policymap"
	"github.com/cilium/cilium/pkg/option"
)

var (
	log = logging.DefaultLogger.WithField(logfields.LogSubsys, "datapath-maps")
)

// endpointManager checks against its list of the current endpoints to determine
// whether map paths should be removed, and implements map removal.
//
// This interface is provided to abstract epmanager/filesystem access for unit
// testing.
type endpointManager interface {
	EndpointExists(endpointID uint16) bool
	RemoveDatapathMapping(endpointID uint16) error
	RemoveMapPath(path string)
	HasGlobalCT() bool
}

// MapSweeper is responsible for checking stale map paths on the filesystem
// and garbage collecting the endpoint if the corresponding endpoint no longer
// exists.
type MapSweeper struct {
	endpointManager
}

// NewMapSweeper creates an object that walks map paths and garbage-collects
// them.
func NewMapSweeper(g endpointManager) *MapSweeper {
	return &MapSweeper{
		endpointManager: g,
	}
}

// deleteMapIfStale uses the endpointManager implementation to determine for
// the given path whether it should be deleted, and if so deletes the path.
func (ms *MapSweeper) deleteMapIfStale(path string, filename string, endpointID string) {
	if tmp, err := strconv.ParseUint(endpointID, 10, 16); err == nil {
		epID := uint16(tmp)
		if ms.EndpointExists(epID) {
			prefix := strings.TrimSuffix(filename, endpointID)
			if filename != bpf.LocalMapName(prefix, epID) {
				ms.RemoveMapPath(path)
			}
		} else {
			err2 := ms.RemoveDatapathMapping(epID)
			if err2 != nil {
				log.WithError(err2).Debugf("Failed to remove ID %d from global policy map", tmp)
			}
			ms.RemoveMapPath(path)
		}
	}
}

func (ms *MapSweeper) checkStaleGlobalMap(path string, filename string) {
	globalCTinUse := ms.HasGlobalCT() || option.Config.EnableNodePort ||
		!option.Config.InstallIptRules && option.Config.Masquerade

	if !globalCTinUse && ctmap.NameIsGlobal(filename) {
		ms.RemoveMapPath(path)
	}
}

func (ms *MapSweeper) walk(path string, _ os.FileInfo, _ error) error {
	filename := filepath.Base(path)

	mapPrefix := []string{
		policymap.MapName,
		ctmap.MapNameTCP6,
		ctmap.MapNameTCP4,
		ctmap.MapNameAny6,
		ctmap.MapNameAny4,
		callsmap.MapName,
		endpoint.IpvlanMapName,
	}

	ms.checkStaleGlobalMap(path, filename)

	for _, m := range mapPrefix {
		if strings.HasPrefix(filename, m) {
			if endpointID := strings.TrimPrefix(filename, m); endpointID != filename {
				ms.deleteMapIfStale(path, filename, endpointID)
			}
		}
	}

	return nil
}

// CollectStaleMapGarbage cleans up stale content in the BPF maps from the
// datapath.
func (ms *MapSweeper) CollectStaleMapGarbage() {
	if err := filepath.Walk(bpf.MapPrefixPath(), ms.walk); err != nil {
		log.WithError(err).Warn("Error while scanning for stale maps")
	}
}

// RemoveDisabledMaps removes BPF maps in the filesystem for features that have
// been disabled. The maps may still be in use in which case they will continue
// to live until the BPF program using them is being replaced.
func (ms *MapSweeper) RemoveDisabledMaps() {
	maps := []string{}

	if !option.Config.EnableIPv6 {
		maps = append(maps, []string{
			"cilium_ct6_global",
			"cilium_ct_any6_global",
			"cilium_lb6_reverse_nat",
			"cilium_lb6_rr_seq",
			"cilium_lb6_services",
			"cilium_lb6_services_v2",
			"cilium_lb6_rr_seq_v2",
			"cilium_lb6_backends",
			"cilium_lb6_reverse_sk",
			"cilium_snat_v6_external",
			"cilium_proxy6",
			lbmap.MaglevOuter6MapName,
		}...)
	}

	if !option.Config.EnableIPv4 {
		maps = append(maps, []string{
			"cilium_ct4_global",
			"cilium_ct_any4_global",
			"cilium_lb4_reverse_nat",
			"cilium_lb4_rr_seq",
			"cilium_lb4_services",
			"cilium_lb4_services_v2",
			"cilium_lb4_rr_seq_v2",
			"cilium_lb4_backends",
			"cilium_lb4_reverse_sk",
			"cilium_snat_v4_external",
			"cilium_proxy4",
			lbmap.MaglevOuter4MapName,
		}...)
	}

	if !option.Config.EnableIPv4FragmentsTracking {
		maps = append(maps, "cilium_ipv4_frag_datagrams")
	}

	if !option.Config.EnableBandwidthManager {
		maps = append(maps, "cilium_throttle")
	}

	if option.Config.NodePortAlg != option.NodePortAlgMaglev {
		maps = append(maps, lbmap.MaglevOuter6MapName, lbmap.MaglevOuter4MapName)
	}

	for _, m := range maps {
		p := path.Join(bpf.MapPrefixPath(), m)
		if _, err := os.Stat(p); !os.IsNotExist(err) {
			ms.RemoveMapPath(p)
		}
	}
}
<commit_msg>pkg/datapath: Remove unused feature maps<commit_after>// Copyright 2016-2020 Authors of Cilium
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package maps

import (
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/cilium/cilium/pkg/bpf"
	"github.com/cilium/cilium/pkg/endpoint"
	"github.com/cilium/cilium/pkg/logging"
	"github.com/cilium/cilium/pkg/logging/logfields"
	"github.com/cilium/cilium/pkg/maps/callsmap"
	"github.com/cilium/cilium/pkg/maps/ctmap"
	"github.com/cilium/cilium/pkg/maps/ipmasq"
	"github.com/cilium/cilium/pkg/maps/lbmap"
	"github.com/cilium/cilium/pkg/maps/policymap"
	"github.com/cilium/cilium/pkg/option"
)

var (
	log = logging.DefaultLogger.WithField(logfields.LogSubsys, "datapath-maps")
)

// endpointManager checks against its list of the current endpoints to determine
// whether map paths should be removed, and implements map removal.
//
// This interface is provided to abstract epmanager/filesystem access for unit
// testing.
type endpointManager interface {
	EndpointExists(endpointID uint16) bool
	RemoveDatapathMapping(endpointID uint16) error
	RemoveMapPath(path string)
	HasGlobalCT() bool
}

// MapSweeper is responsible for checking stale map paths on the filesystem
// and garbage collecting the endpoint if the corresponding endpoint no longer
// exists.
type MapSweeper struct {
	endpointManager
}

// NewMapSweeper creates an object that walks map paths and garbage-collects
// them.
func NewMapSweeper(g endpointManager) *MapSweeper {
	return &MapSweeper{
		endpointManager: g,
	}
}

// deleteMapIfStale uses the endpointManager implementation to determine for
// the given path whether it should be deleted, and if so deletes the path.
func (ms *MapSweeper) deleteMapIfStale(path string, filename string, endpointID string) {
	if tmp, err := strconv.ParseUint(endpointID, 10, 16); err == nil {
		epID := uint16(tmp)
		if ms.EndpointExists(epID) {
			prefix := strings.TrimSuffix(filename, endpointID)
			if filename != bpf.LocalMapName(prefix, epID) {
				ms.RemoveMapPath(path)
			}
		} else {
			err2 := ms.RemoveDatapathMapping(epID)
			if err2 != nil {
				log.WithError(err2).Debugf("Failed to remove ID %d from global policy map", tmp)
			}
			ms.RemoveMapPath(path)
		}
	}
}

func (ms *MapSweeper) checkStaleGlobalMap(path string, filename string) {
	globalCTinUse := ms.HasGlobalCT() || option.Config.EnableNodePort ||
		!option.Config.InstallIptRules && option.Config.Masquerade

	if !globalCTinUse && ctmap.NameIsGlobal(filename) {
		ms.RemoveMapPath(path)
	}
}

func (ms *MapSweeper) walk(path string, _ os.FileInfo, _ error) error {
	filename := filepath.Base(path)

	mapPrefix := []string{
		policymap.MapName,
		ctmap.MapNameTCP6,
		ctmap.MapNameTCP4,
		ctmap.MapNameAny6,
		ctmap.MapNameAny4,
		callsmap.MapName,
		endpoint.IpvlanMapName,
	}

	ms.checkStaleGlobalMap(path, filename)

	for _, m := range mapPrefix {
		if strings.HasPrefix(filename, m) {
			if endpointID := strings.TrimPrefix(filename, m); endpointID != filename {
				ms.deleteMapIfStale(path, filename, endpointID)
			}
		}
	}

	return nil
}

// CollectStaleMapGarbage cleans up stale content in the BPF maps from the
// datapath.
func (ms *MapSweeper) CollectStaleMapGarbage() {
	if err := filepath.Walk(bpf.MapPrefixPath(), ms.walk); err != nil {
		log.WithError(err).Warn("Error while scanning for stale maps")
	}
}

// RemoveDisabledMaps removes BPF maps in the filesystem for features that have
// been disabled. The maps may still be in use in which case they will continue
// to live until the BPF program using them is being replaced.
func (ms *MapSweeper) RemoveDisabledMaps() {
	maps := []string{}

	if !option.Config.EnableIPv6 {
		maps = append(maps, []string{
			"cilium_ct6_global",
			"cilium_ct_any6_global",
			"cilium_lb6_reverse_nat",
			"cilium_lb6_rr_seq",
			"cilium_lb6_services",
			"cilium_lb6_services_v2",
			"cilium_lb6_rr_seq_v2",
			"cilium_lb6_backends",
			"cilium_lb6_reverse_sk",
			"cilium_snat_v6_external",
			"cilium_proxy6",
			lbmap.MaglevOuter6MapName,
			lbmap.Affinity6MapName,
			lbmap.SourceRange6MapName,
		}...)
	}

	if !option.Config.EnableIPv4 {
		maps = append(maps, []string{
			"cilium_ct4_global",
			"cilium_ct_any4_global",
			"cilium_lb4_reverse_nat",
			"cilium_lb4_rr_seq",
			"cilium_lb4_services",
			"cilium_lb4_services_v2",
			"cilium_lb4_rr_seq_v2",
			"cilium_lb4_backends",
			"cilium_lb4_reverse_sk",
			"cilium_snat_v4_external",
			"cilium_proxy4",
			lbmap.MaglevOuter4MapName,
			lbmap.Affinity4MapName,
			lbmap.SourceRange4MapName,
			ipmasq.MapName,
		}...)
	}

	if !option.Config.EnableIPv4FragmentsTracking {
		maps = append(maps, "cilium_ipv4_frag_datagrams")
	}

	if !option.Config.EnableBandwidthManager {
		maps = append(maps, "cilium_throttle")
	}

	if option.Config.NodePortAlg != option.NodePortAlgMaglev {
		maps = append(maps, lbmap.MaglevOuter6MapName, lbmap.MaglevOuter4MapName)
	}

	if !option.Config.EnableSessionAffinity {
		maps = append(maps, lbmap.Affinity6MapName, lbmap.Affinity4MapName, lbmap.AffinityMatchMapName)
	}

	if !option.Config.EnableSVCSourceRangeCheck {
		maps = append(maps, lbmap.SourceRange6MapName, lbmap.SourceRange4MapName)
	}

	if !option.Config.EnableIPMasqAgent {
		maps = append(maps, ipmasq.MapName)
	}

	for _, m := range maps {
		p := path.Join(bpf.MapPrefixPath(), m)
		if _, err := os.Stat(p); !os.IsNotExist(err) {
			ms.RemoveMapPath(p)
		}
	}
}
<|endoftext|>


<commit_before>package middleware

import (
	"bytes"
	"encoding/json"
	"log"
	"net/http"
	"strings"

	"github.com/gorilla/context"
	"github.com/sprioc/sprioc-core/pkg/core"
	"github.com/sprioc/sprioc-core/pkg/rsp"
)

func Secure(f func(http.ResponseWriter, *http.Request) rsp.Response) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")

		user, resp := core.CheckUser(r)
		if !resp.Ok() {
			log.Println(resp)
			w.WriteHeader(resp.Code)
			w.Write(resp.Format())
			return
		}

		context.Set(r, "auth", user)

		setIP(r)

		resp = f(w, r)

		w.WriteHeader(resp.Code)

		dat, err := JSONMarshal(resp.Data, true)
		if err != nil {
			log.Println(err)
		}

		if resp.Data != nil {
			w.Write(dat) // TODO this writes null if the resp.Data is null.
		} else if resp.Message != "" {
			w.Write(resp.Format())
		}
	}
}

func Unsecure(f func(http.ResponseWriter, *http.Request) rsp.Response) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {

		w.Header().Set("Content-Type", "application/json")

		setIP(r)

		resp := f(w, r)
		w.WriteHeader(resp.Code)

		dat, _ := JSONMarshal(resp.Data, true)
		if resp.Data != nil {
			w.Write(dat) // TODO this writes null if the resp.Data is null.
		} else if resp.Message != "" {
			w.Write(resp.Format())
		}
	}
}

func JSONMarshal(v interface{}, unescape bool) ([]byte, error) {
	b, err := json.MarshalIndent(v, "", "    ")

	if unescape {
		b = bytes.Replace(b, []byte("\\u003c"), []byte("<"), -1)
		b = bytes.Replace(b, []byte("\\u003e"), []byte(">"), -1)
		b = bytes.Replace(b, []byte("\\u0026"), []byte("&"), -1)
	}
	return b, err
}

func setIP(r *http.Request) {
	ips, ok := r.Header["x-forwarded-for"]
	if !ok {
		log.Println(ips, ok)
	}

	log.Println(strings.Join(ips, "///"))

	trueIP := ips[len(ips)]

	context.Set(r, "ip", trueIP)

}
<commit_msg>off by one and case sensitivity fixes<commit_after>package middleware

import (
	"bytes"
	"encoding/json"
	"log"
	"net/http"
	"strings"

	"github.com/gorilla/context"
	"github.com/sprioc/sprioc-core/pkg/core"
	"github.com/sprioc/sprioc-core/pkg/rsp"
)

func Secure(f func(http.ResponseWriter, *http.Request) rsp.Response) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")

		user, resp := core.CheckUser(r)
		if !resp.Ok() {
			log.Println(resp)
			w.WriteHeader(resp.Code)
			w.Write(resp.Format())
			return
		}

		context.Set(r, "auth", user)

		setIP(r)

		resp = f(w, r)

		w.WriteHeader(resp.Code)

		dat, err := JSONMarshal(resp.Data, true)
		if err != nil {
			log.Println(err)
		}

		if resp.Data != nil {
			w.Write(dat) // TODO this writes null if the resp.Data is null.
		} else if resp.Message != "" {
			w.Write(resp.Format())
		}
	}
}

func Unsecure(f func(http.ResponseWriter, *http.Request) rsp.Response) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {

		w.Header().Set("Content-Type", "application/json")

		setIP(r)

		resp := f(w, r)
		w.WriteHeader(resp.Code)

		dat, _ := JSONMarshal(resp.Data, true)
		if resp.Data != nil {
			w.Write(dat) // TODO this writes null if the resp.Data is null.
		} else if resp.Message != "" {
			w.Write(resp.Format())
		}
	}
}

func JSONMarshal(v interface{}, unescape bool) ([]byte, error) {
	b, err := json.MarshalIndent(v, "", "    ")

	if unescape {
		b = bytes.Replace(b, []byte("\\u003c"), []byte("<"), -1)
		b = bytes.Replace(b, []byte("\\u003e"), []byte(">"), -1)
		b = bytes.Replace(b, []byte("\\u0026"), []byte("&"), -1)
	}
	return b, err
}

func setIP(r *http.Request) {
	ips, ok := r.Header["X-Forwarded-For"]
	if !ok {
		log.Println(ips, ok)
		return
	}

	log.Println(strings.Join(ips, ", "))

	trueIP := ips[len(ips)-1]

	context.Set(r, "ip", trueIP)

}
<|endoftext|>


<commit_before>package models

import (
	"errors"
	"time"

	"github.com/grafana/grafana/pkg/components/securejsondata"
	"github.com/grafana/grafana/pkg/components/simplejson"
)

const (
	DS_GRAPHITE      = "graphite"
	DS_INFLUXDB      = "influxdb"
	DS_INFLUXDB_08   = "influxdb_08"
	DS_ES            = "elasticsearch"
	DS_OPENTSDB      = "opentsdb"
	DS_CLOUDWATCH    = "cloudwatch"
	DS_KAIROSDB      = "kairosdb"
	DS_PROMETHEUS    = "prometheus"
	DS_POSTGRES      = "postgres"
	DS_MYSQL         = "mysql"
	DS_MSSQL         = "mssql"
	DS_ACCESS_DIRECT = "direct"
	DS_ACCESS_PROXY  = "proxy"
	DS_STACKDRIVER   = "stackdriver"
	DS_AZURE_MONITOR = "grafana-azure-monitor-datasource"
)

var (
	ErrDataSourceNotFound           = errors.New("Data source not found")
	ErrDataSourceNameExists         = errors.New("Data source with same name already exists")
	ErrDataSourceUpdatingOldVersion = errors.New("Trying to update old version of datasource")
	ErrDatasourceIsReadOnly         = errors.New("Data source is readonly. Can only be updated from configuration")
	ErrDataSourceAccessDenied       = errors.New("Data source access denied")
)

type DsAccess string

type DataSource struct {
	Id      int64
	OrgId   int64
	Version int

	Name              string
	Type              string
	Access            DsAccess
	Url               string
	Password          string
	User              string
	Database          string
	BasicAuth         bool
	BasicAuthUser     string
	BasicAuthPassword string
	WithCredentials   bool
	IsDefault         bool
	JsonData          *simplejson.Json
	SecureJsonData    securejsondata.SecureJsonData
	ReadOnly          bool

	Created time.Time
	Updated time.Time
}

// DecryptedBasicAuthPassword returns data source basic auth password in plain text. It uses either deprecated
// basic_auth_password field or encrypted secure_json_data[basicAuthPassword] variable.
func (ds *DataSource) DecryptedBasicAuthPassword() string {
	return ds.decryptedValue("basicAuthPassword", ds.BasicAuthPassword)
}

// DecryptedPassword returns data source password in plain text. It uses either deprecated password field
// or encrypted secure_json_data[password] variable.
func (ds *DataSource) DecryptedPassword() string {
	return ds.decryptedValue("password", ds.Password)
}

// decryptedValue returns decrypted value from secureJsonData
func (ds *DataSource) decryptedValue(field string, fallback string) string {
	if value, ok := ds.SecureJsonData.DecryptedValue(field); ok {
		return value
	}
	return fallback
}

var knownDatasourcePlugins = map[string]bool{
	DS_ES:                                 true,
	DS_GRAPHITE:                           true,
	DS_INFLUXDB:                           true,
	DS_INFLUXDB_08:                        true,
	DS_KAIROSDB:                           true,
	DS_CLOUDWATCH:                         true,
	DS_PROMETHEUS:                         true,
	DS_OPENTSDB:                           true,
	DS_POSTGRES:                           true,
	DS_MYSQL:                              true,
	DS_MSSQL:                              true,
	DS_STACKDRIVER:                        true,
	DS_AZURE_MONITOR:                      true,
	"opennms":                             true,
	"abhisant-druid-datasource":           true,
	"dalmatinerdb-datasource":             true,
	"gnocci":                              true,
	"zabbix":                              true,
	"newrelic-app":                        true,
	"grafana-datadog-datasource":          true,
	"grafana-simple-json":                 true,
	"grafana-splunk-datasource":           true,
	"udoprog-heroic-datasource":           true,
	"grafana-openfalcon-datasource":       true,
	"opennms-datasource":                  true,
	"rackerlabs-blueflood-datasource":     true,
	"crate-datasource":                    true,
	"ayoungprogrammer-finance-datasource": true,
	"monasca-datasource":                  true,
	"vertamedia-clickhouse-datasource":    true,
	"alexanderzobnin-zabbix-datasource":   true,
}

func IsKnownDataSourcePlugin(dsType string) bool {
	_, exists := knownDatasourcePlugins[dsType]
	return exists
}

// ----------------------
// COMMANDS

// Also acts as api DTO
type AddDataSourceCommand struct {
	Name              string            `json:"name" binding:"Required"`
	Type              string            `json:"type" binding:"Required"`
	Access            DsAccess          `json:"access" binding:"Required"`
	Url               string            `json:"url"`
	Password          string            `json:"password"`
	Database          string            `json:"database"`
	User              string            `json:"user"`
	BasicAuth         bool              `json:"basicAuth"`
	BasicAuthUser     string            `json:"basicAuthUser"`
	BasicAuthPassword string            `json:"basicAuthPassword"`
	WithCredentials   bool              `json:"withCredentials"`
	IsDefault         bool              `json:"isDefault"`
	JsonData          *simplejson.Json  `json:"jsonData"`
	SecureJsonData    map[string]string `json:"secureJsonData"`
	ReadOnly          bool              `json:"readOnly"`

	OrgId int64 `json:"-"`

	Result *DataSource
}

// Also acts as api DTO
type UpdateDataSourceCommand struct {
	Name              string            `json:"name" binding:"Required"`
	Type              string            `json:"type" binding:"Required"`
	Access            DsAccess          `json:"access" binding:"Required"`
	Url               string            `json:"url"`
	Password          string            `json:"password"`
	User              string            `json:"user"`
	Database          string            `json:"database"`
	BasicAuth         bool              `json:"basicAuth"`
	BasicAuthUser     string            `json:"basicAuthUser"`
	BasicAuthPassword string            `json:"basicAuthPassword"`
	WithCredentials   bool              `json:"withCredentials"`
	IsDefault         bool              `json:"isDefault"`
	JsonData          *simplejson.Json  `json:"jsonData"`
	SecureJsonData    map[string]string `json:"secureJsonData"`
	Version           int               `json:"version"`
	ReadOnly          bool              `json:"readOnly"`

	OrgId int64 `json:"-"`
	Id    int64 `json:"-"`

	Result *DataSource
}

type DeleteDataSourceByIdCommand struct {
	Id    int64
	OrgId int64

	DeletedDatasourcesCount int64
}

type DeleteDataSourceByNameCommand struct {
	Name  string
	OrgId int64

	DeletedDatasourcesCount int64
}

// ---------------------
// QUERIES

type GetDataSourcesQuery struct {
	OrgId  int64
	User   *SignedInUser
	Result []*DataSource
}

type GetAllDataSourcesQuery struct {
	Result []*DataSource
}

type GetDataSourceByIdQuery struct {
	Id     int64
	OrgId  int64
	Result *DataSource
}

type GetDataSourceByNameQuery struct {
	Name   string
	OrgId  int64
	Result *DataSource
}

// ---------------------
//  Permissions
// ---------------------

type DsPermissionType int

const (
	DsPermissionNoAccess DsPermissionType = iota
	DsPermissionQuery
)

func (p DsPermissionType) String() string {
	names := map[int]string{
		int(DsPermissionQuery):    "Query",
		int(DsPermissionNoAccess): "No Access",
	}
	return names[int(p)]
}

type DatasourcesPermissionFilterQuery struct {
	User        *SignedInUser
	Datasources []*DataSource
	Result      []*DataSource
}
<commit_msg>Usage Stats: Update known datasource plugins (#17787)<commit_after>package models

import (
	"errors"
	"time"

	"github.com/grafana/grafana/pkg/components/securejsondata"
	"github.com/grafana/grafana/pkg/components/simplejson"
)

const (
	DS_GRAPHITE      = "graphite"
	DS_INFLUXDB      = "influxdb"
	DS_INFLUXDB_08   = "influxdb_08"
	DS_ES            = "elasticsearch"
	DS_OPENTSDB      = "opentsdb"
	DS_CLOUDWATCH    = "cloudwatch"
	DS_KAIROSDB      = "kairosdb"
	DS_PROMETHEUS    = "prometheus"
	DS_POSTGRES      = "postgres"
	DS_MYSQL         = "mysql"
	DS_MSSQL         = "mssql"
	DS_ACCESS_DIRECT = "direct"
	DS_ACCESS_PROXY  = "proxy"
	DS_STACKDRIVER   = "stackdriver"
	DS_AZURE_MONITOR = "grafana-azure-monitor-datasource"
	DS_LOKI          = "loki"
)

var (
	ErrDataSourceNotFound           = errors.New("Data source not found")
	ErrDataSourceNameExists         = errors.New("Data source with same name already exists")
	ErrDataSourceUpdatingOldVersion = errors.New("Trying to update old version of datasource")
	ErrDatasourceIsReadOnly         = errors.New("Data source is readonly. Can only be updated from configuration")
	ErrDataSourceAccessDenied       = errors.New("Data source access denied")
)

type DsAccess string

type DataSource struct {
	Id      int64
	OrgId   int64
	Version int

	Name              string
	Type              string
	Access            DsAccess
	Url               string
	Password          string
	User              string
	Database          string
	BasicAuth         bool
	BasicAuthUser     string
	BasicAuthPassword string
	WithCredentials   bool
	IsDefault         bool
	JsonData          *simplejson.Json
	SecureJsonData    securejsondata.SecureJsonData
	ReadOnly          bool

	Created time.Time
	Updated time.Time
}

// DecryptedBasicAuthPassword returns data source basic auth password in plain text. It uses either deprecated
// basic_auth_password field or encrypted secure_json_data[basicAuthPassword] variable.
func (ds *DataSource) DecryptedBasicAuthPassword() string {
	return ds.decryptedValue("basicAuthPassword", ds.BasicAuthPassword)
}

// DecryptedPassword returns data source password in plain text. It uses either deprecated password field
// or encrypted secure_json_data[password] variable.
func (ds *DataSource) DecryptedPassword() string {
	return ds.decryptedValue("password", ds.Password)
}

// decryptedValue returns decrypted value from secureJsonData
func (ds *DataSource) decryptedValue(field string, fallback string) string {
	if value, ok := ds.SecureJsonData.DecryptedValue(field); ok {
		return value
	}
	return fallback
}

var knownDatasourcePlugins = map[string]bool{
	DS_ES:                                    true,
	DS_GRAPHITE:                              true,
	DS_INFLUXDB:                              true,
	DS_INFLUXDB_08:                           true,
	DS_KAIROSDB:                              true,
	DS_CLOUDWATCH:                            true,
	DS_PROMETHEUS:                            true,
	DS_OPENTSDB:                              true,
	DS_POSTGRES:                              true,
	DS_MYSQL:                                 true,
	DS_MSSQL:                                 true,
	DS_STACKDRIVER:                           true,
	DS_AZURE_MONITOR:                         true,
	DS_LOKI:                                  true,
	"opennms":                                true,
	"abhisant-druid-datasource":              true,
	"dalmatinerdb-datasource":                true,
	"gnocci":                                 true,
	"zabbix":                                 true,
	"newrelic-app":                           true,
	"grafana-datadog-datasource":             true,
	"grafana-simple-json":                    true,
	"grafana-splunk-datasource":              true,
	"udoprog-heroic-datasource":              true,
	"grafana-openfalcon-datasource":          true,
	"opennms-datasource":                     true,
	"rackerlabs-blueflood-datasource":        true,
	"crate-datasource":                       true,
	"ayoungprogrammer-finance-datasource":    true,
	"monasca-datasource":                     true,
	"vertamedia-clickhouse-datasource":       true,
	"alexanderzobnin-zabbix-datasource":      true,
	"grafana-influxdb-flux-datasource":       true,
	"doitintl-bigquery-datasource":           true,
	"grafana-azure-data-explorer-datasource": true,
}

func IsKnownDataSourcePlugin(dsType string) bool {
	_, exists := knownDatasourcePlugins[dsType]
	return exists
}

// ----------------------
// COMMANDS

// Also acts as api DTO
type AddDataSourceCommand struct {
	Name              string            `json:"name" binding:"Required"`
	Type              string            `json:"type" binding:"Required"`
	Access            DsAccess          `json:"access" binding:"Required"`
	Url               string            `json:"url"`
	Password          string            `json:"password"`
	Database          string            `json:"database"`
	User              string            `json:"user"`
	BasicAuth         bool              `json:"basicAuth"`
	BasicAuthUser     string            `json:"basicAuthUser"`
	BasicAuthPassword string            `json:"basicAuthPassword"`
	WithCredentials   bool              `json:"withCredentials"`
	IsDefault         bool              `json:"isDefault"`
	JsonData          *simplejson.Json  `json:"jsonData"`
	SecureJsonData    map[string]string `json:"secureJsonData"`
	ReadOnly          bool              `json:"readOnly"`

	OrgId int64 `json:"-"`

	Result *DataSource
}

// Also acts as api DTO
type UpdateDataSourceCommand struct {
	Name              string            `json:"name" binding:"Required"`
	Type              string            `json:"type" binding:"Required"`
	Access            DsAccess          `json:"access" binding:"Required"`
	Url               string            `json:"url"`
	Password          string            `json:"password"`
	User              string            `json:"user"`
	Database          string            `json:"database"`
	BasicAuth         bool              `json:"basicAuth"`
	BasicAuthUser     string            `json:"basicAuthUser"`
	BasicAuthPassword string            `json:"basicAuthPassword"`
	WithCredentials   bool              `json:"withCredentials"`
	IsDefault         bool              `json:"isDefault"`
	JsonData          *simplejson.Json  `json:"jsonData"`
	SecureJsonData    map[string]string `json:"secureJsonData"`
	Version           int               `json:"version"`
	ReadOnly          bool              `json:"readOnly"`

	OrgId int64 `json:"-"`
	Id    int64 `json:"-"`

	Result *DataSource
}

type DeleteDataSourceByIdCommand struct {
	Id    int64
	OrgId int64

	DeletedDatasourcesCount int64
}

type DeleteDataSourceByNameCommand struct {
	Name  string
	OrgId int64

	DeletedDatasourcesCount int64
}

// ---------------------
// QUERIES

type GetDataSourcesQuery struct {
	OrgId  int64
	User   *SignedInUser
	Result []*DataSource
}

type GetAllDataSourcesQuery struct {
	Result []*DataSource
}

type GetDataSourceByIdQuery struct {
	Id     int64
	OrgId  int64
	Result *DataSource
}

type GetDataSourceByNameQuery struct {
	Name   string
	OrgId  int64
	Result *DataSource
}

// ---------------------
//  Permissions
// ---------------------

type DsPermissionType int

const (
	DsPermissionNoAccess DsPermissionType = iota
	DsPermissionQuery
)

func (p DsPermissionType) String() string {
	names := map[int]string{
		int(DsPermissionQuery):    "Query",
		int(DsPermissionNoAccess): "No Access",
	}
	return names[int(p)]
}

type DatasourcesPermissionFilterQuery struct {
	User        *SignedInUser
	Datasources []*DataSource
	Result      []*DataSource
}
<|endoftext|>


<commit_before>package uuid

import (
	"os"

	uuid "github.com/nu7hatch/gouuid"
	"github.com/sapk/sca/pkg/model"
	log "github.com/sirupsen/logrus"
)

const id = "UUID"

//Module retrieve information form executing sca
type Module struct {
	UUID string
}

//Response describe collector informations
type Response string

//New constructor for Module
func New(options map[string]string) model.Module {
	log.WithFields(log.Fields{
		"id":      id,
		"options": options,
	}).Debug("Creating new Module")
	hostname, err := os.Hostname() //TODO maybe cache it at build time ?
	if err != nil {
		log.WithFields(log.Fields{
			"hostname": hostname,
			"err":      err,
		}).Warn("Failed to retrieve hostname")
	}
	u5, err := uuid.NewV5(uuid.NamespaceURL, []byte(hostname)) //TODO better discriminate maybe add time and save it in /etc/sca/uuid ?
	if err != nil {
		log.WithFields(log.Fields{
			"uuid": u5,
			"err":  err,
		}).Fatal("Failed to generate uuid")
	}
	return &Module{UUID: u5.String()} //TODO use option to get a user or config (/etc/sca/uuid ?) defined uuid
}

//ID //TODO
func (m *Module) ID() string {
	return id
}

//Event return event chan
func (m *Module) Event() <-chan string {
	return nil
}

//GetData //TODO
func (m *Module) GetData() interface{} {
	return m.UUID
}
<commit_msg>Update uuid.go<commit_after>package uuid

import (
	"os"

	uuid "github.com/nu7hatch/gouuid"
	"github.com/sapk/sca/pkg/model"
	log "github.com/sirupsen/logrus"
)

const id = "UUID"

//Module retrieve information form executing sca
type Module struct {
	UUID string
}

//Response describe collector informations
type Response string

//New constructor for Module
func New(options map[string]string) model.Module {
	log.WithFields(log.Fields{
		"id":      id,
		"options": options,
	}).Debug("Creating new Module")
	hostname, err := os.Hostname()
	if err != nil {
		log.WithFields(log.Fields{
			"hostname": hostname,
			"err":      err,
		}).Warn("Failed to retrieve hostname")
	}
	u5, err := uuid.NewV5(uuid.NamespaceURL, []byte(hostname)) //TODO better discriminate maybe add time and save it in /etc/sca/uuid ?
	if err != nil {
		log.WithFields(log.Fields{
			"uuid": u5,
			"err":  err,
		}).Fatal("Failed to generate uuid")
	}
	return &Module{UUID: u5.String()} //TODO use option to get a user or config (/etc/sca/uuid or via cmd ?) defined uuid

//ID //TODO
func (m *Module) ID() string {
	return id
}

//Event return event chan
func (m *Module) Event() <-chan string {
	return nil
}

//GetData //TODO
func (m *Module) GetData() interface{} {
	return m.UUID
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"io"
	"os"

	"github.com/spf13/cobra"

	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	kapi "k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/kubectl/resource"
	kprinters "k8s.io/kubernetes/pkg/printers"

	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
	templateapi "github.com/openshift/origin/pkg/template/apis/template"
)

var (
	exportLong = templates.LongDesc(`
		Export resources so they can be used elsewhere

		The export command makes it easy to take existing objects and convert them to configuration files
		for backups or for creating elsewhere in the cluster. Fields that cannot be specified on create
		will be set to empty, and any field which is assigned on creation (like a service's clusterIP, or
		a deployment config's latestVersion). The status part of objects is also cleared.

		Some fields like clusterIP may be useful when exporting an application from one cluster to apply
		to another - assuming another service on the destination cluster does not already use that IP.
		The --exact flag will instruct export to not clear fields that might be useful. You may also use
		--raw to get the exact values for an object - useful for converting a file on disk between API
		versions.

		Another use case for export is to create reusable templates for applications. Pass --as-template
		to generate the API structure for a template to which you can add parameters and object labels.`)

	exportExample = templates.Examples(`
		# export the services and deployment configurations labeled name=test
	  %[1]s export svc,dc -l name=test

	  # export all services to a template
	  %[1]s export service --as-template=test

	  # export to JSON
	  %[1]s export service -o json`)
)

func NewCmdExport(fullName string, f *clientcmd.Factory, in io.Reader, out io.Writer) *cobra.Command {
	exporter := &DefaultExporter{}
	var filenames []string
	cmd := &cobra.Command{
		Use:     "export RESOURCE/NAME ... [options]",
		Short:   "Export resources so they can be used elsewhere",
		Long:    exportLong,
		Example: fmt.Sprintf(exportExample, fullName),
		Run: func(cmd *cobra.Command, args []string) {
			err := RunExport(f, exporter, in, out, cmd, args, filenames)
			if err == kcmdutil.ErrExit {
				os.Exit(1)
			}
			kcmdutil.CheckErr(err)
		},
	}
	cmd.Flags().String("as-template", "", "Output a Template object with specified name instead of a List or single object.")
	cmd.Flags().Bool("exact", false, "If true, preserve fields that may be cluster specific, such as service clusterIPs or generated names")
	cmd.Flags().Bool("raw", false, "If true, do not alter the resources in any way after they are loaded.")
	cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on")
	cmd.Flags().Bool("all-namespaces", false, "If true, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")
	cmd.Flags().StringSliceVarP(&filenames, "filename", "f", filenames, "Filename, directory, or URL to file for the resource to export.")
	cmd.MarkFlagFilename("filename")
	cmd.Flags().Bool("all", true, "DEPRECATED: all is ignored, specifying a resource without a name selects all the instances of that resource")
	cmd.Flags().MarkDeprecated("all", "all is ignored because specifying a resource without a name selects all the instances of that resource")
	kcmdutil.AddPrinterFlags(cmd)
	return cmd
}

func RunExport(f *clientcmd.Factory, exporter Exporter, in io.Reader, out io.Writer, cmd *cobra.Command, args []string, filenames []string) error {
	selector := kcmdutil.GetFlagString(cmd, "selector")
	allNamespaces := kcmdutil.GetFlagBool(cmd, "all-namespaces")
	exact := kcmdutil.GetFlagBool(cmd, "exact")
	asTemplate := kcmdutil.GetFlagString(cmd, "as-template")
	raw := kcmdutil.GetFlagBool(cmd, "raw")
	if exact && raw {
		return kcmdutil.UsageError(cmd, "--exact and --raw may not both be specified")
	}

	clientConfig, err := f.ClientConfig()
	if err != nil {
		return err
	}

	var outputVersion schema.GroupVersion
	outputVersionString := kcmdutil.GetFlagString(cmd, "output-version")
	if len(outputVersionString) == 0 {
		outputVersion = *clientConfig.GroupVersion
	} else {
		outputVersion, err = schema.ParseGroupVersion(outputVersionString)
		if err != nil {
			return err
		}
	}

	cmdNamespace, explicit, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	builder, err := f.NewUnstructuredBuilder(true)
	if err != nil {
		return err
	}

	mapper, typer, err := f.UnstructuredObject()
	if err != nil {
		return err
	}

	b := builder.
		NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
		FilenameParam(explicit, &resource.FilenameOptions{Recursive: false, Filenames: filenames}).
		SelectorParam(selector).
		ResourceTypeOrNameArgs(true, args...).
		Flatten()

	one := false
	infos, err := b.Do().IntoSingleItemImplied(&one).Infos()
	if err != nil {
		return err
	}

	if len(infos) == 0 {
		return fmt.Errorf("no resources found - nothing to export")
	}

	if !raw {
		newInfos := []*resource.Info{}
		errs := []error{}
		for _, info := range infos {
			if err := exporter.Export(info.Object, exact); err != nil {
				if err == ErrExportOmit {
					continue
				}
				errs = append(errs, err)
			}
			newInfos = append(newInfos, info)
		}
		if len(errs) > 0 {
			return utilerrors.NewAggregate(errs)
		}
		infos = newInfos
	}

	var result runtime.Object
	if len(asTemplate) > 0 {
		objects, err := resource.AsVersionedObjects(infos, outputVersion, kapi.Codecs.LegacyCodec(outputVersion))
		if err != nil {
			return err
		}
		template := &templateapi.Template{
			Objects: objects,
		}
		template.Name = asTemplate
		result, err = kapi.Scheme.ConvertToVersion(template, outputVersion)
		if err != nil {
			return err
		}
	} else {
		object, err := resource.AsVersionedObject(infos, !one, outputVersion, kapi.Codecs.LegacyCodec(outputVersion))
		if err != nil {
			return err
		}
		result = object
	}

	// use YAML as the default format
	outputFormat := kcmdutil.GetFlagString(cmd, "output")
	templateFile := kcmdutil.GetFlagString(cmd, "template")
	if len(outputFormat) == 0 && len(templateFile) != 0 {
		outputFormat = "template"
	}
	if len(outputFormat) == 0 {
		outputFormat = "yaml"
	}
	decoders := []runtime.Decoder{f.Decoder(true), unstructured.UnstructuredJSONScheme}
	p, err := kprinters.GetStandardPrinter(
		&kprinters.OutputOptions{
			FmtType:          outputFormat,
			FmtArg:           templateFile,
			AllowMissingKeys: kcmdutil.GetFlagBool(cmd, "allow-missing-template-keys"),
		},
		kcmdutil.GetFlagBool(cmd, "no-headers"), mapper, typer, kapi.Codecs.LegacyCodec(outputVersion), decoders, kprinters.PrintOptions{})

	if err != nil {
		return err
	}
	return p.PrintObj(result, out)
}
<commit_msg>convert unstructured objs before exporting<commit_after>package cmd

import (
	"fmt"
	"io"
	"os"

	"github.com/spf13/cobra"

	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
	kapi "k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/kubectl/resource"
	kprinters "k8s.io/kubernetes/pkg/printers"

	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
	templateapi "github.com/openshift/origin/pkg/template/apis/template"
)

var (
	exportLong = templates.LongDesc(`
		Export resources so they can be used elsewhere

		The export command makes it easy to take existing objects and convert them to configuration files
		for backups or for creating elsewhere in the cluster. Fields that cannot be specified on create
		will be set to empty, and any field which is assigned on creation (like a service's clusterIP, or
		a deployment config's latestVersion). The status part of objects is also cleared.

		Some fields like clusterIP may be useful when exporting an application from one cluster to apply
		to another - assuming another service on the destination cluster does not already use that IP.
		The --exact flag will instruct export to not clear fields that might be useful. You may also use
		--raw to get the exact values for an object - useful for converting a file on disk between API
		versions.

		Another use case for export is to create reusable templates for applications. Pass --as-template
		to generate the API structure for a template to which you can add parameters and object labels.`)

	exportExample = templates.Examples(`
		# export the services and deployment configurations labeled name=test
	  %[1]s export svc,dc -l name=test

	  # export all services to a template
	  %[1]s export service --as-template=test

	  # export to JSON
	  %[1]s export service -o json`)
)

func NewCmdExport(fullName string, f *clientcmd.Factory, in io.Reader, out io.Writer) *cobra.Command {
	exporter := &DefaultExporter{}
	var filenames []string
	cmd := &cobra.Command{
		Use:     "export RESOURCE/NAME ... [options]",
		Short:   "Export resources so they can be used elsewhere",
		Long:    exportLong,
		Example: fmt.Sprintf(exportExample, fullName),
		Run: func(cmd *cobra.Command, args []string) {
			err := RunExport(f, exporter, in, out, cmd, args, filenames)
			if err == kcmdutil.ErrExit {
				os.Exit(1)
			}
			kcmdutil.CheckErr(err)
		},
	}
	cmd.Flags().String("as-template", "", "Output a Template object with specified name instead of a List or single object.")
	cmd.Flags().Bool("exact", false, "If true, preserve fields that may be cluster specific, such as service clusterIPs or generated names")
	cmd.Flags().Bool("raw", false, "If true, do not alter the resources in any way after they are loaded.")
	cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on")
	cmd.Flags().Bool("all-namespaces", false, "If true, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")
	cmd.Flags().StringSliceVarP(&filenames, "filename", "f", filenames, "Filename, directory, or URL to file for the resource to export.")
	cmd.MarkFlagFilename("filename")
	cmd.Flags().Bool("all", true, "DEPRECATED: all is ignored, specifying a resource without a name selects all the instances of that resource")
	cmd.Flags().MarkDeprecated("all", "all is ignored because specifying a resource without a name selects all the instances of that resource")
	kcmdutil.AddPrinterFlags(cmd)
	return cmd
}

func RunExport(f *clientcmd.Factory, exporter Exporter, in io.Reader, out io.Writer, cmd *cobra.Command, args []string, filenames []string) error {
	selector := kcmdutil.GetFlagString(cmd, "selector")
	allNamespaces := kcmdutil.GetFlagBool(cmd, "all-namespaces")
	exact := kcmdutil.GetFlagBool(cmd, "exact")
	asTemplate := kcmdutil.GetFlagString(cmd, "as-template")
	raw := kcmdutil.GetFlagBool(cmd, "raw")
	if exact && raw {
		return kcmdutil.UsageError(cmd, "--exact and --raw may not both be specified")
	}

	clientConfig, err := f.ClientConfig()
	if err != nil {
		return err
	}

	var outputVersion schema.GroupVersion
	outputVersionString := kcmdutil.GetFlagString(cmd, "output-version")
	if len(outputVersionString) == 0 {
		outputVersion = *clientConfig.GroupVersion
	} else {
		outputVersion, err = schema.ParseGroupVersion(outputVersionString)
		if err != nil {
			return err
		}
	}

	cmdNamespace, explicit, err := f.DefaultNamespace()
	if err != nil {
		return err
	}

	builder, err := f.NewUnstructuredBuilder(true)
	if err != nil {
		return err
	}

	mapper, typer, err := f.UnstructuredObject()
	if err != nil {
		return err
	}

	b := builder.
		NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
		FilenameParam(explicit, &resource.FilenameOptions{Recursive: false, Filenames: filenames}).
		SelectorParam(selector).
		ResourceTypeOrNameArgs(true, args...).
		Flatten()

	one := false
	infos, err := b.Do().IntoSingleItemImplied(&one).Infos()
	if err != nil {
		return err
	}

	if len(infos) == 0 {
		return fmt.Errorf("no resources found - nothing to export")
	}

	if !raw {
		newInfos := []*resource.Info{}
		errs := []error{}
		for _, info := range infos {
			converted := false

			// convert unstructured object to runtime.Object
			data, err := runtime.Encode(kapi.Codecs.LegacyCodec(), info.Object)
			if err != nil {
				errs = append(errs, err)
				continue
			}
			decoded, err := runtime.Decode(f.Decoder(true), data)
			if err == nil {
				// ignore error, if any, in order to allow resources
				// not known by the client to still be exported
				info.Object = decoded
				converted = true
			}

			if err := exporter.Export(info.Object, exact); err != nil {
				if err == ErrExportOmit {
					continue
				}
				errs = append(errs, err)
			}

			// if an unstructured resource was successfully converted by the universal decoder,
			// re-convert that object once again into its external version.
			// If object cannot be converted to an external version, ignore error and proceed with
			// internal version.
			if converted {
				if data, err = runtime.Encode(kapi.Codecs.LegacyCodec(outputVersion), info.Object); err == nil {
					external, err := runtime.Decode(f.Decoder(false), data)
					if err != nil {
						errs = append(errs, fmt.Errorf("error: failed to convert resource to external version: %v", err))
						continue
					}
					info.Object = external
				}
			}

			newInfos = append(newInfos, info)
		}
		if len(errs) > 0 {
			return utilerrors.NewAggregate(errs)
		}
		infos = newInfos
	}

	var result runtime.Object
	if len(asTemplate) > 0 {
		objects, err := resource.AsVersionedObjects(infos, outputVersion, kapi.Codecs.LegacyCodec(outputVersion))
		if err != nil {
			return err
		}
		template := &templateapi.Template{
			Objects: objects,
		}
		template.Name = asTemplate
		result, err = kapi.Scheme.ConvertToVersion(template, outputVersion)
		if err != nil {
			return err
		}
	} else {
		object, err := resource.AsVersionedObject(infos, !one, outputVersion, kapi.Codecs.LegacyCodec(outputVersion))
		if err != nil {
			return err
		}
		result = object
	}

	// use YAML as the default format
	outputFormat := kcmdutil.GetFlagString(cmd, "output")
	templateFile := kcmdutil.GetFlagString(cmd, "template")
	if len(outputFormat) == 0 && len(templateFile) != 0 {
		outputFormat = "template"
	}
	if len(outputFormat) == 0 {
		outputFormat = "yaml"
	}
	decoders := []runtime.Decoder{f.Decoder(true), unstructured.UnstructuredJSONScheme}
	p, err := kprinters.GetStandardPrinter(
		&kprinters.OutputOptions{
			FmtType:          outputFormat,
			FmtArg:           templateFile,
			AllowMissingKeys: kcmdutil.GetFlagBool(cmd, "allow-missing-template-keys"),
		},
		kcmdutil.GetFlagBool(cmd, "no-headers"), mapper, typer, kapi.Codecs.LegacyCodec(outputVersion), decoders, kprinters.PrintOptions{})

	if err != nil {
		return err
	}
	return p.PrintObj(result, out)
}
<|endoftext|>


<commit_before>package sshagent

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"os"
	"path/filepath"
	"sync"
	"time"

	"github.com/opencontainers/selinux/go-selinux"
	"github.com/sirupsen/logrus"
	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"
)

// AgentServer is an ssh agent that can be served and shutdown at a later time
type AgentServer struct {
	agent     agent.Agent
	wg        sync.WaitGroup
	conn      *net.Conn
	listener  net.Listener
	shutdown  chan bool
	servePath string
	serveDir  string
}

// NewAgentServer creates a new agent on the host
func NewAgentServer(source *Source) (*AgentServer, error) {
	if source.Keys != nil {
		return newAgentServerKeyring(source.Keys)
	}
	return newAgentServerSocket(source.Socket)
}

// newAgentServerKeyring creates a new agent from scratch and adds keys
func newAgentServerKeyring(keys []interface{}) (*AgentServer, error) {
	a := agent.NewKeyring()
	for _, k := range keys {
		if err := a.Add(agent.AddedKey{PrivateKey: k}); err != nil {
			return nil, fmt.Errorf("failed to create ssh agent: %w", err)
		}
	}
	return &AgentServer{
		agent:    a,
		shutdown: make(chan bool, 1),
	}, nil
}

// newAgentServerSocket creates a new agent from an existing agent on the host
func newAgentServerSocket(socketPath string) (*AgentServer, error) {
	conn, err := net.Dial("unix", socketPath)
	if err != nil {
		return nil, err
	}
	a := &readOnlyAgent{agent.NewClient(conn)}

	return &AgentServer{
		agent:    a,
		conn:     &conn,
		shutdown: make(chan bool, 1),
	}, nil

}

// Serve starts the SSH agent on the host and returns the path of the socket where the agent is serving
func (a *AgentServer) Serve(processLabel string) (string, error) {
	err := selinux.SetSocketLabel(processLabel)
	if err != nil {
		return "", err
	}
	serveDir, err := ioutil.TempDir("", ".buildah-ssh-sock")
	if err != nil {
		return "", err
	}
	servePath := filepath.Join(serveDir, "ssh_auth_sock")
	a.serveDir = serveDir
	a.servePath = servePath
	listener, err := net.Listen("unix", servePath)
	if err != nil {
		return "", err
	}
	err = selinux.SetSocketLabel("")
	if err != nil {
		return "", err
	}
	a.listener = listener

	go func() {
		for {
			//listener.Accept blocks
			c, err := listener.Accept()
			if err != nil {
				select {
				case <-a.shutdown:
					return
				default:
					logrus.Errorf("error accepting SSH connection: %v", err)
					continue
				}
			}
			a.wg.Add(1)
			go func() {
				// agent.ServeAgent will only ever return with error,
				err := agent.ServeAgent(a.agent, c)
				if err != io.EOF {
					logrus.Errorf("error serving agent: %v", err)
				}
				a.wg.Done()
			}()
			// the only way to get agent.ServeAgent is to close the connection it's serving on
			// TODO: ideally we should use some sort of forwarding mechanism for output instead of manually closing connection.
			go func() {
				time.Sleep(2000 * time.Millisecond)
				c.Close()
			}()
		}
	}()
	return a.servePath, nil
}

// Shutdown shuts down the agent and closes the socket
func (a *AgentServer) Shutdown() error {
	if a.listener != nil {
		a.shutdown <- true
		a.listener.Close()
	}
	if a.conn != nil {
		conn := *a.conn
		conn.Close()
	}
	a.wg.Wait()
	err := os.RemoveAll(a.serveDir)
	if err != nil {
		return err
	}
	a.serveDir = ""
	a.servePath = ""
	return nil
}

// ServePath returns the path where the agent is serving
func (a *AgentServer) ServePath() string {
	return a.servePath
}

// readOnlyAgent and its functions originally from github.com/mopby/buildkit/session/sshforward/sshprovider/agentprovider.go

// readOnlyAgent implemetnts the agent.Agent interface
// readOnlyAgent allows reads only to prevent keys from being added from the build to the forwarded ssh agent on the host
type readOnlyAgent struct {
	agent.Agent
}

func (a *readOnlyAgent) Add(_ agent.AddedKey) error {
	return errors.New("adding new keys not allowed by buildah")
}

func (a *readOnlyAgent) Remove(_ ssh.PublicKey) error {
	return errors.New("removing keys not allowed by buildah")
}

func (a *readOnlyAgent) RemoveAll() error {
	return errors.New("removing keys not allowed by buildah")
}

func (a *readOnlyAgent) Lock(_ []byte) error {
	return errors.New("locking agent not allowed by buildah")
}

// Source is what the forwarded agent's source is
// The source of the forwarded agent can be from a socket on the host, or from individual key files
type Source struct {
	Socket string
	Keys   []interface{}
}

// NewSource takes paths and checks of they are keys or sockets, and creates a source
func NewSource(paths []string) (*Source, error) {
	var keys []interface{}
	var socket string
	if len(paths) == 0 {
		socket = os.Getenv("SSH_AUTH_SOCK")
		if socket == "" {
			return nil, errors.New("$SSH_AUTH_SOCK not set")
		}
	}
	for _, p := range paths {
		if socket != "" {
			return nil, errors.New("only one socket is allowed")
		}

		fi, err := os.Stat(p)
		if err != nil {
			return nil, err
		}
		if fi.Mode()&os.ModeSocket > 0 {
			if len(keys) == 0 {
				socket = p
			} else {
				return nil, errors.New("cannot mix keys and socket file")
			}
			continue
		}

		f, err := os.Open(p)
		if err != nil {
			return nil, err
		}
		dt, err := ioutil.ReadAll(&io.LimitedReader{R: f, N: 100 * 1024})
		if err != nil {
			return nil, err
		}

		k, err := ssh.ParseRawPrivateKey(dt)
		if err != nil {
			return nil, fmt.Errorf("cannot parse ssh key: %w", err)
		}
		keys = append(keys, k)
	}
	if socket != "" {
		return &Source{
			Socket: socket,
		}, nil
	}
	return &Source{
		Keys: keys,
	}, nil
}
<commit_msg>sshagent: LockOSThread before setting SocketLabel<commit_after>package sshagent

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"os"
	"path/filepath"
	"runtime"
	"sync"
	"time"

	"github.com/opencontainers/selinux/go-selinux"
	"github.com/sirupsen/logrus"
	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"
)

// AgentServer is an ssh agent that can be served and shutdown at a later time
type AgentServer struct {
	agent     agent.Agent
	wg        sync.WaitGroup
	conn      *net.Conn
	listener  net.Listener
	shutdown  chan bool
	servePath string
	serveDir  string
}

// NewAgentServer creates a new agent on the host
func NewAgentServer(source *Source) (*AgentServer, error) {
	if source.Keys != nil {
		return newAgentServerKeyring(source.Keys)
	}
	return newAgentServerSocket(source.Socket)
}

// newAgentServerKeyring creates a new agent from scratch and adds keys
func newAgentServerKeyring(keys []interface{}) (*AgentServer, error) {
	a := agent.NewKeyring()
	for _, k := range keys {
		if err := a.Add(agent.AddedKey{PrivateKey: k}); err != nil {
			return nil, fmt.Errorf("failed to create ssh agent: %w", err)
		}
	}
	return &AgentServer{
		agent:    a,
		shutdown: make(chan bool, 1),
	}, nil
}

// newAgentServerSocket creates a new agent from an existing agent on the host
func newAgentServerSocket(socketPath string) (*AgentServer, error) {
	conn, err := net.Dial("unix", socketPath)
	if err != nil {
		return nil, err
	}
	a := &readOnlyAgent{agent.NewClient(conn)}

	return &AgentServer{
		agent:    a,
		conn:     &conn,
		shutdown: make(chan bool, 1),
	}, nil

}

// Serve starts the SSH agent on the host and returns the path of the socket where the agent is serving
func (a *AgentServer) Serve(processLabel string) (string, error) {
	// Calls to `selinux.SetSocketLabel` should be wrapped in
	// runtime.LockOSThread()/runtime.UnlockOSThread() until
	// the the socket is created to guarantee another goroutine
	// does not migrate to the current thread before execution
	// is complete.
	// Ref: https://github.com/opencontainers/selinux/blob/main/go-selinux/selinux.go#L158
	runtime.LockOSThread()
	err := selinux.SetSocketLabel(processLabel)
	if err != nil {
		return "", err
	}
	serveDir, err := ioutil.TempDir("", ".buildah-ssh-sock")
	if err != nil {
		return "", err
	}
	servePath := filepath.Join(serveDir, "ssh_auth_sock")
	a.serveDir = serveDir
	a.servePath = servePath
	listener, err := net.Listen("unix", servePath)
	if err != nil {
		return "", err
	}
	// Reset socket label.
	err = selinux.SetSocketLabel("")
	// Unlock the thread only if the process label could be restored
	// successfully.  Otherwise leave the thread locked and the Go runtime
	// will terminate it once it returns to the threads pool.
	runtime.UnlockOSThread()
	if err != nil {
		return "", err
	}
	a.listener = listener

	go func() {
		for {
			//listener.Accept blocks
			c, err := listener.Accept()
			if err != nil {
				select {
				case <-a.shutdown:
					return
				default:
					logrus.Errorf("error accepting SSH connection: %v", err)
					continue
				}
			}
			a.wg.Add(1)
			go func() {
				// agent.ServeAgent will only ever return with error,
				err := agent.ServeAgent(a.agent, c)
				if err != io.EOF {
					logrus.Errorf("error serving agent: %v", err)
				}
				a.wg.Done()
			}()
			// the only way to get agent.ServeAgent is to close the connection it's serving on
			// TODO: ideally we should use some sort of forwarding mechanism for output instead of manually closing connection.
			go func() {
				time.Sleep(2000 * time.Millisecond)
				c.Close()
			}()
		}
	}()
	return a.servePath, nil
}

// Shutdown shuts down the agent and closes the socket
func (a *AgentServer) Shutdown() error {
	if a.listener != nil {
		a.shutdown <- true
		a.listener.Close()
	}
	if a.conn != nil {
		conn := *a.conn
		conn.Close()
	}
	a.wg.Wait()
	err := os.RemoveAll(a.serveDir)
	if err != nil {
		return err
	}
	a.serveDir = ""
	a.servePath = ""
	return nil
}

// ServePath returns the path where the agent is serving
func (a *AgentServer) ServePath() string {
	return a.servePath
}

// readOnlyAgent and its functions originally from github.com/mopby/buildkit/session/sshforward/sshprovider/agentprovider.go

// readOnlyAgent implemetnts the agent.Agent interface
// readOnlyAgent allows reads only to prevent keys from being added from the build to the forwarded ssh agent on the host
type readOnlyAgent struct {
	agent.Agent
}

func (a *readOnlyAgent) Add(_ agent.AddedKey) error {
	return errors.New("adding new keys not allowed by buildah")
}

func (a *readOnlyAgent) Remove(_ ssh.PublicKey) error {
	return errors.New("removing keys not allowed by buildah")
}

func (a *readOnlyAgent) RemoveAll() error {
	return errors.New("removing keys not allowed by buildah")
}

func (a *readOnlyAgent) Lock(_ []byte) error {
	return errors.New("locking agent not allowed by buildah")
}

// Source is what the forwarded agent's source is
// The source of the forwarded agent can be from a socket on the host, or from individual key files
type Source struct {
	Socket string
	Keys   []interface{}
}

// NewSource takes paths and checks of they are keys or sockets, and creates a source
func NewSource(paths []string) (*Source, error) {
	var keys []interface{}
	var socket string
	if len(paths) == 0 {
		socket = os.Getenv("SSH_AUTH_SOCK")
		if socket == "" {
			return nil, errors.New("$SSH_AUTH_SOCK not set")
		}
	}
	for _, p := range paths {
		if socket != "" {
			return nil, errors.New("only one socket is allowed")
		}

		fi, err := os.Stat(p)
		if err != nil {
			return nil, err
		}
		if fi.Mode()&os.ModeSocket > 0 {
			if len(keys) == 0 {
				socket = p
			} else {
				return nil, errors.New("cannot mix keys and socket file")
			}
			continue
		}

		f, err := os.Open(p)
		if err != nil {
			return nil, err
		}
		dt, err := ioutil.ReadAll(&io.LimitedReader{R: f, N: 100 * 1024})
		if err != nil {
			return nil, err
		}

		k, err := ssh.ParseRawPrivateKey(dt)
		if err != nil {
			return nil, fmt.Errorf("cannot parse ssh key: %w", err)
		}
		keys = append(keys, k)
	}
	if socket != "" {
		return &Source{
			Socket: socket,
		}, nil
	}
	return &Source{
		Keys: keys,
	}, nil
}
<|endoftext|>


<commit_before>// Copyright 2012 The Plotinum Authors. All rights reserved.
// Use of this source code is governed by an MIT-style license
// that can be found in the LICENSE file.

package plotter2

import (
	"code.google.com/p/plotinum/plot"
	"code.google.com/p/plotinum/vg"
	"fmt"
	"image/color"
	"math"
	"math/rand"
	"testing"
)

func TestDrawImage(t *testing.T) {
	if err := Example_horizontalBoxPlots().Save(4, 4, "test.png"); err != nil {
		t.Error(err)
	}
}

func TestDrawEps(t *testing.T) {
	if err := Example_horizontalBoxPlots().Save(4, 4, "test.eps"); err != nil {
		t.Error(err)
	}
}

func TestDrawSvg(t *testing.T) {
	if err := Example_horizontalBoxPlots().Save(4, 4, "test.svg"); err != nil {
		t.Error(err)
	}
}

// Example_functions draws some functions.
func Example_functions() *plot.Plot {
	p, err := plot.New()
	if err != nil {
		panic(err)
	}
	p.Title.Text = "Functions"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	quad := NewFunction(func(x float64) float64 { return x * x })
	quad.Color = color.RGBA{B: 255, A: 255}

	exp := NewFunction(func(x float64) float64 { return math.Pow(2, x) })
	exp.Dashes = []vg.Length{vg.Points(2), vg.Points(2)}
	exp.Width = vg.Points(2)
	exp.Color = color.RGBA{G: 255, A: 255}

	sin := NewFunction(func(x float64) float64 { return 10*math.Sin(x) + 50 })
	sin.Dashes = []vg.Length{vg.Points(4), vg.Points(5)}
	sin.Width = vg.Points(4)
	sin.Color = color.RGBA{R: 255, A: 255}

	p.Add(quad, exp, sin)
	p.Legend.Add("x^2", quad)
	p.Legend.Add("2^x", exp)
	p.Legend.Add("10*sin(x)+50", sin)
	p.Legend.ThumbnailWidth = vg.Inches(0.5)

	p.X.Min = 0
	p.X.Max = 10
	p.Y.Min = 0
	p.Y.Max = 100
	return p
}

// Example_verticalBoxPlots draws vertical boxplots.
func Example_verticalBoxPlots() *plot.Plot {
	rand.Seed(int64(0))
	n := 100
	uniform := make(ValueLabels, n)
	normal := make(ValueLabels, n)
	expon := make(ValueLabels, n)
	for i := 0; i < n; i++ {
		uniform[i].Value = rand.Float64()
		uniform[i].Label = fmt.Sprintf("%4.4f", uniform[i].Value)
		normal[i].Value = rand.NormFloat64()
		normal[i].Label = fmt.Sprintf("%4.4f", normal[i].Value)
		expon[i].Value = rand.ExpFloat64()
		expon[i].Label = fmt.Sprintf("%4.4f", expon[i].Value)
	}

	p, err := plot.New()
	if err != nil {
		panic(err)
	}
	p.Title.Text = "Box Plot"
	p.Y.Label.Text = "Values"

	// Make boxes for our data and add them to the plot.
	uniBox := NewBoxPlot(vg.Points(20), 0, uniform)
	uniLabels, err := uniBox.PointLabels(uniform)
	if err != nil {
		panic(err)
	}

	normBox := NewBoxPlot(vg.Points(20), 1, normal)
	normLabels, err := normBox.PointLabels(normal)
	if err != nil {
		panic(err)
	}

	expBox := NewBoxPlot(vg.Points(20), 2, expon)
	expLabels, err := expBox.PointLabels(expon)
	if err != nil {
		panic(err)
	}

	p.Add(uniBox, uniLabels, normBox, normLabels, expBox, expLabels)

	// Set the X axis of the plot to nominal with
	// the given names for x=0, x=1 and x=2.
	p.NominalX("Uniform\nDistribution", "Normal\nDistribution",
		"Exponential\nDistribution")
	return p
}

// Example_horizontalBoxPlots draws horizontal boxplots.
func Example_horizontalBoxPlots() *plot.Plot {
	rand.Seed(int64(0))
	n := 100
	uniform := make(ValueLabels, n)
	normal := make(ValueLabels, n)
	expon := make(ValueLabels, n)
	for i := 0; i < n; i++ {
		uniform[i].Value = rand.Float64()
		uniform[i].Label = fmt.Sprintf("%4.4f", uniform[i].Value)
		normal[i].Value = rand.NormFloat64()
		normal[i].Label = fmt.Sprintf("%4.4f", normal[i].Value)
		expon[i].Value = rand.ExpFloat64()
		expon[i].Label = fmt.Sprintf("%4.4f", expon[i].Value)
	}

	p, err := plot.New()
	if err != nil {
		panic(err)
	}
	p.Title.Text = "Horizontal Box Plot"
	p.X.Label.Text = "Values"

	// Make boxes for our data and add them to the plot.
	uniBox := HorizBoxPlot{NewBoxPlot(vg.Points(20), 0, uniform)}
	uniLabels, err := uniBox.PointLabels(uniform)
	if err != nil {
		panic(err)
	}

	normBox := HorizBoxPlot{NewBoxPlot(vg.Points(20), 1, normal)}
	normLabels, err := normBox.PointLabels(normal)
	if err != nil {
		panic(err)
	}

	expBox := HorizBoxPlot{NewBoxPlot(vg.Points(20), 2, expon)}
	expLabels, err := expBox.PointLabels(expon)
	if err != nil {
		panic(err)
	}
	p.Add(uniBox, uniLabels, normBox, normLabels, expBox, expLabels)

	// Set the Y axis of the plot to nominal with
	// the given names for y=0, y=1 and y=2.
	p.NominalY("Uniform\nDistribution", "Normal\nDistribution",
		"Exponential\nDistribution")
	return p
}

// Example_points draws some scatter points, a line,
// and a line with points.
func Example_points() *plot.Plot {
	rand.Seed(int64(0))

	n := 15
	scatterData := randomPoints(n)
	lineData := randomPoints(n)
	linePointsData := randomPoints(n)

	p, err := plot.New()
	if err != nil {
		panic(err)
	}
	p.Title.Text = "Points Example"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	s := NewScatter(scatterData)
	s.GlyphStyle.Color = color.RGBA{R: 255, B: 128, A: 255}
	s.GlyphStyle.Radius = vg.Points(3)

	l := NewLine(lineData)
	l.LineStyle.Width = vg.Points(1)
	l.LineStyle.Dashes = []vg.Length{vg.Points(5), vg.Points(5)}
	l.LineStyle.Color = color.RGBA{B: 255, A: 255}

	lp := NewLinePoints(linePointsData)
	lp.LineStyle.Color = color.RGBA{G: 255, A: 255}
	lp.GlyphStyle.Shape = plot.CircleGlyph
	lp.GlyphStyle.Color = color.RGBA{R: 255, A: 255}

	p.Add(s, l, lp)
	p.Legend.Add("scatter", s)
	p.Legend.Add("line", l)
	p.Legend.Add("line points", lp)

	return p
}

// randomPoints returns some random x, y points.
func randomPoints(n int) XYs {
	pts := make(XYs, n)
	for i := range pts {
		if i == 0 {
			pts[i].X = rand.Float64()
		} else {
			pts[i].X = pts[i-1].X + rand.Float64()
		}
		pts[i].Y = pts[i].X + 10*rand.Float64()
	}
	return pts
}

// An example of making a histogram.
func Example_histogram() *plot.Plot {
	rand.Seed(int64(0))
	n := 10000
	vals := make(XYs, n)
	for i := 0; i < n; i++ {
		vals[i].X = rand.NormFloat64()
		vals[i].Y = 1
	}

	p, err := plot.New()
	if err != nil {
		panic(err)
	}
	p.Title.Text = "Histogram"
	h := NewHistogram(vals, 16)
	h.Normalize(1)
	p.Add(h)

	// The normal distribution function
	norm := NewFunction(stdNorm)
	norm.Color = color.RGBA{R: 255, A: 255}
	norm.Width = vg.Points(2)
	p.Add(norm)

	return p
}

// stdNorm returns the probability of drawing a
// value from a standard normal distribution.
func stdNorm(x float64) float64 {
	const sigma = 1.0
	const mu = 0.0
	const root2π = 2.50662827459517818309
	return 1.0 / (sigma * root2π) * math.Exp(-((x-mu)*(x-mu))/(2*sigma*sigma))
}

func TestEmpty(t *testing.T) {
	p, err := plot.New()
	if err != nil {
		t.Error(err)
	}

	if err := p.Save(4, 4, "empty.svg"); err != nil {
		t.Error(err)
	}
}
<commit_msg>Add an example for drawing boxplots without labels. This shows off how easy it is to create box plots.<commit_after>// Copyright 2012 The Plotinum Authors. All rights reserved.
// Use of this source code is governed by an MIT-style license
// that can be found in the LICENSE file.

package plotter2

import (
	"code.google.com/p/plotinum/plot"
	"code.google.com/p/plotinum/vg"
	"fmt"
	"image/color"
	"math"
	"math/rand"
	"testing"
)

func TestDrawImage(t *testing.T) {
	if err := Example_horizontalBoxPlots().Save(4, 4, "test.png"); err != nil {
		t.Error(err)
	}
}

func TestDrawEps(t *testing.T) {
	if err := Example_boxPlots().Save(4, 4, "test.eps"); err != nil {
		t.Error(err)
	}
}

func TestDrawSvg(t *testing.T) {
	if err := Example_horizontalBoxPlots().Save(4, 4, "test.svg"); err != nil {
		t.Error(err)
	}
}

// Example_functions draws some functions.
func Example_functions() *plot.Plot {
	p, err := plot.New()
	if err != nil {
		panic(err)
	}
	p.Title.Text = "Functions"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	quad := NewFunction(func(x float64) float64 { return x * x })
	quad.Color = color.RGBA{B: 255, A: 255}

	exp := NewFunction(func(x float64) float64 { return math.Pow(2, x) })
	exp.Dashes = []vg.Length{vg.Points(2), vg.Points(2)}
	exp.Width = vg.Points(2)
	exp.Color = color.RGBA{G: 255, A: 255}

	sin := NewFunction(func(x float64) float64 { return 10*math.Sin(x) + 50 })
	sin.Dashes = []vg.Length{vg.Points(4), vg.Points(5)}
	sin.Width = vg.Points(4)
	sin.Color = color.RGBA{R: 255, A: 255}

	p.Add(quad, exp, sin)
	p.Legend.Add("x^2", quad)
	p.Legend.Add("2^x", exp)
	p.Legend.Add("10*sin(x)+50", sin)
	p.Legend.ThumbnailWidth = vg.Inches(0.5)

	p.X.Min = 0
	p.X.Max = 10
	p.Y.Min = 0
	p.Y.Max = 100
	return p
}

// Example_boxPlots draws vertical boxplots.
func Example_boxPlots() *plot.Plot {
	rand.Seed(int64(0))
	n := 100
	uniform := make(Values, n)
	normal := make(Values, n)
	expon := make(Values, n)
	for i := 0; i < n; i++ {
		uniform[i] = rand.Float64()
		normal[i] = rand.NormFloat64()
		expon[i] = rand.ExpFloat64()
	}

	p, err := plot.New()
	if err != nil {
		panic(err)
	}
	p.Title.Text = "Box Plot"
	p.Y.Label.Text = "Values"

	// Make boxes for our data and add them to the plot.
	p.Add(NewBoxPlot(vg.Points(20), 0, uniform),
		NewBoxPlot(vg.Points(20), 1, normal),
		NewBoxPlot(vg.Points(20), 2, expon))

	// Set the X axis of the plot to nominal with
	// the given names for x=0, x=1 and x=2.
	p.NominalX("Uniform\nDistribution", "Normal\nDistribution",
		"Exponential\nDistribution")
	return p
}

// Example_verticalBoxPlots draws vertical boxplots
// with some labels on their points.
func Example_verticalBoxPlots() *plot.Plot {
	rand.Seed(int64(0))
	n := 100
	uniform := make(ValueLabels, n)
	normal := make(ValueLabels, n)
	expon := make(ValueLabels, n)
	for i := 0; i < n; i++ {
		uniform[i].Value = rand.Float64()
		uniform[i].Label = fmt.Sprintf("%4.4f", uniform[i].Value)
		normal[i].Value = rand.NormFloat64()
		normal[i].Label = fmt.Sprintf("%4.4f", normal[i].Value)
		expon[i].Value = rand.ExpFloat64()
		expon[i].Label = fmt.Sprintf("%4.4f", expon[i].Value)
	}

	p, err := plot.New()
	if err != nil {
		panic(err)
	}
	p.Title.Text = "Box Plot"
	p.Y.Label.Text = "Values"

	// Make boxes for our data and add them to the plot.
	uniBox := NewBoxPlot(vg.Points(20), 0, uniform)
	uniLabels, err := uniBox.PointLabels(uniform)
	if err != nil {
		panic(err)
	}

	normBox := NewBoxPlot(vg.Points(20), 1, normal)
	normLabels, err := normBox.PointLabels(normal)
	if err != nil {
		panic(err)
	}

	expBox := NewBoxPlot(vg.Points(20), 2, expon)
	expLabels, err := expBox.PointLabels(expon)
	if err != nil {
		panic(err)
	}

	p.Add(uniBox, uniLabels, normBox, normLabels, expBox, expLabels)

	// Set the X axis of the plot to nominal with
	// the given names for x=0, x=1 and x=2.
	p.NominalX("Uniform\nDistribution", "Normal\nDistribution",
		"Exponential\nDistribution")
	return p
}

// Example_horizontalBoxPlots draws horizontal boxplots
// with some labels on their points.
func Example_horizontalBoxPlots() *plot.Plot {
	rand.Seed(int64(0))
	n := 100
	uniform := make(ValueLabels, n)
	normal := make(ValueLabels, n)
	expon := make(ValueLabels, n)
	for i := 0; i < n; i++ {
		uniform[i].Value = rand.Float64()
		uniform[i].Label = fmt.Sprintf("%4.4f", uniform[i].Value)
		normal[i].Value = rand.NormFloat64()
		normal[i].Label = fmt.Sprintf("%4.4f", normal[i].Value)
		expon[i].Value = rand.ExpFloat64()
		expon[i].Label = fmt.Sprintf("%4.4f", expon[i].Value)
	}

	p, err := plot.New()
	if err != nil {
		panic(err)
	}
	p.Title.Text = "Horizontal Box Plot"
	p.X.Label.Text = "Values"

	// Make boxes for our data and add them to the plot.
	uniBox := HorizBoxPlot{NewBoxPlot(vg.Points(20), 0, uniform)}
	uniLabels, err := uniBox.PointLabels(uniform)
	if err != nil {
		panic(err)
	}

	normBox := HorizBoxPlot{NewBoxPlot(vg.Points(20), 1, normal)}
	normLabels, err := normBox.PointLabels(normal)
	if err != nil {
		panic(err)
	}

	expBox := HorizBoxPlot{NewBoxPlot(vg.Points(20), 2, expon)}
	expLabels, err := expBox.PointLabels(expon)
	if err != nil {
		panic(err)
	}
	p.Add(uniBox, uniLabels, normBox, normLabels, expBox, expLabels)

	// Set the Y axis of the plot to nominal with
	// the given names for y=0, y=1 and y=2.
	p.NominalY("Uniform\nDistribution", "Normal\nDistribution",
		"Exponential\nDistribution")
	return p
}

// Example_points draws some scatter points, a line,
// and a line with points.
func Example_points() *plot.Plot {
	rand.Seed(int64(0))

	n := 15
	scatterData := randomPoints(n)
	lineData := randomPoints(n)
	linePointsData := randomPoints(n)

	p, err := plot.New()
	if err != nil {
		panic(err)
	}
	p.Title.Text = "Points Example"
	p.X.Label.Text = "X"
	p.Y.Label.Text = "Y"

	s := NewScatter(scatterData)
	s.GlyphStyle.Color = color.RGBA{R: 255, B: 128, A: 255}
	s.GlyphStyle.Radius = vg.Points(3)

	l := NewLine(lineData)
	l.LineStyle.Width = vg.Points(1)
	l.LineStyle.Dashes = []vg.Length{vg.Points(5), vg.Points(5)}
	l.LineStyle.Color = color.RGBA{B: 255, A: 255}

	lp := NewLinePoints(linePointsData)
	lp.LineStyle.Color = color.RGBA{G: 255, A: 255}
	lp.GlyphStyle.Shape = plot.CircleGlyph
	lp.GlyphStyle.Color = color.RGBA{R: 255, A: 255}

	p.Add(s, l, lp)
	p.Legend.Add("scatter", s)
	p.Legend.Add("line", l)
	p.Legend.Add("line points", lp)

	return p
}

// randomPoints returns some random x, y points.
func randomPoints(n int) XYs {
	pts := make(XYs, n)
	for i := range pts {
		if i == 0 {
			pts[i].X = rand.Float64()
		} else {
			pts[i].X = pts[i-1].X + rand.Float64()
		}
		pts[i].Y = pts[i].X + 10*rand.Float64()
	}
	return pts
}

// An example of making a histogram.
func Example_histogram() *plot.Plot {
	rand.Seed(int64(0))
	n := 10000
	vals := make(XYs, n)
	for i := 0; i < n; i++ {
		vals[i].X = rand.NormFloat64()
		vals[i].Y = 1
	}

	p, err := plot.New()
	if err != nil {
		panic(err)
	}
	p.Title.Text = "Histogram"
	h := NewHistogram(vals, 16)
	h.Normalize(1)
	p.Add(h)

	// The normal distribution function
	norm := NewFunction(stdNorm)
	norm.Color = color.RGBA{R: 255, A: 255}
	norm.Width = vg.Points(2)
	p.Add(norm)

	return p
}

// stdNorm returns the probability of drawing a
// value from a standard normal distribution.
func stdNorm(x float64) float64 {
	const sigma = 1.0
	const mu = 0.0
	const root2π = 2.50662827459517818309
	return 1.0 / (sigma * root2π) * math.Exp(-((x-mu)*(x-mu))/(2*sigma*sigma))
}

func TestEmpty(t *testing.T) {
	p, err := plot.New()
	if err != nil {
		t.Error(err)
	}

	if err := p.Save(4, 4, "empty.svg"); err != nil {
		t.Error(err)
	}
}
<|endoftext|>