<commit_before>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package cmd

import (
	"fmt"
	"io"

	"k8s.io/apiserver/pkg/util/flag"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/kubernetes/pkg/kubectl/cmd/auth"
	cmdconfig "k8s.io/kubernetes/pkg/kubectl/cmd/config"
	"k8s.io/kubernetes/pkg/kubectl/cmd/rollout"
	"k8s.io/kubernetes/pkg/kubectl/cmd/set"
	"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/kubectl/util/i18n"

	"github.com/golang/glog"
	"github.com/spf13/cobra"
)

const (
	bashCompletionFunc = `# call kubectl get $1,
__kubectl_override_flag_list=(kubeconfig cluster user context namespace server)
__kubectl_override_flags()
{
    local ${__kubectl_override_flag_list[*]} two_word_of of
    for w in "${words[@]}"; do
        if [ -n "${two_word_of}" ]; then
            eval "${two_word_of}=\"--${two_word_of}=\${w}\""
            two_word_of=
            continue
        fi
        for of in "${__kubectl_override_flag_list[@]}"; do
            case "${w}" in
                --${of}=*)
                    eval "${of}=\"${w}\""
                    ;;
                --${of})
                    two_word_of="${of}"
                    ;;
            esac
        done
        if [ "${w}" == "--all-namespaces" ]; then
            namespace="--all-namespaces"
        fi
    done
    for of in "${__kubectl_override_flag_list[@]}"; do
        if eval "test -n \"\$${of}\""; then
            eval "echo \${${of}}"
        fi
    done
}

__kubectl_config_get_contexts()
{
    __kubectl_parse_config "contexts"
}

__kubectl_config_get_clusters()
{
    __kubectl_parse_config "clusters"
}

__kubectl_config_get_users()
{
    __kubectl_parse_config "users"
}

# $1 has to be "contexts", "clusters" or "users"
__kubectl_parse_config()
{
    local template kubectl_out
    template="{{ range .$1  }}{{ .name }} {{ end }}"
    if kubectl_out=$(kubectl config $(__kubectl_override_flags) -o template --template="${template}" view 2>/dev/null); then
        COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
    fi
}

__kubectl_parse_get()
{
    local template
    template="{{ range .items  }}{{ .metadata.name }} {{ end }}"
    local kubectl_out
    if kubectl_out=$(kubectl get $(__kubectl_override_flags) -o template --template="${template}" "$1" 2>/dev/null); then
        COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
    fi
}

__kubectl_get_resource()
{
    if [[ ${#nouns[@]} -eq 0 ]]; then
        return 1
    fi
    __kubectl_parse_get "${nouns[${#nouns[@]} -1]}"
}

__kubectl_get_resource_namespace()
{
    __kubectl_parse_get "namespace"
}

__kubectl_get_resource_pod()
{
    __kubectl_parse_get "pod"
}

__kubectl_get_resource_rc()
{
    __kubectl_parse_get "rc"
}

__kubectl_get_resource_node()
{
    __kubectl_parse_get "node"
}

__kubectl_get_resource_clusterrole()
{
    __kubectl_parse_get "clusterrole"
}

# $1 is the name of the pod we want to get the list of containers inside
__kubectl_get_containers()
{
    local template
    template="{{ range .spec.containers  }}{{ .name }} {{ end }}"
    __debug "${FUNCNAME} nouns are ${nouns[*]}"

    local len="${#nouns[@]}"
    if [[ ${len} -ne 1 ]]; then
        return
    fi
    local last=${nouns[${len} -1]}
    local kubectl_out
    if kubectl_out=$(kubectl get $(__kubectl_override_flags) -o template --template="${template}" pods "${last}" 2>/dev/null); then
        COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
    fi
}

# Require both a pod and a container to be specified
__kubectl_require_pod_and_container()
{
    if [[ ${#nouns[@]} -eq 0 ]]; then
        __kubectl_parse_get pods
        return 0
    fi;
    __kubectl_get_containers
    return 0
}

__custom_func() {
    case ${last_command} in
        kubectl_get | kubectl_describe | kubectl_delete | kubectl_label | kubectl_edit | kubectl_patch |\
        kubectl_annotate | kubectl_expose | kubectl_scale | kubectl_autoscale | kubectl_taint | kubectl_rollout_*)
            __kubectl_get_resource
            return
            ;;
        kubectl_logs | kubectl_attach)
            __kubectl_require_pod_and_container
            return
            ;;
        kubectl_exec | kubectl_port-forward | kubectl_top_pod)
            __kubectl_get_resource_pod
            return
            ;;
        kubectl_rolling-update)
            __kubectl_get_resource_rc
            return
            ;;
        kubectl_cordon | kubectl_uncordon | kubectl_drain | kubectl_top_node)
            __kubectl_get_resource_node
            return
            ;;
        kubectl_config_use-context)
            __kubectl_config_get_contexts
            return
            ;;
        kubectl_config_delete-cluster)
            __kubectl_config_get_clusters
            return
            ;;
        *)
            ;;
    esac
}
`

	// If you add a resource to this list, please also take a look at pkg/kubectl/kubectl.go
	// and add a short forms entry in expandResourceShortcut() when appropriate.
	// TODO: This should be populated using the discovery information from apiserver.
	validResources = `Valid resource types include:

    * all
    * certificatesigningrequests (aka 'csr')
    * clusterrolebindings
    * clusterroles
    * clusters (valid only for federation apiservers)
    * componentstatuses (aka 'cs')
    * configmaps (aka 'cm')
    * controllerrevisions
    * cronjobs
    * customresourcedefinition (aka 'crd')
    * daemonsets (aka 'ds')
    * deployments (aka 'deploy')
    * endpoints (aka 'ep')
    * events (aka 'ev')
    * horizontalpodautoscalers (aka 'hpa')
    * ingresses (aka 'ing')
    * jobs
    * limitranges (aka 'limits')
    * namespaces (aka 'ns')
    * networkpolicies (aka 'netpol')
    * nodes (aka 'no')
    * persistentvolumeclaims (aka 'pvc')
    * persistentvolumes (aka 'pv')
    * poddisruptionbudgets (aka 'pdb')
    * podpreset
    * pods (aka 'po')
    * podsecuritypolicies (aka 'psp')
    * podtemplates
    * replicasets (aka 'rs')
    * replicationcontrollers (aka 'rc')
    * resourcequotas (aka 'quota')
    * rolebindings
    * roles
    * secrets
    * serviceaccounts (aka 'sa')
    * services (aka 'svc')
    * statefulsets
    * storageclasses

`
)

var (
	bash_completion_flags = map[string]string{
		"namespace": "__kubectl_get_resource_namespace",
		"context":   "__kubectl_config_get_contexts",
		"cluster":   "__kubectl_config_get_clusters",
		"user":      "__kubectl_config_get_users",
	}
)

// NewKubectlCommand creates the `kubectl` command and its nested children.
func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Command {
	// Parent command to which all subcommands are added.
	cmds := &cobra.Command{
		Use:   "kubectl",
		Short: i18n.T("kubectl controls the Kubernetes cluster manager"),
		Long: templates.LongDesc(`
      kubectl controls the Kubernetes cluster manager.

      Find more information at https://github.com/kubernetes/kubernetes.`),
		Run: runHelp,
		BashCompletionFunction: bashCompletionFunc,
	}

	f.BindFlags(cmds.PersistentFlags())
	f.BindExternalFlags(cmds.PersistentFlags())

	// Sending in 'nil' for the getLanguageFn() results in using
	// the LANG environment variable.
	//
	// TODO: Consider adding a flag or file preference for setting
	// the language, instead of just loading from the LANG env. variable.
	i18n.LoadTranslations("kubectl", nil)

	// From this point and forward we get warnings on flags that contain "_" separators
	cmds.SetGlobalNormalizationFunc(flag.WarnWordSepNormalizeFunc)

	groups := templates.CommandGroups{
		{
			Message: "Basic Commands (Beginner):",
			Commands: []*cobra.Command{
				NewCmdCreate(f, out, err),
				NewCmdExposeService(f, out),
				NewCmdRun(f, in, out, err),
				set.NewCmdSet(f, in, out, err),
				deprecatedAlias("run-container", NewCmdRun(f, in, out, err)),
			},
		},
		{
			Message: "Basic Commands (Intermediate):",
			Commands: []*cobra.Command{
				NewCmdGet(f, out, err),
				NewCmdExplain(f, out, err),
				NewCmdEdit(f, out, err),
				NewCmdDelete(f, out, err),
			},
		},
		{
			Message: "Deploy Commands:",
			Commands: []*cobra.Command{
				rollout.NewCmdRollout(f, out, err),
				NewCmdRollingUpdate(f, out),
				NewCmdScale(f, out),
				NewCmdAutoscale(f, out),
			},
		},
		{
			Message: "Cluster Management Commands:",
			Commands: []*cobra.Command{
				NewCmdCertificate(f, out),
				NewCmdClusterInfo(f, out),
				NewCmdTop(f, out, err),
				NewCmdCordon(f, out),
				NewCmdUncordon(f, out),
				NewCmdDrain(f, out, err),
				NewCmdTaint(f, out),
			},
		},
		{
			Message: "Troubleshooting and Debugging Commands:",
			Commands: []*cobra.Command{
				NewCmdDescribe(f, out, err),
				NewCmdLogs(f, out),
				NewCmdAttach(f, in, out, err),
				NewCmdExec(f, in, out, err),
				NewCmdPortForward(f, out, err),
				NewCmdProxy(f, out),
				NewCmdCp(f, out, err),
				auth.NewCmdAuth(f, out, err),
			},
		},
		{
			Message: "Advanced Commands:",
			Commands: []*cobra.Command{
				NewCmdApply("kubectl", f, out, err),
				NewCmdPatch(f, out),
				NewCmdReplace(f, out),
				NewCmdConvert(f, out),
			},
		},
		{
			Message: "Settings Commands:",
			Commands: []*cobra.Command{
				NewCmdLabel(f, out),
				NewCmdAnnotate(f, out),
				NewCmdCompletion(out, ""),
			},
		},
	}
	groups.Add(cmds)

	filters := []string{"options"}

	// Hide the "alpha" subcommand if there are no alpha commands in this build.
	alpha := NewCmdAlpha(f, in, out, err)
	if !alpha.HasSubCommands() {
		filters = append(filters, alpha.Name())
	}

	templates.ActsAsRootCommand(cmds, filters, groups...)

	for name, completion := range bash_completion_flags {
		if cmds.Flag(name) != nil {
			if cmds.Flag(name).Annotations == nil {
				cmds.Flag(name).Annotations = map[string][]string{}
			}
			cmds.Flag(name).Annotations[cobra.BashCompCustom] = append(
				cmds.Flag(name).Annotations[cobra.BashCompCustom],
				completion,
			)
		}
	}

	cmds.AddCommand(alpha)
	cmds.AddCommand(cmdconfig.NewCmdConfig(clientcmd.NewDefaultPathOptions(), out, err))
	cmds.AddCommand(NewCmdPlugin(f, in, out, err))
	cmds.AddCommand(NewCmdVersion(f, out))
	cmds.AddCommand(NewCmdApiVersions(f, out))
	cmds.AddCommand(NewCmdOptions(out))

	return cmds
}

func runHelp(cmd *cobra.Command, args []string) {
	cmd.Help()
}

func printDeprecationWarning(command, alias string) {
	glog.Warningf("%s is DEPRECATED and will be removed in a future version. Use %s instead.", alias, command)
}

// deprecatedAlias is intended to be used to create a "wrapper" command around
// an existing command. The wrapper works the same but prints a deprecation
// message before running. This command is identical functionality.
func deprecatedAlias(deprecatedVersion string, cmd *cobra.Command) *cobra.Command {
	// Have to be careful here because Cobra automatically extracts the name
	// of the command from the .Use field.
	originalName := cmd.Name()

	cmd.Use = deprecatedVersion
	cmd.Deprecated = fmt.Sprintf("use %q instead", originalName)
	cmd.Short = fmt.Sprintf("%s. This command is deprecated, use %q instead", cmd.Short, originalName)
	cmd.Hidden = true
	return cmd
}

// deprecated is similar to deprecatedAlias, but it is used for deprecations
// that are not simple aliases; this command is actually a different
// (deprecated) codepath.
func deprecated(baseName, to string, parent, cmd *cobra.Command) string {
	cmd.Long = fmt.Sprintf("Deprecated: all functionality can be found in \"%s %s\"", baseName, to)
	cmd.Short = fmt.Sprintf("Deprecated: use %s", to)
	parent.AddCommand(cmd)
	return cmd.Name()
}
<commit_msg>Add missing short names to kubectl help text<commit_after>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package cmd

import (
	"fmt"
	"io"

	"k8s.io/apiserver/pkg/util/flag"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/kubernetes/pkg/kubectl/cmd/auth"
	cmdconfig "k8s.io/kubernetes/pkg/kubectl/cmd/config"
	"k8s.io/kubernetes/pkg/kubectl/cmd/rollout"
	"k8s.io/kubernetes/pkg/kubectl/cmd/set"
	"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/kubectl/util/i18n"

	"github.com/golang/glog"
	"github.com/spf13/cobra"
)

const (
	bashCompletionFunc = `# call kubectl get $1,
__kubectl_override_flag_list=(kubeconfig cluster user context namespace server)
__kubectl_override_flags()
{
    local ${__kubectl_override_flag_list[*]} two_word_of of
    for w in "${words[@]}"; do
        if [ -n "${two_word_of}" ]; then
            eval "${two_word_of}=\"--${two_word_of}=\${w}\""
            two_word_of=
            continue
        fi
        for of in "${__kubectl_override_flag_list[@]}"; do
            case "${w}" in
                --${of}=*)
                    eval "${of}=\"${w}\""
                    ;;
                --${of})
                    two_word_of="${of}"
                    ;;
            esac
        done
        if [ "${w}" == "--all-namespaces" ]; then
            namespace="--all-namespaces"
        fi
    done
    for of in "${__kubectl_override_flag_list[@]}"; do
        if eval "test -n \"\$${of}\""; then
            eval "echo \${${of}}"
        fi
    done
}

__kubectl_config_get_contexts()
{
    __kubectl_parse_config "contexts"
}

__kubectl_config_get_clusters()
{
    __kubectl_parse_config "clusters"
}

__kubectl_config_get_users()
{
    __kubectl_parse_config "users"
}

# $1 has to be "contexts", "clusters" or "users"
__kubectl_parse_config()
{
    local template kubectl_out
    template="{{ range .$1  }}{{ .name }} {{ end }}"
    if kubectl_out=$(kubectl config $(__kubectl_override_flags) -o template --template="${template}" view 2>/dev/null); then
        COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
    fi
}

__kubectl_parse_get()
{
    local template
    template="{{ range .items  }}{{ .metadata.name }} {{ end }}"
    local kubectl_out
    if kubectl_out=$(kubectl get $(__kubectl_override_flags) -o template --template="${template}" "$1" 2>/dev/null); then
        COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
    fi
}

__kubectl_get_resource()
{
    if [[ ${#nouns[@]} -eq 0 ]]; then
        return 1
    fi
    __kubectl_parse_get "${nouns[${#nouns[@]} -1]}"
}

__kubectl_get_resource_namespace()
{
    __kubectl_parse_get "namespace"
}

__kubectl_get_resource_pod()
{
    __kubectl_parse_get "pod"
}

__kubectl_get_resource_rc()
{
    __kubectl_parse_get "rc"
}

__kubectl_get_resource_node()
{
    __kubectl_parse_get "node"
}

__kubectl_get_resource_clusterrole()
{
    __kubectl_parse_get "clusterrole"
}

# $1 is the name of the pod we want to get the list of containers inside
__kubectl_get_containers()
{
    local template
    template="{{ range .spec.containers  }}{{ .name }} {{ end }}"
    __debug "${FUNCNAME} nouns are ${nouns[*]}"

    local len="${#nouns[@]}"
    if [[ ${len} -ne 1 ]]; then
        return
    fi
    local last=${nouns[${len} -1]}
    local kubectl_out
    if kubectl_out=$(kubectl get $(__kubectl_override_flags) -o template --template="${template}" pods "${last}" 2>/dev/null); then
        COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
    fi
}

# Require both a pod and a container to be specified
__kubectl_require_pod_and_container()
{
    if [[ ${#nouns[@]} -eq 0 ]]; then
        __kubectl_parse_get pods
        return 0
    fi;
    __kubectl_get_containers
    return 0
}

__custom_func() {
    case ${last_command} in
        kubectl_get | kubectl_describe | kubectl_delete | kubectl_label | kubectl_edit | kubectl_patch |\
        kubectl_annotate | kubectl_expose | kubectl_scale | kubectl_autoscale | kubectl_taint | kubectl_rollout_*)
            __kubectl_get_resource
            return
            ;;
        kubectl_logs | kubectl_attach)
            __kubectl_require_pod_and_container
            return
            ;;
        kubectl_exec | kubectl_port-forward | kubectl_top_pod)
            __kubectl_get_resource_pod
            return
            ;;
        kubectl_rolling-update)
            __kubectl_get_resource_rc
            return
            ;;
        kubectl_cordon | kubectl_uncordon | kubectl_drain | kubectl_top_node)
            __kubectl_get_resource_node
            return
            ;;
        kubectl_config_use-context)
            __kubectl_config_get_contexts
            return
            ;;
        kubectl_config_delete-cluster)
            __kubectl_config_get_clusters
            return
            ;;
        *)
            ;;
    esac
}
`

	// If you add a resource to this list, please also take a look at pkg/kubectl/kubectl.go
	// and add a short forms entry in expandResourceShortcut() when appropriate.
	// TODO: This should be populated using the discovery information from apiserver.
	validResources = `Valid resource types include:

    * all
    * certificatesigningrequests (aka 'csr')
    * clusterrolebindings
    * clusterroles
    * clusters (valid only for federation apiservers)
    * componentstatuses (aka 'cs')
    * configmaps (aka 'cm')
    * controllerrevisions
    * cronjobs
    * customresourcedefinition (aka 'crd')
    * daemonsets (aka 'ds')
    * deployments (aka 'deploy')
    * endpoints (aka 'ep')
    * events (aka 'ev')
    * horizontalpodautoscalers (aka 'hpa')
    * ingresses (aka 'ing')
    * jobs
    * limitranges (aka 'limits')
    * namespaces (aka 'ns')
    * networkpolicies (aka 'netpol')
    * nodes (aka 'no')
    * persistentvolumeclaims (aka 'pvc')
    * persistentvolumes (aka 'pv')
    * poddisruptionbudgets (aka 'pdb')
    * podpreset
    * pods (aka 'po')
    * podsecuritypolicies (aka 'psp')
    * podtemplates
    * replicasets (aka 'rs')
    * replicationcontrollers (aka 'rc')
    * resourcequotas (aka 'quota')
    * rolebindings
    * roles
    * secrets
    * serviceaccounts (aka 'sa')
    * services (aka 'svc')
    * statefulsets (aka 'sts')
    * storageclasses (aka 'sc')

`
)

var (
	bash_completion_flags = map[string]string{
		"namespace": "__kubectl_get_resource_namespace",
		"context":   "__kubectl_config_get_contexts",
		"cluster":   "__kubectl_config_get_clusters",
		"user":      "__kubectl_config_get_users",
	}
)

// NewKubectlCommand creates the `kubectl` command and its nested children.
func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Command {
	// Parent command to which all subcommands are added.
	cmds := &cobra.Command{
		Use:   "kubectl",
		Short: i18n.T("kubectl controls the Kubernetes cluster manager"),
		Long: templates.LongDesc(`
      kubectl controls the Kubernetes cluster manager.

      Find more information at https://github.com/kubernetes/kubernetes.`),
		Run: runHelp,
		BashCompletionFunction: bashCompletionFunc,
	}

	f.BindFlags(cmds.PersistentFlags())
	f.BindExternalFlags(cmds.PersistentFlags())

	// Sending in 'nil' for the getLanguageFn() results in using
	// the LANG environment variable.
	//
	// TODO: Consider adding a flag or file preference for setting
	// the language, instead of just loading from the LANG env. variable.
	i18n.LoadTranslations("kubectl", nil)

	// From this point and forward we get warnings on flags that contain "_" separators
	cmds.SetGlobalNormalizationFunc(flag.WarnWordSepNormalizeFunc)

	groups := templates.CommandGroups{
		{
			Message: "Basic Commands (Beginner):",
			Commands: []*cobra.Command{
				NewCmdCreate(f, out, err),
				NewCmdExposeService(f, out),
				NewCmdRun(f, in, out, err),
				set.NewCmdSet(f, in, out, err),
				deprecatedAlias("run-container", NewCmdRun(f, in, out, err)),
			},
		},
		{
			Message: "Basic Commands (Intermediate):",
			Commands: []*cobra.Command{
				NewCmdGet(f, out, err),
				NewCmdExplain(f, out, err),
				NewCmdEdit(f, out, err),
				NewCmdDelete(f, out, err),
			},
		},
		{
			Message: "Deploy Commands:",
			Commands: []*cobra.Command{
				rollout.NewCmdRollout(f, out, err),
				NewCmdRollingUpdate(f, out),
				NewCmdScale(f, out),
				NewCmdAutoscale(f, out),
			},
		},
		{
			Message: "Cluster Management Commands:",
			Commands: []*cobra.Command{
				NewCmdCertificate(f, out),
				NewCmdClusterInfo(f, out),
				NewCmdTop(f, out, err),
				NewCmdCordon(f, out),
				NewCmdUncordon(f, out),
				NewCmdDrain(f, out, err),
				NewCmdTaint(f, out),
			},
		},
		{
			Message: "Troubleshooting and Debugging Commands:",
			Commands: []*cobra.Command{
				NewCmdDescribe(f, out, err),
				NewCmdLogs(f, out),
				NewCmdAttach(f, in, out, err),
				NewCmdExec(f, in, out, err),
				NewCmdPortForward(f, out, err),
				NewCmdProxy(f, out),
				NewCmdCp(f, out, err),
				auth.NewCmdAuth(f, out, err),
			},
		},
		{
			Message: "Advanced Commands:",
			Commands: []*cobra.Command{
				NewCmdApply("kubectl", f, out, err),
				NewCmdPatch(f, out),
				NewCmdReplace(f, out),
				NewCmdConvert(f, out),
			},
		},
		{
			Message: "Settings Commands:",
			Commands: []*cobra.Command{
				NewCmdLabel(f, out),
				NewCmdAnnotate(f, out),
				NewCmdCompletion(out, ""),
			},
		},
	}
	groups.Add(cmds)

	filters := []string{"options"}

	// Hide the "alpha" subcommand if there are no alpha commands in this build.
	alpha := NewCmdAlpha(f, in, out, err)
	if !alpha.HasSubCommands() {
		filters = append(filters, alpha.Name())
	}

	templates.ActsAsRootCommand(cmds, filters, groups...)

	for name, completion := range bash_completion_flags {
		if cmds.Flag(name) != nil {
			if cmds.Flag(name).Annotations == nil {
				cmds.Flag(name).Annotations = map[string][]string{}
			}
			cmds.Flag(name).Annotations[cobra.BashCompCustom] = append(
				cmds.Flag(name).Annotations[cobra.BashCompCustom],
				completion,
			)
		}
	}

	cmds.AddCommand(alpha)
	cmds.AddCommand(cmdconfig.NewCmdConfig(clientcmd.NewDefaultPathOptions(), out, err))
	cmds.AddCommand(NewCmdPlugin(f, in, out, err))
	cmds.AddCommand(NewCmdVersion(f, out))
	cmds.AddCommand(NewCmdApiVersions(f, out))
	cmds.AddCommand(NewCmdOptions(out))

	return cmds
}

func runHelp(cmd *cobra.Command, args []string) {
	cmd.Help()
}

func printDeprecationWarning(command, alias string) {
	glog.Warningf("%s is DEPRECATED and will be removed in a future version. Use %s instead.", alias, command)
}

// deprecatedAlias is intended to be used to create a "wrapper" command around
// an existing command. The wrapper works the same but prints a deprecation
// message before running. This command is identical functionality.
func deprecatedAlias(deprecatedVersion string, cmd *cobra.Command) *cobra.Command {
	// Have to be careful here because Cobra automatically extracts the name
	// of the command from the .Use field.
	originalName := cmd.Name()

	cmd.Use = deprecatedVersion
	cmd.Deprecated = fmt.Sprintf("use %q instead", originalName)
	cmd.Short = fmt.Sprintf("%s. This command is deprecated, use %q instead", cmd.Short, originalName)
	cmd.Hidden = true
	return cmd
}

// deprecated is similar to deprecatedAlias, but it is used for deprecations
// that are not simple aliases; this command is actually a different
// (deprecated) codepath.
func deprecated(baseName, to string, parent, cmd *cobra.Command) string {
	cmd.Long = fmt.Sprintf("Deprecated: all functionality can be found in \"%s %s\"", baseName, to)
	cmd.Short = fmt.Sprintf("Deprecated: use %s", to)
	parent.AddCommand(cmd)
	return cmd.Name()
}
<|endoftext|>


<commit_before>// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium

package logging

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"os"
	"regexp"
	"strings"
	"sync/atomic"

	"github.com/sirupsen/logrus"
	"k8s.io/klog/v2"

	"github.com/cilium/cilium/pkg/logging/logfields"
)

type LogFormat string

const (
	Syslog    = "syslog"
	LevelOpt  = "level"
	FormatOpt = "format"

	LogFormatText LogFormat = "text"
	LogFormatJSON LogFormat = "json"

	// DefaultLogFormat is the string representation of the default logrus.Formatter
	// we want to use (possible values: text or json)
	DefaultLogFormat LogFormat = LogFormatText

	// DefaultLogLevel is the default log level we want to use for our logrus.Formatter
	DefaultLogLevel logrus.Level = logrus.InfoLevel
)

// DefaultLogger is the base logrus logger. It is different from the logrus
// default to avoid external dependencies from writing out unexpectedly
var DefaultLogger = InitializeDefaultLogger()

func init() {
	log := DefaultLogger.WithField(logfields.LogSubsys, "klog")

	//Create a new flag set and set error handler
	klogFlags := flag.NewFlagSet("cilium", flag.ExitOnError)

	// Make sure that klog logging variables are initialized so that we can
	// update them from this file.
	klog.InitFlags(klogFlags)

	// Make sure klog does not log to stderr as we want it to control the output
	// of klog so we want klog to log the errors to each writer of each level.
	klogFlags.Set("logtostderr", "false")

	// We don't need all headers because logrus will already print them if
	// necessary.
	klogFlags.Set("skip_headers", "true")

	klog.SetOutputBySeverity("INFO", log.WriterLevel(logrus.InfoLevel))
	klog.SetOutputBySeverity("WARNING", log.WriterLevel(logrus.WarnLevel))
	klog.SetOutputBySeverity("ERROR", log.WriterLevel(logrus.ErrorLevel))
	klog.SetOutputBySeverity("FATAL", log.WriterLevel(logrus.FatalLevel))

	// Do not repeat log messages on all severities in klog
	klogFlags.Set("one_output", "true")
}

// LogOptions maps configuration key-value pairs related to logging.
type LogOptions map[string]string

// InitializeDefaultLogger returns a logrus Logger with a custom text formatter.
func InitializeDefaultLogger() (logger *logrus.Logger) {
	logger = logrus.New()
	logger.SetFormatter(GetFormatter(DefaultLogFormat))
	logger.SetLevel(DefaultLogLevel)
	return
}

// GetLogLevel returns the log level specified in the provided LogOptions. If
// it is not set in the options, it will return the default level.
func (o LogOptions) GetLogLevel() (level logrus.Level) {
	levelOpt, ok := o[LevelOpt]
	if !ok {
		return DefaultLogLevel
	}

	var err error
	if level, err = logrus.ParseLevel(levelOpt); err != nil {
		logrus.WithError(err).Warning("Ignoring user-configured log level")
		return DefaultLogLevel
	}

	return
}

// GetLogFormat returns the log format specified in the provided LogOptions. If
// it is not set in the options or is invalid, it will return the default format.
func (o LogOptions) GetLogFormat() LogFormat {
	formatOpt, ok := o[FormatOpt]
	if !ok {
		return DefaultLogFormat
	}

	formatOpt = strings.ToLower(formatOpt)
	re := regexp.MustCompile(`^(text|json)$`)
	if !re.MatchString(formatOpt) {
		logrus.WithError(
			fmt.Errorf("incorrect log format configured '%s', expected 'text' or 'json'", formatOpt),
		).Warning("Ignoring user-configured log format")
		return DefaultLogFormat
	}

	return LogFormat(formatOpt)
}

// SetLogLevel updates the DefaultLogger with a new logrus.Level
func SetLogLevel(logLevel logrus.Level) {
	DefaultLogger.SetLevel(logLevel)
}

// SetDefaultLogLevel updates the DefaultLogger with the DefaultLogLevel
func SetDefaultLogLevel() {
	DefaultLogger.SetLevel(DefaultLogLevel)
}

// SetLogLevelToDebug updates the DefaultLogger with the logrus.DebugLevel
func SetLogLevelToDebug() {
	DefaultLogger.SetLevel(logrus.DebugLevel)
}

// SetLogFormat updates the DefaultLogger with a new LogFormat
func SetLogFormat(logFormat LogFormat) {
	DefaultLogger.SetFormatter(GetFormatter(logFormat))
}

// SetDefaultLogFormat updates the DefaultLogger with the DefaultLogFormat
func SetDefaultLogFormat() {
	DefaultLogger.SetFormatter(GetFormatter(DefaultLogFormat))
}

// AddHooks adds additional logrus hook to default logger
func AddHooks(hooks ...logrus.Hook) {
	for _, hook := range hooks {
		DefaultLogger.AddHook(hook)
	}
}

// SetupLogging sets up each logging service provided in loggers and configures
// each logger with the provided logOpts.
func SetupLogging(loggers []string, logOpts LogOptions, tag string, debug bool) error {
	// Updating the default log format
	SetLogFormat(logOpts.GetLogFormat())

	// Set default logger to output to stdout if no loggers are provided.
	if len(loggers) == 0 {
		// TODO: switch to a per-logger version when we upgrade to logrus >1.0.3
		logrus.SetOutput(os.Stdout)
	}

	// Updating the default log level, overriding the log options if the debug arg is being set
	if debug {
		SetLogLevelToDebug()
	} else {
		SetLogLevel(logOpts.GetLogLevel())
	}

	// always suppress the default logger so libraries don't print things
	logrus.SetLevel(logrus.PanicLevel)

	// Iterate through all provided loggers and configure them according
	// to user-provided settings.
	for _, logger := range loggers {
		switch logger {
		case Syslog:
			if err := setupSyslog(logOpts, tag, debug); err != nil {
				return fmt.Errorf("failed to set up syslog: %w", err)
			}
		default:
			return fmt.Errorf("provided log driver %q is not a supported log driver", logger)
		}
	}

	return nil
}

// GetFormatter returns a configured logrus.Formatter with some specific values
// we want to have
func GetFormatter(format LogFormat) logrus.Formatter {
	switch format {
	case LogFormatText:
		return &logrus.TextFormatter{
			DisableTimestamp: true,
			DisableColors:    true,
		}
	case LogFormatJSON:
		return &logrus.JSONFormatter{
			DisableTimestamp: true,
		}
	}

	return nil
}

// validateOpts iterates through all of the keys and values in logOpts, and errors out if
// the key in logOpts is not a key in supportedOpts, or the value of corresponding key is
// not listed in the value of validKVs.
func (o LogOptions) validateOpts(logDriver string, supportedOpts map[string]bool, validKVs map[string][]string) error {
	for k, v := range o {
		if !supportedOpts[k] {
			return fmt.Errorf("provided configuration key %q is not supported as a logging option for log driver %s", k, logDriver)
		}
		if validValues, ok := validKVs[k]; ok {
			valid := false
			for _, vv := range validValues {
				if v == vv {
					valid = true
					break
				}
			}
			if !valid {
				return fmt.Errorf("provided configuration value %q is not a valid value for %q in log driver %s, valid values: %v", v, k, logDriver, validValues)
			}

		}
	}
	return nil
}

// getLogDriverConfig returns a map containing the key-value pairs that start
// with string logDriver from map logOpts.
func getLogDriverConfig(logDriver string, logOpts LogOptions) LogOptions {
	keysToValidate := make(LogOptions)
	for k, v := range logOpts {
		ok, err := regexp.MatchString(logDriver+".*", k)
		if err != nil {
			DefaultLogger.Fatal(err)
		}
		if ok {
			keysToValidate[k] = v
		}
	}
	return keysToValidate
}

// MultiLine breaks a multi line text into individual log entries and calls the
// logging function to log each entry
func MultiLine(logFn func(args ...interface{}), output string) {
	scanner := bufio.NewScanner(bytes.NewReader([]byte(output)))
	for scanner.Scan() {
		logFn(scanner.Text())
	}
}

// CanLogAt returns whether a log message at the given level would be
// logged by the given logger.
func CanLogAt(logger *logrus.Logger, level logrus.Level) bool {
	return GetLevel(logger) >= level
}

// GetLevel returns the log level of the given logger.
func GetLevel(logger *logrus.Logger) logrus.Level {
	return logrus.Level(atomic.LoadUint32((*uint32)(&logger.Level)))
}
<commit_msg>logging: Initialize klog from SetupLogging<commit_after>// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium

package logging

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"os"
	"regexp"
	"strings"
	"sync/atomic"

	"github.com/sirupsen/logrus"
	"k8s.io/klog/v2"

	"github.com/cilium/cilium/pkg/logging/logfields"
)

type LogFormat string

const (
	Syslog    = "syslog"
	LevelOpt  = "level"
	FormatOpt = "format"

	LogFormatText LogFormat = "text"
	LogFormatJSON LogFormat = "json"

	// DefaultLogFormat is the string representation of the default logrus.Formatter
	// we want to use (possible values: text or json)
	DefaultLogFormat LogFormat = LogFormatText

	// DefaultLogLevel is the default log level we want to use for our logrus.Formatter
	DefaultLogLevel logrus.Level = logrus.InfoLevel
)

// DefaultLogger is the base logrus logger. It is different from the logrus
// default to avoid external dependencies from writing out unexpectedly
var DefaultLogger = InitializeDefaultLogger()

func initializeKLog() {
	log := DefaultLogger.WithField(logfields.LogSubsys, "klog")

	//Create a new flag set and set error handler
	klogFlags := flag.NewFlagSet("cilium", flag.ExitOnError)

	// Make sure that klog logging variables are initialized so that we can
	// update them from this file.
	klog.InitFlags(klogFlags)

	// Make sure klog does not log to stderr as we want it to control the output
	// of klog so we want klog to log the errors to each writer of each level.
	klogFlags.Set("logtostderr", "false")

	// We don't need all headers because logrus will already print them if
	// necessary.
	klogFlags.Set("skip_headers", "true")

	klog.SetOutputBySeverity("INFO", log.WriterLevel(logrus.InfoLevel))
	klog.SetOutputBySeverity("WARNING", log.WriterLevel(logrus.WarnLevel))
	klog.SetOutputBySeverity("ERROR", log.WriterLevel(logrus.ErrorLevel))
	klog.SetOutputBySeverity("FATAL", log.WriterLevel(logrus.FatalLevel))

	// Do not repeat log messages on all severities in klog
	klogFlags.Set("one_output", "true")
}

// LogOptions maps configuration key-value pairs related to logging.
type LogOptions map[string]string

// InitializeDefaultLogger returns a logrus Logger with a custom text formatter.
func InitializeDefaultLogger() (logger *logrus.Logger) {
	logger = logrus.New()
	logger.SetFormatter(GetFormatter(DefaultLogFormat))
	logger.SetLevel(DefaultLogLevel)
	return
}

// GetLogLevel returns the log level specified in the provided LogOptions. If
// it is not set in the options, it will return the default level.
func (o LogOptions) GetLogLevel() (level logrus.Level) {
	levelOpt, ok := o[LevelOpt]
	if !ok {
		return DefaultLogLevel
	}

	var err error
	if level, err = logrus.ParseLevel(levelOpt); err != nil {
		logrus.WithError(err).Warning("Ignoring user-configured log level")
		return DefaultLogLevel
	}

	return
}

// GetLogFormat returns the log format specified in the provided LogOptions. If
// it is not set in the options or is invalid, it will return the default format.
func (o LogOptions) GetLogFormat() LogFormat {
	formatOpt, ok := o[FormatOpt]
	if !ok {
		return DefaultLogFormat
	}

	formatOpt = strings.ToLower(formatOpt)
	re := regexp.MustCompile(`^(text|json)$`)
	if !re.MatchString(formatOpt) {
		logrus.WithError(
			fmt.Errorf("incorrect log format configured '%s', expected 'text' or 'json'", formatOpt),
		).Warning("Ignoring user-configured log format")
		return DefaultLogFormat
	}

	return LogFormat(formatOpt)
}

// SetLogLevel updates the DefaultLogger with a new logrus.Level
func SetLogLevel(logLevel logrus.Level) {
	DefaultLogger.SetLevel(logLevel)
}

// SetDefaultLogLevel updates the DefaultLogger with the DefaultLogLevel
func SetDefaultLogLevel() {
	DefaultLogger.SetLevel(DefaultLogLevel)
}

// SetLogLevelToDebug updates the DefaultLogger with the logrus.DebugLevel
func SetLogLevelToDebug() {
	DefaultLogger.SetLevel(logrus.DebugLevel)
}

// SetLogFormat updates the DefaultLogger with a new LogFormat
func SetLogFormat(logFormat LogFormat) {
	DefaultLogger.SetFormatter(GetFormatter(logFormat))
}

// SetDefaultLogFormat updates the DefaultLogger with the DefaultLogFormat
func SetDefaultLogFormat() {
	DefaultLogger.SetFormatter(GetFormatter(DefaultLogFormat))
}

// AddHooks adds additional logrus hook to default logger
func AddHooks(hooks ...logrus.Hook) {
	for _, hook := range hooks {
		DefaultLogger.AddHook(hook)
	}
}

// SetupLogging sets up each logging service provided in loggers and configures
// each logger with the provided logOpts.
func SetupLogging(loggers []string, logOpts LogOptions, tag string, debug bool) error {
	// Bridge klog to logrus. Note that this will open multiple pipes and fork
	// background goroutines that are not cleaned up.
	initializeKLog()

	// Updating the default log format
	SetLogFormat(logOpts.GetLogFormat())

	// Set default logger to output to stdout if no loggers are provided.
	if len(loggers) == 0 {
		// TODO: switch to a per-logger version when we upgrade to logrus >1.0.3
		logrus.SetOutput(os.Stdout)
	}

	// Updating the default log level, overriding the log options if the debug arg is being set
	if debug {
		SetLogLevelToDebug()
	} else {
		SetLogLevel(logOpts.GetLogLevel())
	}

	// always suppress the default logger so libraries don't print things
	logrus.SetLevel(logrus.PanicLevel)

	// Iterate through all provided loggers and configure them according
	// to user-provided settings.
	for _, logger := range loggers {
		switch logger {
		case Syslog:
			if err := setupSyslog(logOpts, tag, debug); err != nil {
				return fmt.Errorf("failed to set up syslog: %w", err)
			}
		default:
			return fmt.Errorf("provided log driver %q is not a supported log driver", logger)
		}
	}

	return nil
}

// GetFormatter returns a configured logrus.Formatter with some specific values
// we want to have
func GetFormatter(format LogFormat) logrus.Formatter {
	switch format {
	case LogFormatText:
		return &logrus.TextFormatter{
			DisableTimestamp: true,
			DisableColors:    true,
		}
	case LogFormatJSON:
		return &logrus.JSONFormatter{
			DisableTimestamp: true,
		}
	}

	return nil
}

// validateOpts iterates through all of the keys and values in logOpts, and errors out if
// the key in logOpts is not a key in supportedOpts, or the value of corresponding key is
// not listed in the value of validKVs.
func (o LogOptions) validateOpts(logDriver string, supportedOpts map[string]bool, validKVs map[string][]string) error {
	for k, v := range o {
		if !supportedOpts[k] {
			return fmt.Errorf("provided configuration key %q is not supported as a logging option for log driver %s", k, logDriver)
		}
		if validValues, ok := validKVs[k]; ok {
			valid := false
			for _, vv := range validValues {
				if v == vv {
					valid = true
					break
				}
			}
			if !valid {
				return fmt.Errorf("provided configuration value %q is not a valid value for %q in log driver %s, valid values: %v", v, k, logDriver, validValues)
			}

		}
	}
	return nil
}

// getLogDriverConfig returns a map containing the key-value pairs that start
// with string logDriver from map logOpts.
func getLogDriverConfig(logDriver string, logOpts LogOptions) LogOptions {
	keysToValidate := make(LogOptions)
	for k, v := range logOpts {
		ok, err := regexp.MatchString(logDriver+".*", k)
		if err != nil {
			DefaultLogger.Fatal(err)
		}
		if ok {
			keysToValidate[k] = v
		}
	}
	return keysToValidate
}

// MultiLine breaks a multi line text into individual log entries and calls the
// logging function to log each entry
func MultiLine(logFn func(args ...interface{}), output string) {
	scanner := bufio.NewScanner(bytes.NewReader([]byte(output)))
	for scanner.Scan() {
		logFn(scanner.Text())
	}
}

// CanLogAt returns whether a log message at the given level would be
// logged by the given logger.
func CanLogAt(logger *logrus.Logger, level logrus.Level) bool {
	return GetLevel(logger) >= level
}

// GetLevel returns the log level of the given logger.
func GetLevel(logger *logrus.Logger) logrus.Level {
	return logrus.Level(atomic.LoadUint32((*uint32)(&logger.Level)))
}
<|endoftext|>


<commit_before>package models

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

// Typed errors
var (
	ErrInvalidRoleType     = errors.New("Invalid role type")
	ErrLastOrgAdmin        = errors.New("Cannot remove last organization admin")
	ErrOrgUserNotFound     = errors.New("Cannot find the organization user")
	ErrOrgUserAlreadyAdded = errors.New("User is already added to organization")
)

type RoleType string

const (
	ROLE_VIEWER RoleType = "Viewer"
	ROLE_EDITOR RoleType = "Editor"
	ROLE_ADMIN  RoleType = "Admin"
)

func (r RoleType) IsValid() bool {
	return r == ROLE_VIEWER || r == ROLE_ADMIN || r == ROLE_EDITOR
}

func (r RoleType) Includes(other RoleType) bool {
	if r == ROLE_ADMIN {
		return true
	}

	if r == ROLE_EDITOR {
		return other != ROLE_ADMIN
	}

	if r == ROLE_VIEWER {
		return other == ROLE_VIEWER
	}

	return false
}

func (r *RoleType) UnmarshalJSON(data []byte) error {
	var str string
	err := json.Unmarshal(data, &str)
	if err != nil {
		return err
	}

	*r = RoleType(str)

	if !(*r).IsValid() {
		if (*r) != "" {
			return fmt.Errorf("JSON validation error: invalid role value: %s", *r)
		}

		*r = ROLE_VIEWER
	}

	return nil
}

type OrgUser struct {
	Id      int64
	OrgId   int64
	UserId  int64
	Role    RoleType
	Created time.Time
	Updated time.Time
}

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

type RemoveOrgUserCommand struct {
	UserId                   int64
	OrgId                    int64
	ShouldDeleteOrphanedUser bool
	UserWasDeleted           bool
}

type AddOrgUserCommand struct {
	LoginOrEmail string   `json:"loginOrEmail" binding:"Required"`
	Role         RoleType `json:"role" binding:"Required"`

	OrgId  int64 `json:"-"`
	UserId int64 `json:"-"`
}

type UpdateOrgUserCommand struct {
	Role RoleType `json:"role" binding:"Required"`

	OrgId  int64 `json:"-"`
	UserId int64 `json:"-"`
}

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

type GetOrgUsersQuery struct {
	OrgId int64
	Query string
	Limit int

	Result []*OrgUserDTO
}

// ----------------------
// Projections and DTOs

type OrgUserDTO struct {
	OrgId         int64     `json:"orgId"`
	UserId        int64     `json:"userId"`
	Email         string    `json:"email"`
	AvatarUrl     string    `json:"avatarUrl"`
	Login         string    `json:"login"`
	Role          string    `json:"role"`
	LastSeenAt    time.Time `json:"lastSeenAt"`
	LastSeenAtAge string    `json:"lastSeenAtAge"`
}
<commit_msg>Fixed gofmt issue in PR #16093<commit_after>package models

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

// Typed errors
var (
	ErrInvalidRoleType     = errors.New("Invalid role type")
	ErrLastOrgAdmin        = errors.New("Cannot remove last organization admin")
	ErrOrgUserNotFound     = errors.New("Cannot find the organization user")
	ErrOrgUserAlreadyAdded = errors.New("User is already added to organization")
)

type RoleType string

const (
	ROLE_VIEWER RoleType = "Viewer"
	ROLE_EDITOR RoleType = "Editor"
	ROLE_ADMIN  RoleType = "Admin"
)

func (r RoleType) IsValid() bool {
	return r == ROLE_VIEWER || r == ROLE_ADMIN || r == ROLE_EDITOR
}

func (r RoleType) Includes(other RoleType) bool {
	if r == ROLE_ADMIN {
		return true
	}

	if r == ROLE_EDITOR {
		return other != ROLE_ADMIN
	}

	if r == ROLE_VIEWER {
		return other == ROLE_VIEWER
	}

	return false
}

func (r *RoleType) UnmarshalJSON(data []byte) error {
	var str string
	err := json.Unmarshal(data, &str)
	if err != nil {
		return err
	}

	*r = RoleType(str)

	if !(*r).IsValid() {
		if (*r) != "" {
			return fmt.Errorf("JSON validation error: invalid role value: %s", *r)
		}

		*r = ROLE_VIEWER
	}

	return nil
}

type OrgUser struct {
	Id      int64
	OrgId   int64
	UserId  int64
	Role    RoleType
	Created time.Time
	Updated time.Time
}

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

type RemoveOrgUserCommand struct {
	UserId                   int64
	OrgId                    int64
	ShouldDeleteOrphanedUser bool
	UserWasDeleted           bool
}

type AddOrgUserCommand struct {
	LoginOrEmail string   `json:"loginOrEmail" binding:"Required"`
	Role         RoleType `json:"role" binding:"Required"`

	OrgId  int64 `json:"-"`
	UserId int64 `json:"-"`
}

type UpdateOrgUserCommand struct {
	Role RoleType `json:"role" binding:"Required"`

	OrgId  int64 `json:"-"`
	UserId int64 `json:"-"`
}

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

type GetOrgUsersQuery struct {
	OrgId int64
	Query string
	Limit int

	Result []*OrgUserDTO
}

// ----------------------
// Projections and DTOs

type OrgUserDTO struct {
	OrgId         int64     `json:"orgId"`
	UserId        int64     `json:"userId"`
	Email         string    `json:"email"`
	AvatarUrl     string    `json:"avatarUrl"`
	Login         string    `json:"login"`
	Role          string    `json:"role"`
	LastSeenAt    time.Time `json:"lastSeenAt"`
	LastSeenAtAge string    `json:"lastSeenAtAge"`
}
<|endoftext|>


<commit_before>package plugin

import (
	"fmt"
	"github.com/Aptomi/aptomi/pkg/lang"
	"sync"
)

const (
	clusterCodeSeparator = "#"
)

type defaultRegistry struct {
	mu sync.Mutex

	clusterTypes       map[string]ClusterPluginConstructor
	codeTypes          map[string]CodePluginConstructor
	postProcessPlugins []PostProcessPlugin

	// Cached plugins instances
	clusterPlugins map[string]ClusterPlugin
	codePlugins    map[string]CodePlugin
}

// NewRegistry creates a registry of aptomi engine plugins
func NewRegistry(clusterTypes map[string]ClusterPluginConstructor, codeTypes map[string]CodePluginConstructor, postProcessPlugins []PostProcessPlugin) Registry {
	return &defaultRegistry{
		clusterTypes:       clusterTypes,
		codeTypes:          codeTypes,
		postProcessPlugins: postProcessPlugins,
		clusterPlugins:     make(map[string]ClusterPlugin),
		codePlugins:        make(map[string]CodePlugin),
	}
}

func (registry *defaultRegistry) ForCluster(cluster *lang.Cluster) (ClusterPlugin, error) {
	constructor, exist := registry.clusterTypes[cluster.Type]
	if !exist {
		return nil, fmt.Errorf("no plugin found for cluster type: %s", cluster.Type)
	}

	registry.mu.Lock()
	defer registry.mu.Unlock()

	clusterPlugin, exist := registry.clusterPlugins[cluster.Name]
	if !exist {
		clusterPlugin = constructor(cluster)
		registry.clusterPlugins[cluster.Name] = clusterPlugin
	}

	return clusterPlugin, nil
}

func (registry *defaultRegistry) ForCodeType(cluster *lang.Cluster, codeType string) (CodePlugin, error) {
	clusterPlugin, err := registry.ForCluster(cluster)
	if err != nil {
		return nil, err
	}

	constructor, exist := registry.codeTypes[codeType]
	if !exist {
		return nil, fmt.Errorf("no plugin found for code type: %s", codeType)
	}

	key := cluster.Name + clusterCodeSeparator + codeType

	registry.mu.Lock()
	defer registry.mu.Unlock()

	codePlugin, exist := registry.codePlugins[key]
	if !exist {
		codePlugin = constructor(clusterPlugin)
		registry.codePlugins[key] = codePlugin
	}

	return codePlugin, nil
}

func (registry *defaultRegistry) PostProcess() []PostProcessPlugin {
	return registry.postProcessPlugins
}
<commit_msg>Update plugin registry to work with new plugin constructors<commit_after>package plugin

import (
	"fmt"
	"github.com/Aptomi/aptomi/pkg/config"
	"github.com/Aptomi/aptomi/pkg/lang"
	"sync"
)

const (
	clusterCodeSeparator = "#"
)

type defaultRegistry struct {
	mu sync.Mutex

	config             config.Plugins
	clusterTypes       map[string]ClusterPluginConstructor
	codeTypes          map[string]CodePluginConstructor
	postProcessPlugins []PostProcessPlugin

	// Cached plugins instances
	clusterPlugins map[string]ClusterPlugin
	codePlugins    map[string]CodePlugin
}

// NewRegistry creates a registry of aptomi engine plugins
func NewRegistry(config config.Plugins, clusterTypes map[string]ClusterPluginConstructor, codeTypes map[string]CodePluginConstructor, postProcessPlugins []PostProcessPlugin) Registry {
	return &defaultRegistry{
		config:             config,
		clusterTypes:       clusterTypes,
		codeTypes:          codeTypes,
		postProcessPlugins: postProcessPlugins,
		clusterPlugins:     make(map[string]ClusterPlugin),
		codePlugins:        make(map[string]CodePlugin),
	}
}

func (registry *defaultRegistry) ForCluster(cluster *lang.Cluster) (ClusterPlugin, error) {
	constructor, exist := registry.clusterTypes[cluster.Type]
	if !exist {
		return nil, fmt.Errorf("no plugin found for cluster type: %s", cluster.Type)
	}

	registry.mu.Lock()
	defer registry.mu.Unlock()

	clusterPlugin, exist := registry.clusterPlugins[cluster.Name]
	if !exist {
		var err error
		clusterPlugin, err = constructor(cluster, registry.config)
		if err != nil {
			return nil, err
		}
		registry.clusterPlugins[cluster.Name] = clusterPlugin
	}

	return clusterPlugin, nil
}

func (registry *defaultRegistry) ForCodeType(cluster *lang.Cluster, codeType string) (CodePlugin, error) {
	clusterPlugin, err := registry.ForCluster(cluster)
	if err != nil {
		return nil, err
	}

	constructor, exist := registry.codeTypes[codeType]
	if !exist {
		return nil, fmt.Errorf("no plugin found for code type: %s", codeType)
	}

	key := cluster.Name + clusterCodeSeparator + codeType

	registry.mu.Lock()
	defer registry.mu.Unlock()

	codePlugin, exist := registry.codePlugins[key]
	if !exist {
		codePlugin, err = constructor(clusterPlugin, registry.config)
		if err != nil {
			return nil, err
		}
		registry.codePlugins[key] = codePlugin
	}

	return codePlugin, nil
}

func (registry *defaultRegistry) PostProcess() []PostProcessPlugin {
	return registry.postProcessPlugins
}
<|endoftext|>


<commit_before>package project

var (
	description        = "The aws-operator manages Kubernetes clusters running on AWS."
	gitSHA             = "n/a"
	name        string = "aws-operator"
	source      string = "https://github.com/giantswarm/aws-operator"
	version            = "8.6.2-hama"
)

func Description() string {
	return description
}

func GitSHA() string {
	return gitSHA
}

func Name() string {
	return name
}

func Source() string {
	return source
}

func Version() string {
	return version
}
<commit_msg>set dev version 8.6.2-dev (#2488)<commit_after>package project

var (
	description        = "The aws-operator manages Kubernetes clusters running on AWS."
	gitSHA             = "n/a"
	name        string = "aws-operator"
	source      string = "https://github.com/giantswarm/aws-operator"
	version            = "8.6.2-dev"
)

func Description() string {
	return description
}

func GitSHA() string {
	return gitSHA
}

func Name() string {
	return name
}

func Source() string {
	return source
}

func Version() string {
	return version
}
<|endoftext|>


<commit_before>package project

var (
	description string = "The azure-operator manages Kubernetes clusters on Azure."
	gitSHA             = "n/a"
	name        string = "azure-operator"
	source      string = "https://github.com/giantswarm/azure-operator"
	version            = "3.0.2-dev"
)

func Description() string {
	return description
}

func GitSHA() string {
	return gitSHA
}

func Name() string {
	return name
}

func Source() string {
	return source
}

func Version() string {
	return version
}
<commit_msg>release 3.0.2 (#752)<commit_after>package project

var (
	description string = "The azure-operator manages Kubernetes clusters on Azure."
	gitSHA             = "n/a"
	name        string = "azure-operator"
	source      string = "https://github.com/giantswarm/azure-operator"
	version            = "3.0.2"
)

func Description() string {
	return description
}

func GitSHA() string {
	return gitSHA
}

func Name() string {
	return name
}

func Source() string {
	return source
}

func Version() string {
	return version
}
<|endoftext|>


<commit_before>// Copyright 2018 The gVisor 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 fs

import (
	"bytes"
	"fmt"
	"sync"
	"sync/atomic"

	"gvisor.googlesource.com/gvisor/pkg/refs"
	"gvisor.googlesource.com/gvisor/pkg/sentry/context"
)

// DirentOperations provide file systems greater control over how long a Dirent stays pinned
// in core. Implementations must not take Dirent.mu.
type DirentOperations interface {
	// Revalidate is called during lookup each time we encounter a Dirent
	// in the cache. Implementations may update stale properties of the
	// child Inode. If Revalidate returns true, then the entire Inode will
	// be reloaded.
	//
	// Revalidate will never be called on a Inode that is mounted.
	Revalidate(ctx context.Context, name string, parent, child *Inode) bool

	// Keep returns true if the Dirent should be kept in memory for as long
	// as possible beyond any active references.
	Keep(dirent *Dirent) bool
}

// MountSourceOperations contains filesystem specific operations.
type MountSourceOperations interface {
	// TODO(b/67778729): Add:
	// BlockSize() int64
	// FS() Filesystem

	// DirentOperations provide optional extra management of Dirents.
	DirentOperations

	// Destroy destroys the MountSource.
	Destroy()

	// Below are MountSourceOperations that do not conform to Linux.

	// ResetInodeMappings clears all mappings of Inodes before SaveInodeMapping
	// is called.
	ResetInodeMappings()

	// SaveInodeMappings is called during saving to store, for each reachable
	// Inode in the mounted filesystem, a mapping of Inode.StableAttr.InodeID
	// to the Inode's path relative to its mount point. If an Inode is
	// reachable at more than one path due to hard links, it is unspecified
	// which path is mapped. Filesystems that do not use this information to
	// restore inodes can make SaveInodeMappings a no-op.
	SaveInodeMapping(inode *Inode, path string)
}

// InodeMappings defines a fmt.Stringer MountSource Inode mappings.
type InodeMappings map[uint64]string

// String implements fmt.Stringer.String.
func (i InodeMappings) String() string {
	var mappingsBuf bytes.Buffer
	mappingsBuf.WriteString("\n")
	for ino, name := range i {
		mappingsBuf.WriteString(fmt.Sprintf("\t%q\t\tinode number %d\n", name, ino))
	}
	return mappingsBuf.String()
}

// MountSource represents a source of file objects.
//
// MountSource corresponds to struct super_block in Linux.
//
// A mount source may represent a physical device (or a partition of a physical
// device) or a virtual source of files such as procfs for a specific PID
// namespace. There should be only one mount source per logical device. E.g.
// there should be only procfs mount source for a given PID namespace.
//
// A mount source represents files as inodes. Every inode belongs to exactly
// one mount source. Each file object may only be represented using one inode
// object in a sentry instance.
//
// This is an amalgamation of structs super_block, vfsmount, and mount, while
// MountSourceOperations is akin to struct super_operations.
//
// Hence, mount source also contains common mounted file system state, such as
// mount flags, the root Dirent, and children mounts. For now, this
// amalgamation implies that a mount source cannot be shared by multiple mounts
// (e.g. cannot be mounted at different locations).
//
// TODO(b/63601033): Move mount-specific information out of MountSource.
//
// +stateify savable
type MountSource struct {
	refs.AtomicRefCount

	// MountSourceOperations defines filesystem specific behavior.
	MountSourceOperations

	// FilesystemType is the type of the filesystem backing this mount.
	FilesystemType string

	// Flags are the flags that this filesystem was mounted with.
	Flags MountSourceFlags

	// fscache keeps Dirents pinned beyond application references to them.
	// It must be flushed before kernel.SaveTo.
	fscache *DirentCache

	// direntRefs is the sum of references on all Dirents in this MountSource.
	//
	// direntRefs is increased when a Dirent in MountSource is IncRef'd, and
	// decreased when a Dirent in MountSource is DecRef'd.
	//
	// To cleanly unmount a MountSource, one must check that no direntRefs are
	// held anymore. To check, one must hold root.parent.dirMu of the
	// MountSource's root Dirent before reading direntRefs to prevent further
	// walks to Dirents in this MountSource.
	//
	// direntRefs must be atomically changed.
	direntRefs uint64

	// mu protects the fields below, which are set by the MountNamespace
	// during MountSource/Unmount.
	mu sync.Mutex `state:"nosave"`

	// id is a unique id for this mount.
	id uint64

	// root is the root Dirent of this mount.
	root *Dirent

	// parent is the parent MountSource, or nil if this MountSource is the root.
	parent *MountSource

	// children are the child MountSources of this MountSource.
	children map[*MountSource]struct{}
}

// DefaultDirentCacheSize is the number of Dirents that the VFS can hold an
// extra reference on.
const DefaultDirentCacheSize uint64 = 1000

// NewMountSource returns a new MountSource. Filesystem may be nil if there is no
// filesystem backing the mount.
func NewMountSource(mops MountSourceOperations, filesystem Filesystem, flags MountSourceFlags) *MountSource {
	fsType := "none"
	if filesystem != nil {
		fsType = filesystem.Name()
	}
	return &MountSource{
		MountSourceOperations: mops,
		Flags:                 flags,
		FilesystemType:        fsType,
		fscache:               NewDirentCache(DefaultDirentCacheSize),
		children:              make(map[*MountSource]struct{}),
	}
}

// Parent returns the parent mount, or nil if this mount is the root.
func (msrc *MountSource) Parent() *MountSource {
	msrc.mu.Lock()
	defer msrc.mu.Unlock()
	return msrc.parent
}

// ID returns the ID of this mount.
func (msrc *MountSource) ID() uint64 {
	msrc.mu.Lock()
	defer msrc.mu.Unlock()
	return msrc.id
}

// Children returns the (immediate) children of this MountSource.
func (msrc *MountSource) Children() []*MountSource {
	msrc.mu.Lock()
	defer msrc.mu.Unlock()

	ms := make([]*MountSource, 0, len(msrc.children))
	for c := range msrc.children {
		ms = append(ms, c)
	}
	return ms
}

// Submounts returns all mounts that are descendants of this mount.
func (msrc *MountSource) Submounts() []*MountSource {
	var ms []*MountSource
	for _, c := range msrc.Children() {
		ms = append(ms, c)
		ms = append(ms, c.Submounts()...)
	}
	return ms
}

// Root returns the root dirent of this mount. Callers must call DecRef on the
// returned dirent.
func (msrc *MountSource) Root() *Dirent {
	msrc.mu.Lock()
	defer msrc.mu.Unlock()
	msrc.root.IncRef()
	return msrc.root
}

// DirentRefs returns the current mount direntRefs.
func (msrc *MountSource) DirentRefs() uint64 {
	return atomic.LoadUint64(&msrc.direntRefs)
}

// IncDirentRefs increases direntRefs.
func (msrc *MountSource) IncDirentRefs() {
	atomic.AddUint64(&msrc.direntRefs, 1)
}

// DecDirentRefs decrements direntRefs.
func (msrc *MountSource) DecDirentRefs() {
	if atomic.AddUint64(&msrc.direntRefs, ^uint64(0)) == ^uint64(0) {
		panic("Decremented zero mount reference direntRefs")
	}
}

func (msrc *MountSource) destroy() {
	if c := msrc.DirentRefs(); c != 0 {
		panic(fmt.Sprintf("MountSource with non-zero direntRefs is being destroyed: %d", c))
	}
	msrc.MountSourceOperations.Destroy()
}

// DecRef drops a reference on the MountSource.
func (msrc *MountSource) DecRef() {
	msrc.DecRefWithDestructor(msrc.destroy)
}

// FlushDirentRefs drops all references held by the MountSource on Dirents.
func (msrc *MountSource) FlushDirentRefs() {
	msrc.fscache.Invalidate()
}

// SetDirentCacheMaxSize sets the max size to the dirent cache associated with
// this mount source.
func (msrc *MountSource) SetDirentCacheMaxSize(max uint64) {
	msrc.fscache.setMaxSize(max)
}

// SetDirentCacheLimiter sets the limiter objcet to the dirent cache associated
// with this mount source.
func (msrc *MountSource) SetDirentCacheLimiter(l *DirentCacheLimiter) {
	msrc.fscache.limit = l
}

// NewCachingMountSource returns a generic mount that will cache dirents
// aggressively.
func NewCachingMountSource(filesystem Filesystem, flags MountSourceFlags) *MountSource {
	return NewMountSource(&SimpleMountSourceOperations{
		keep:       true,
		revalidate: false,
	}, filesystem, flags)
}

// NewNonCachingMountSource returns a generic mount that will never cache dirents.
func NewNonCachingMountSource(filesystem Filesystem, flags MountSourceFlags) *MountSource {
	return NewMountSource(&SimpleMountSourceOperations{
		keep:       false,
		revalidate: false,
	}, filesystem, flags)
}

// NewRevalidatingMountSource returns a generic mount that will cache dirents,
// but will revalidate them on each lookup.
func NewRevalidatingMountSource(filesystem Filesystem, flags MountSourceFlags) *MountSource {
	return NewMountSource(&SimpleMountSourceOperations{
		keep:       true,
		revalidate: true,
	}, filesystem, flags)
}

// NewPseudoMountSource returns a "pseudo" mount source that is not backed by
// an actual filesystem. It is always non-caching.
func NewPseudoMountSource() *MountSource {
	return NewMountSource(&SimpleMountSourceOperations{
		keep:       false,
		revalidate: false,
	}, nil, MountSourceFlags{})
}

// SimpleMountSourceOperations implements MountSourceOperations.
//
// +stateify savable
type SimpleMountSourceOperations struct {
	keep       bool
	revalidate bool
}

// Revalidate implements MountSourceOperations.Revalidate.
func (smo *SimpleMountSourceOperations) Revalidate(context.Context, string, *Inode, *Inode) bool {
	return smo.revalidate
}

// Keep implements MountSourceOperations.Keep.
func (smo *SimpleMountSourceOperations) Keep(*Dirent) bool {
	return smo.keep
}

// ResetInodeMappings implements MountSourceOperations.ResetInodeMappings.
func (*SimpleMountSourceOperations) ResetInodeMappings() {}

// SaveInodeMapping implements MountSourceOperations.SaveInodeMapping.
func (*SimpleMountSourceOperations) SaveInodeMapping(*Inode, string) {}

// Destroy implements MountSourceOperations.Destroy.
func (*SimpleMountSourceOperations) Destroy() {}

// Info defines attributes of a filesystem.
type Info struct {
	// Type is the filesystem type magic value.
	Type uint64

	// TotalBlocks is the total data blocks in the filesystem.
	TotalBlocks uint64

	// FreeBlocks is the number of free blocks available.
	FreeBlocks uint64

	// TotalFiles is the total file nodes in the filesystem.
	TotalFiles uint64

	// FreeFiles is the number of free file nodes.
	FreeFiles uint64
}
<commit_msg>Remove obsolete TODO.<commit_after>// Copyright 2018 The gVisor 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 fs

import (
	"bytes"
	"fmt"
	"sync"
	"sync/atomic"

	"gvisor.googlesource.com/gvisor/pkg/refs"
	"gvisor.googlesource.com/gvisor/pkg/sentry/context"
)

// DirentOperations provide file systems greater control over how long a Dirent stays pinned
// in core. Implementations must not take Dirent.mu.
type DirentOperations interface {
	// Revalidate is called during lookup each time we encounter a Dirent
	// in the cache. Implementations may update stale properties of the
	// child Inode. If Revalidate returns true, then the entire Inode will
	// be reloaded.
	//
	// Revalidate will never be called on a Inode that is mounted.
	Revalidate(ctx context.Context, name string, parent, child *Inode) bool

	// Keep returns true if the Dirent should be kept in memory for as long
	// as possible beyond any active references.
	Keep(dirent *Dirent) bool
}

// MountSourceOperations contains filesystem specific operations.
type MountSourceOperations interface {
	// DirentOperations provide optional extra management of Dirents.
	DirentOperations

	// Destroy destroys the MountSource.
	Destroy()

	// Below are MountSourceOperations that do not conform to Linux.

	// ResetInodeMappings clears all mappings of Inodes before SaveInodeMapping
	// is called.
	ResetInodeMappings()

	// SaveInodeMappings is called during saving to store, for each reachable
	// Inode in the mounted filesystem, a mapping of Inode.StableAttr.InodeID
	// to the Inode's path relative to its mount point. If an Inode is
	// reachable at more than one path due to hard links, it is unspecified
	// which path is mapped. Filesystems that do not use this information to
	// restore inodes can make SaveInodeMappings a no-op.
	SaveInodeMapping(inode *Inode, path string)
}

// InodeMappings defines a fmt.Stringer MountSource Inode mappings.
type InodeMappings map[uint64]string

// String implements fmt.Stringer.String.
func (i InodeMappings) String() string {
	var mappingsBuf bytes.Buffer
	mappingsBuf.WriteString("\n")
	for ino, name := range i {
		mappingsBuf.WriteString(fmt.Sprintf("\t%q\t\tinode number %d\n", name, ino))
	}
	return mappingsBuf.String()
}

// MountSource represents a source of file objects.
//
// MountSource corresponds to struct super_block in Linux.
//
// A mount source may represent a physical device (or a partition of a physical
// device) or a virtual source of files such as procfs for a specific PID
// namespace. There should be only one mount source per logical device. E.g.
// there should be only procfs mount source for a given PID namespace.
//
// A mount source represents files as inodes. Every inode belongs to exactly
// one mount source. Each file object may only be represented using one inode
// object in a sentry instance.
//
// This is an amalgamation of structs super_block, vfsmount, and mount, while
// MountSourceOperations is akin to struct super_operations.
//
// Hence, mount source also contains common mounted file system state, such as
// mount flags, the root Dirent, and children mounts. For now, this
// amalgamation implies that a mount source cannot be shared by multiple mounts
// (e.g. cannot be mounted at different locations).
//
// TODO(b/63601033): Move mount-specific information out of MountSource.
//
// +stateify savable
type MountSource struct {
	refs.AtomicRefCount

	// MountSourceOperations defines filesystem specific behavior.
	MountSourceOperations

	// FilesystemType is the type of the filesystem backing this mount.
	FilesystemType string

	// Flags are the flags that this filesystem was mounted with.
	Flags MountSourceFlags

	// fscache keeps Dirents pinned beyond application references to them.
	// It must be flushed before kernel.SaveTo.
	fscache *DirentCache

	// direntRefs is the sum of references on all Dirents in this MountSource.
	//
	// direntRefs is increased when a Dirent in MountSource is IncRef'd, and
	// decreased when a Dirent in MountSource is DecRef'd.
	//
	// To cleanly unmount a MountSource, one must check that no direntRefs are
	// held anymore. To check, one must hold root.parent.dirMu of the
	// MountSource's root Dirent before reading direntRefs to prevent further
	// walks to Dirents in this MountSource.
	//
	// direntRefs must be atomically changed.
	direntRefs uint64

	// mu protects the fields below, which are set by the MountNamespace
	// during MountSource/Unmount.
	mu sync.Mutex `state:"nosave"`

	// id is a unique id for this mount.
	id uint64

	// root is the root Dirent of this mount.
	root *Dirent

	// parent is the parent MountSource, or nil if this MountSource is the root.
	parent *MountSource

	// children are the child MountSources of this MountSource.
	children map[*MountSource]struct{}
}

// DefaultDirentCacheSize is the number of Dirents that the VFS can hold an
// extra reference on.
const DefaultDirentCacheSize uint64 = 1000

// NewMountSource returns a new MountSource. Filesystem may be nil if there is no
// filesystem backing the mount.
func NewMountSource(mops MountSourceOperations, filesystem Filesystem, flags MountSourceFlags) *MountSource {
	fsType := "none"
	if filesystem != nil {
		fsType = filesystem.Name()
	}
	return &MountSource{
		MountSourceOperations: mops,
		Flags:                 flags,
		FilesystemType:        fsType,
		fscache:               NewDirentCache(DefaultDirentCacheSize),
		children:              make(map[*MountSource]struct{}),
	}
}

// Parent returns the parent mount, or nil if this mount is the root.
func (msrc *MountSource) Parent() *MountSource {
	msrc.mu.Lock()
	defer msrc.mu.Unlock()
	return msrc.parent
}

// ID returns the ID of this mount.
func (msrc *MountSource) ID() uint64 {
	msrc.mu.Lock()
	defer msrc.mu.Unlock()
	return msrc.id
}

// Children returns the (immediate) children of this MountSource.
func (msrc *MountSource) Children() []*MountSource {
	msrc.mu.Lock()
	defer msrc.mu.Unlock()

	ms := make([]*MountSource, 0, len(msrc.children))
	for c := range msrc.children {
		ms = append(ms, c)
	}
	return ms
}

// Submounts returns all mounts that are descendants of this mount.
func (msrc *MountSource) Submounts() []*MountSource {
	var ms []*MountSource
	for _, c := range msrc.Children() {
		ms = append(ms, c)
		ms = append(ms, c.Submounts()...)
	}
	return ms
}

// Root returns the root dirent of this mount. Callers must call DecRef on the
// returned dirent.
func (msrc *MountSource) Root() *Dirent {
	msrc.mu.Lock()
	defer msrc.mu.Unlock()
	msrc.root.IncRef()
	return msrc.root
}

// DirentRefs returns the current mount direntRefs.
func (msrc *MountSource) DirentRefs() uint64 {
	return atomic.LoadUint64(&msrc.direntRefs)
}

// IncDirentRefs increases direntRefs.
func (msrc *MountSource) IncDirentRefs() {
	atomic.AddUint64(&msrc.direntRefs, 1)
}

// DecDirentRefs decrements direntRefs.
func (msrc *MountSource) DecDirentRefs() {
	if atomic.AddUint64(&msrc.direntRefs, ^uint64(0)) == ^uint64(0) {
		panic("Decremented zero mount reference direntRefs")
	}
}

func (msrc *MountSource) destroy() {
	if c := msrc.DirentRefs(); c != 0 {
		panic(fmt.Sprintf("MountSource with non-zero direntRefs is being destroyed: %d", c))
	}
	msrc.MountSourceOperations.Destroy()
}

// DecRef drops a reference on the MountSource.
func (msrc *MountSource) DecRef() {
	msrc.DecRefWithDestructor(msrc.destroy)
}

// FlushDirentRefs drops all references held by the MountSource on Dirents.
func (msrc *MountSource) FlushDirentRefs() {
	msrc.fscache.Invalidate()
}

// SetDirentCacheMaxSize sets the max size to the dirent cache associated with
// this mount source.
func (msrc *MountSource) SetDirentCacheMaxSize(max uint64) {
	msrc.fscache.setMaxSize(max)
}

// SetDirentCacheLimiter sets the limiter objcet to the dirent cache associated
// with this mount source.
func (msrc *MountSource) SetDirentCacheLimiter(l *DirentCacheLimiter) {
	msrc.fscache.limit = l
}

// NewCachingMountSource returns a generic mount that will cache dirents
// aggressively.
func NewCachingMountSource(filesystem Filesystem, flags MountSourceFlags) *MountSource {
	return NewMountSource(&SimpleMountSourceOperations{
		keep:       true,
		revalidate: false,
	}, filesystem, flags)
}

// NewNonCachingMountSource returns a generic mount that will never cache dirents.
func NewNonCachingMountSource(filesystem Filesystem, flags MountSourceFlags) *MountSource {
	return NewMountSource(&SimpleMountSourceOperations{
		keep:       false,
		revalidate: false,
	}, filesystem, flags)
}

// NewRevalidatingMountSource returns a generic mount that will cache dirents,
// but will revalidate them on each lookup.
func NewRevalidatingMountSource(filesystem Filesystem, flags MountSourceFlags) *MountSource {
	return NewMountSource(&SimpleMountSourceOperations{
		keep:       true,
		revalidate: true,
	}, filesystem, flags)
}

// NewPseudoMountSource returns a "pseudo" mount source that is not backed by
// an actual filesystem. It is always non-caching.
func NewPseudoMountSource() *MountSource {
	return NewMountSource(&SimpleMountSourceOperations{
		keep:       false,
		revalidate: false,
	}, nil, MountSourceFlags{})
}

// SimpleMountSourceOperations implements MountSourceOperations.
//
// +stateify savable
type SimpleMountSourceOperations struct {
	keep       bool
	revalidate bool
}

// Revalidate implements MountSourceOperations.Revalidate.
func (smo *SimpleMountSourceOperations) Revalidate(context.Context, string, *Inode, *Inode) bool {
	return smo.revalidate
}

// Keep implements MountSourceOperations.Keep.
func (smo *SimpleMountSourceOperations) Keep(*Dirent) bool {
	return smo.keep
}

// ResetInodeMappings implements MountSourceOperations.ResetInodeMappings.
func (*SimpleMountSourceOperations) ResetInodeMappings() {}

// SaveInodeMapping implements MountSourceOperations.SaveInodeMapping.
func (*SimpleMountSourceOperations) SaveInodeMapping(*Inode, string) {}

// Destroy implements MountSourceOperations.Destroy.
func (*SimpleMountSourceOperations) Destroy() {}

// Info defines attributes of a filesystem.
type Info struct {
	// Type is the filesystem type magic value.
	Type uint64

	// TotalBlocks is the total data blocks in the filesystem.
	TotalBlocks uint64

	// FreeBlocks is the number of free blocks available.
	FreeBlocks uint64

	// TotalFiles is the total file nodes in the filesystem.
	TotalFiles uint64

	// FreeFiles is the number of free file nodes.
	FreeFiles uint64
}
<|endoftext|>


<commit_before>// Package version provides ways to get the version of the
// program.
package version

import (
	"os/exec"
	"strings"
)

// VERSION defines piladb version.
// It must be set when creating a new release,
// otherwise people building the project from
// source will get an inaccurate version.
const VERSION = "0.1.2"

// Version returns piladb version given a v version. If v is empty,
// defaults to CommitHash.
func Version(v string) string {
	if v == "" {
		return CommitHash()
	}

	return v
}

// CommitHash returns the commit hash of the repository.
func CommitHash() string {
	cmd := exec.Command("git", []string{"rev-parse", "HEAD"}...)

	b, err := cmd.Output()
	if err != nil {
		return "undefined"
	}
	return strings.Replace(string(b), "\n", "", -1)
}
<commit_msg>Unset VERSION<commit_after>// Package version provides ways to get the version of the
// program.
package version

import (
	"os/exec"
	"strings"
)

// VERSION defines piladb version.
// It must be set when creating a new release,
// otherwise people building the project from
// source will get an inaccurate version.
const VERSION = ""

// Version returns piladb version given a v version. If v is empty,
// defaults to CommitHash.
func Version(v string) string {
	if v == "" {
		return CommitHash()
	}

	return v
}

// CommitHash returns the commit hash of the repository.
func CommitHash() string {
	cmd := exec.Command("git", []string{"rev-parse", "HEAD"}...)

	b, err := cmd.Output()
	if err != nil {
		return "undefined"
	}
	return strings.Replace(string(b), "\n", "", -1)
}
<|endoftext|>


<commit_before>/*
 * This file is part of the KubeVirt project
 *
 * 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.
 *
 * Copyright 2017, 2018 Red Hat, Inc.
 *
 */

package vnc

import (
	"fmt"
	"io"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"time"

	"github.com/golang/glog"
	"github.com/spf13/cobra"
	"k8s.io/client-go/tools/clientcmd"

	"kubevirt.io/kubevirt/pkg/kubecli"
	"kubevirt.io/kubevirt/pkg/virtctl/templates"
)

const (
	LISTEN_TIMEOUT = 60 * time.Second
	FLAG           = "vnc"

	//#### Tiger VNC ####
	//# https://github.com/TigerVNC/tigervnc/releases
	TIGER_VNC = "/Applications/TigerVNC Viewer 1.8.0.app/Contents/MacOS/TigerVNC Viewer"

	//#### Chicken VNC ####
	//# https://sourceforge.net/projects/chicken/
	CHICKEN_VNC = "/Applications/Chicken.app/Contents/MacOS/Chicken"

	//####  Real VNC ####
	//# https://www.realvnc.com/en/connect/download/viewer/macos/
	REAL_VNC = "/Applications/VNC Viewer.app/Contents/MacOS/vncviewer"

	REMOTE_VIEWER = "remote-viewer"
)

func NewCommand(clientConfig clientcmd.ClientConfig) *cobra.Command {
	cmd := &cobra.Command{
		Use:     "vnc (VMI)",
		Short:   "Open a vnc connection to a virtual machine instance.",
		Example: usage(),
		Args:    cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			c := VNC{clientConfig: clientConfig}
			return c.Run(cmd, args)
		},
	}
	cmd.SetUsageTemplate(templates.UsageTemplate())
	return cmd
}

type VNC struct {
	clientConfig clientcmd.ClientConfig
}

func (o *VNC) Run(cmd *cobra.Command, args []string) error {
	namespace, _, err := o.clientConfig.Namespace()
	if err != nil {
		return err
	}

	vmi := args[0]

	virtCli, err := kubecli.GetKubevirtClientFromClientConfig(o.clientConfig)
	if err != nil {
		return err
	}

	// setup connection with VM
	vnc, err := virtCli.VirtualMachineInstance(namespace).VNC(vmi)
	if err != nil {
		return fmt.Errorf("Can't access VMI %s: %s", vmi, err.Error())
	}

	lnAddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:0")
	if err != nil {
		return fmt.Errorf("Can't resolve the address: %s", err.Error())
	}

	// The local tcp server is used to proxy the podExec websock connection to remote-viewer
	ln, err := net.ListenTCP("tcp", lnAddr)
	if err != nil {
		return fmt.Errorf("Can't listen on unix socket: %s", err.Error())
	}
	// End of pre-flight checks. Everything looks good, we can start
	// the goroutines and let the data flow

	//                                       -> pipeInWriter  -> pipeInReader
	// remote-viewer -> unix sock connection
	//                                       <- pipeOutReader <- pipeOutWriter
	pipeInReader, pipeInWriter := io.Pipe()
	pipeOutReader, pipeOutWriter := io.Pipe()

	k8ResChan := make(chan error)
	listenResChan := make(chan error)
	viewResChan := make(chan error)
	stopChan := make(chan struct{}, 1)
	doneChan := make(chan struct{}, 1)
	writeStop := make(chan error)
	readStop := make(chan error)

	go func() {
		// transfer data from/to the VM
		k8ResChan <- vnc.Stream(kubecli.StreamOptions{
			In:  pipeInReader,
			Out: pipeOutWriter,
		})
	}()

	// wait for remote-viewer to connect to our local proxy server
	go func() {
		start := time.Now()
		glog.Infof("connection timeout: %v", LISTEN_TIMEOUT)
		// exit early if spawning remote-viewer fails
		ln.SetDeadline(time.Now().Add(LISTEN_TIMEOUT))

		fd, err := ln.Accept()
		if err != nil {
			glog.V(2).Infof("Failed to accept unix sock connection. %s", err.Error())
			listenResChan <- err
		}
		defer fd.Close()

		glog.V(2).Infof("remote-viewer connected in %v", time.Now().Sub(start))

		// write to FD <- pipeOutReader
		go func() {
			_, err := io.Copy(fd, pipeOutReader)
			readStop <- err
		}()

		// read from FD -> pipeInWriter
		go func() {
			_, err := io.Copy(pipeInWriter, fd)
			writeStop <- err
		}()

		// don't terminate until remote-viewer is done
		<-doneChan
		listenResChan <- err
	}()

	// execute VNC
	go func() {
		defer close(doneChan)
		port := ln.Addr().(*net.TCPAddr).Port
		args := []string{}

		vncBin := ""
		osType := runtime.GOOS
		switch osType {
		case "darwin":
			if _, err := os.Stat(TIGER_VNC); err == nil {
				vncBin = TIGER_VNC
				args = tigerVncArgs(port)
			} else if !os.IsNotExist(err) {
				viewResChan <- err
				return
			} else if _, err := os.Stat(CHICKEN_VNC); err == nil {
				vncBin = CHICKEN_VNC
				args = chickenVncArgs(port)
			} else if !os.IsNotExist(err) {
				viewResChan <- err
				return
			} else if _, err := os.Stat(REAL_VNC); err == nil {
				vncBin = REAL_VNC
				args = realVncArgs(port)
			} else if !os.IsNotExist(err) {
				viewResChan <- err
				return
			} else if _, err := exec.LookPath(REMOTE_VIEWER); err == nil {
				// fall back to user supplied script/binary in path
				vncBin = REMOTE_VIEWER
				args = remoteViewerArgs(port)
			} else if !os.IsNotExist(err) {
				viewResChan <- err
				return
			}
		case "linux":
			_, err := exec.LookPath(REMOTE_VIEWER)
			if exec.ErrNotFound == err {
				viewResChan <- fmt.Errorf("could not find the remote-viewer binary in $PATH")
				return
			} else if err != nil {
				viewResChan <- err
				return
			}
			vncBin = REMOTE_VIEWER
			args = remoteViewerArgs(port)
		default:
			viewResChan <- fmt.Errorf("virtctl does not support VNC on %v", osType)
			return
		}

		if vncBin == "" {
			glog.Errorf("No supported VNC app found in %s", osType)
			err = fmt.Errorf("No supported VNC app found in %s", osType)
		} else {
			if glog.V(4) {
				glog.Infof("Executing commandline: '%s %v'", vncBin, args)
			}
			cmnd := exec.Command(vncBin, args...)
			output, err := cmnd.CombinedOutput()
			if err != nil {
				glog.Errorf("%s execution failed: %v, output: %v", vncBin, err, string(output))
			} else {
				glog.V(2).Infof("remote-viewer output: %v", string(output))
			}
		}
		viewResChan <- err
	}()

	go func() {
		defer close(stopChan)
		interrupt := make(chan os.Signal, 1)
		signal.Notify(interrupt, os.Interrupt)
		<-interrupt
	}()

	select {
	case <-stopChan:
	case err = <-readStop:
	case err = <-writeStop:
	case err = <-k8ResChan:
	case err = <-viewResChan:
	case err = <-listenResChan:
	}

	if err != nil {
		return fmt.Errorf("Error encountered: %s", err.Error())
	}
	return nil
}

func tigerVncArgs(port int) (args []string) {
	args = append(args, fmt.Sprintf("127.0.0.1:%d", port))
	if glog.V(4) {
		args = append(args, "Log=*:stderr:100")
	}
	return
}

func chickenVncArgs(port int) (args []string) {
	args = append(args, fmt.Sprintf("127.0.0.1:%d", port))
	return
}

func realVncArgs(port int) (args []string) {
	args = append(args, fmt.Sprintf("127.0.0.1:%d", port))
	args = append(args, "-WarnUnencrypted=0")
	args = append(args, "-Shared=0")
	args = append(args, "-ShareFiles=0")
	if glog.V(4) {
		args = append(args, "-log=*:stderr:100")
	}
	return
}

func remoteViewerArgs(port int) (args []string) {
	args = append(args, fmt.Sprintf("vnc://127.0.0.1:%d", port))
	if glog.V(4) {
		args = append(args, "--debug")
	}
	return
}

func usage() string {
	usage := "  # Connect to 'testvmi' via remote-viewer:\n"
	usage += "  virtctl vnc testvmi"
	return usage
}
<commit_msg>virtctl: Enable compatible with multiple TigerVNC versions<commit_after>/*
 * This file is part of the KubeVirt project
 *
 * 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.
 *
 * Copyright 2017, 2018 Red Hat, Inc.
 *
 */

package vnc

import (
	"fmt"
	"io"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"runtime"
	"time"

	"github.com/golang/glog"
	"github.com/spf13/cobra"
	"k8s.io/client-go/tools/clientcmd"

	"kubevirt.io/kubevirt/pkg/kubecli"
	"kubevirt.io/kubevirt/pkg/virtctl/templates"
)

const (
	LISTEN_TIMEOUT = 60 * time.Second
	FLAG           = "vnc"

	//#### Tiger VNC ####
	//# https://github.com/TigerVNC/tigervnc/releases
	// Compatible with multiple Tiger VNC versions
	TIGER_VNC_PATTERN = `/Applications/TigerVNC Viewer*.app/Contents/MacOS/TigerVNC Viewer`

	//#### Chicken VNC ####
	//# https://sourceforge.net/projects/chicken/
	CHICKEN_VNC = "/Applications/Chicken.app/Contents/MacOS/Chicken"

	//####  Real VNC ####
	//# https://www.realvnc.com/en/connect/download/viewer/macos/
	REAL_VNC = "/Applications/VNC Viewer.app/Contents/MacOS/vncviewer"

	REMOTE_VIEWER = "remote-viewer"
)

func NewCommand(clientConfig clientcmd.ClientConfig) *cobra.Command {
	cmd := &cobra.Command{
		Use:     "vnc (VMI)",
		Short:   "Open a vnc connection to a virtual machine instance.",
		Example: usage(),
		Args:    cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			c := VNC{clientConfig: clientConfig}
			return c.Run(cmd, args)
		},
	}
	cmd.SetUsageTemplate(templates.UsageTemplate())
	return cmd
}

type VNC struct {
	clientConfig clientcmd.ClientConfig
}

func (o *VNC) Run(cmd *cobra.Command, args []string) error {
	namespace, _, err := o.clientConfig.Namespace()
	if err != nil {
		return err
	}

	vmi := args[0]

	virtCli, err := kubecli.GetKubevirtClientFromClientConfig(o.clientConfig)
	if err != nil {
		return err
	}

	// setup connection with VM
	vnc, err := virtCli.VirtualMachineInstance(namespace).VNC(vmi)
	if err != nil {
		return fmt.Errorf("Can't access VMI %s: %s", vmi, err.Error())
	}

	lnAddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:0")
	if err != nil {
		return fmt.Errorf("Can't resolve the address: %s", err.Error())
	}

	// The local tcp server is used to proxy the podExec websock connection to remote-viewer
	ln, err := net.ListenTCP("tcp", lnAddr)
	if err != nil {
		return fmt.Errorf("Can't listen on unix socket: %s", err.Error())
	}
	// End of pre-flight checks. Everything looks good, we can start
	// the goroutines and let the data flow

	//                                       -> pipeInWriter  -> pipeInReader
	// remote-viewer -> unix sock connection
	//                                       <- pipeOutReader <- pipeOutWriter
	pipeInReader, pipeInWriter := io.Pipe()
	pipeOutReader, pipeOutWriter := io.Pipe()

	k8ResChan := make(chan error)
	listenResChan := make(chan error)
	viewResChan := make(chan error)
	stopChan := make(chan struct{}, 1)
	doneChan := make(chan struct{}, 1)
	writeStop := make(chan error)
	readStop := make(chan error)

	go func() {
		// transfer data from/to the VM
		k8ResChan <- vnc.Stream(kubecli.StreamOptions{
			In:  pipeInReader,
			Out: pipeOutWriter,
		})
	}()

	// wait for remote-viewer to connect to our local proxy server
	go func() {
		start := time.Now()
		glog.Infof("connection timeout: %v", LISTEN_TIMEOUT)
		// exit early if spawning remote-viewer fails
		ln.SetDeadline(time.Now().Add(LISTEN_TIMEOUT))

		fd, err := ln.Accept()
		if err != nil {
			glog.V(2).Infof("Failed to accept unix sock connection. %s", err.Error())
			listenResChan <- err
		}
		defer fd.Close()

		glog.V(2).Infof("remote-viewer connected in %v", time.Now().Sub(start))

		// write to FD <- pipeOutReader
		go func() {
			_, err := io.Copy(fd, pipeOutReader)
			readStop <- err
		}()

		// read from FD -> pipeInWriter
		go func() {
			_, err := io.Copy(pipeInWriter, fd)
			writeStop <- err
		}()

		// don't terminate until remote-viewer is done
		<-doneChan
		listenResChan <- err
	}()

	// execute VNC
	go func() {
		defer close(doneChan)
		port := ln.Addr().(*net.TCPAddr).Port
		args := []string{}

		vncBin := ""
		osType := runtime.GOOS
		switch osType {
		case "darwin":
			if matches, err := filepath.Glob(TIGER_VNC_PATTERN); err == nil && len(matches) > 0 {
				// Always use the latest version
				vncBin = matches[len(matches)-1]
				args = tigerVncArgs(port)
			} else if err == filepath.ErrBadPattern {
				viewResChan <- err
				return
			} else if _, err := os.Stat(CHICKEN_VNC); err == nil {
				vncBin = CHICKEN_VNC
				args = chickenVncArgs(port)
			} else if !os.IsNotExist(err) {
				viewResChan <- err
				return
			} else if _, err := os.Stat(REAL_VNC); err == nil {
				vncBin = REAL_VNC
				args = realVncArgs(port)
			} else if !os.IsNotExist(err) {
				viewResChan <- err
				return
			} else if _, err := exec.LookPath(REMOTE_VIEWER); err == nil {
				// fall back to user supplied script/binary in path
				vncBin = REMOTE_VIEWER
				args = remoteViewerArgs(port)
			} else if !os.IsNotExist(err) {
				viewResChan <- err
				return
			}
		case "linux":
			_, err := exec.LookPath(REMOTE_VIEWER)
			if exec.ErrNotFound == err {
				viewResChan <- fmt.Errorf("could not find the remote-viewer binary in $PATH")
				return
			} else if err != nil {
				viewResChan <- err
				return
			}
			vncBin = REMOTE_VIEWER
			args = remoteViewerArgs(port)
		default:
			viewResChan <- fmt.Errorf("virtctl does not support VNC on %v", osType)
			return
		}

		if vncBin == "" {
			glog.Errorf("No supported VNC app found in %s", osType)
			err = fmt.Errorf("No supported VNC app found in %s", osType)
		} else {
			if glog.V(4) {
				glog.Infof("Executing commandline: '%s %v'", vncBin, args)
			}
			cmnd := exec.Command(vncBin, args...)
			output, err := cmnd.CombinedOutput()
			if err != nil {
				glog.Errorf("%s execution failed: %v, output: %v", vncBin, err, string(output))
			} else {
				glog.V(2).Infof("remote-viewer output: %v", string(output))
			}
		}
		viewResChan <- err
	}()

	go func() {
		defer close(stopChan)
		interrupt := make(chan os.Signal, 1)
		signal.Notify(interrupt, os.Interrupt)
		<-interrupt
	}()

	select {
	case <-stopChan:
	case err = <-readStop:
	case err = <-writeStop:
	case err = <-k8ResChan:
	case err = <-viewResChan:
	case err = <-listenResChan:
	}

	if err != nil {
		return fmt.Errorf("Error encountered: %s", err.Error())
	}
	return nil
}

func tigerVncArgs(port int) (args []string) {
	args = append(args, fmt.Sprintf("127.0.0.1:%d", port))
	if glog.V(4) {
		args = append(args, "Log=*:stderr:100")
	}
	return
}

func chickenVncArgs(port int) (args []string) {
	args = append(args, fmt.Sprintf("127.0.0.1:%d", port))
	return
}

func realVncArgs(port int) (args []string) {
	args = append(args, fmt.Sprintf("127.0.0.1:%d", port))
	args = append(args, "-WarnUnencrypted=0")
	args = append(args, "-Shared=0")
	args = append(args, "-ShareFiles=0")
	if glog.V(4) {
		args = append(args, "-log=*:stderr:100")
	}
	return
}

func remoteViewerArgs(port int) (args []string) {
	args = append(args, fmt.Sprintf("vnc://127.0.0.1:%d", port))
	if glog.V(4) {
		args = append(args, "--debug")
	}
	return
}

func usage() string {
	usage := "  # Connect to 'testvmi' via remote-viewer:\n"
	usage += "  virtctl vnc testvmi"
	return usage
}
<|endoftext|>