<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"
	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/util/i18n"

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

const (
	bash_completion_func = `# 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_get_namespaces()
{
    local template kubectl_out
    template="{{ range .items  }}{{ .metadata.name }} {{ end }}"
    if kubectl_out=$(kubectl get -o template --template="${template}" namespace 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_pod()
{
    __kubectl_parse_get "pod"
}

__kubectl_get_resource_rc()
{
    __kubectl_parse_get "rc"
}

__kubectl_get_resource_node()
{
    __kubectl_parse_get "node"
}

# $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_stop | 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
            ;;
        *)
            ;;
    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.
	valid_resources = `Valid resource types include:

    * all
    * certificatesigningrequests (aka 'csr')
    * clusters (valid only for federation apiservers)
    * clusterrolebindings
    * clusterroles
    * componentstatuses (aka 'cs')
    * configmaps (aka 'cm')
    * 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
    * nodes (aka 'no')
    * persistentvolumeclaims (aka 'pvc')
    * persistentvolumes (aka 'pv')
    * pods (aka 'po')
    * poddisruptionbudgets (aka 'pdb')
    * podsecuritypolicies (aka 'psp')
    * podtemplates
    * replicasets (aka 'rs')
    * replicationcontrollers (aka 'rc')
    * resourcequotas (aka 'quota')
    * rolebindings
    * roles
    * secrets
    * serviceaccounts (aka 'sa')
    * services (aka 'svc')
    * statefulsets
    * storageclasses
    * thirdpartyresources
    `
)

// 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: bash_completion_func,
	}

	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, 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, in, out, err),
			},
		},
		{
			Message: "Advanced Commands:",
			Commands: []*cobra.Command{
				NewCmdApply(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(f, out, ""),
			},
		},
	}
	groups.Add(cmds)

	filters := []string{
		"options",
		Deprecated("kubectl", "delete", cmds, NewCmdStop(f, out)),
	}
	templates.ActsAsRootCommand(cmds, filters, groups...)

	if cmds.Flag("namespace") != nil {
		if cmds.Flag("namespace").Annotations == nil {
			cmds.Flag("namespace").Annotations = map[string][]string{}
		}
		cmds.Flag("namespace").Annotations[cobra.BashCompCustom] = append(
			cmds.Flag("namespace").Annotations[cobra.BashCompCustom],
			"__kubectl_get_namespaces",
		)
	}

	cmds.AddCommand(cmdconfig.NewCmdConfig(clientcmd.NewDefaultPathOptions(), 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)
}

func Deprecated(baseName, to string, parent, cmd *cobra.Command) string {
	cmd.Long = fmt.Sprintf("Deprecated: This command is deprecated, all its functionalities are covered by \"%s %s\"", baseName, to)
	cmd.Short = fmt.Sprintf("Deprecated: %s", to)
	parent.AddCommand(cmd)
	return cmd.Name()
}
<commit_msg>Support --context flag completion for kubectl<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"
	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/util/i18n"

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

const (
	bash_completion_func = `# 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_get_namespaces()
{
    local template kubectl_out
    template="{{ range .items  }}{{ .metadata.name }} {{ end }}"
    if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then
        COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
    fi
}

__kubectl_get_contexts()
{
    local template kubectl_out
    template="{{ range .contexts  }}{{ .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_pod()
{
    __kubectl_parse_get "pod"
}

__kubectl_get_resource_rc()
{
    __kubectl_parse_get "rc"
}

__kubectl_get_resource_node()
{
    __kubectl_parse_get "node"
}

# $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_stop | 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
            ;;
        *)
            ;;
    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.
	valid_resources = `Valid resource types include:

    * all
    * certificatesigningrequests (aka 'csr')
    * clusters (valid only for federation apiservers)
    * clusterrolebindings
    * clusterroles
    * componentstatuses (aka 'cs')
    * configmaps (aka 'cm')
    * 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
    * nodes (aka 'no')
    * persistentvolumeclaims (aka 'pvc')
    * persistentvolumes (aka 'pv')
    * pods (aka 'po')
    * poddisruptionbudgets (aka 'pdb')
    * podsecuritypolicies (aka 'psp')
    * podtemplates
    * replicasets (aka 'rs')
    * replicationcontrollers (aka 'rc')
    * resourcequotas (aka 'quota')
    * rolebindings
    * roles
    * secrets
    * serviceaccounts (aka 'sa')
    * services (aka 'svc')
    * statefulsets
    * storageclasses
    * thirdpartyresources
    `
)

// 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: bash_completion_func,
	}

	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, 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, in, out, err),
			},
		},
		{
			Message: "Advanced Commands:",
			Commands: []*cobra.Command{
				NewCmdApply(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(f, out, ""),
			},
		},
	}
	groups.Add(cmds)

	filters := []string{
		"options",
		Deprecated("kubectl", "delete", cmds, NewCmdStop(f, out)),
	}
	templates.ActsAsRootCommand(cmds, filters, groups...)

	if cmds.Flag("namespace") != nil {
		if cmds.Flag("namespace").Annotations == nil {
			cmds.Flag("namespace").Annotations = map[string][]string{}
		}
		cmds.Flag("namespace").Annotations[cobra.BashCompCustom] = append(
			cmds.Flag("namespace").Annotations[cobra.BashCompCustom],
			"__kubectl_get_namespaces",
		)
	}

	if cmds.Flag("context") != nil {
		if cmds.Flag("context").Annotations == nil {
			cmds.Flag("context").Annotations = map[string][]string{}
		}
		cmds.Flag("context").Annotations[cobra.BashCompCustom] = append(
			cmds.Flag("context").Annotations[cobra.BashCompCustom],
			"__kubectl_get_contexts",
		)
	}

	cmds.AddCommand(cmdconfig.NewCmdConfig(clientcmd.NewDefaultPathOptions(), 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)
}

func Deprecated(baseName, to string, parent, cmd *cobra.Command) string {
	cmd.Long = fmt.Sprintf("Deprecated: This command is deprecated, all its functionalities are covered by \"%s %s\"", baseName, to)
	cmd.Short = fmt.Sprintf("Deprecated: %s", to)
	parent.AddCommand(cmd)
	return cmd.Name()
}
<|endoftext|>


<commit_before>// +build go1.12

package mutagen

import (
	"encoding/binary"
	"fmt"
	"io"
)

const (
	// VersionMajor represents the current major version of Mutagen.
	VersionMajor = 0
	// VersionMinor represents the current minor version of Mutagen.
	VersionMinor = 9
	// VersionPatch represents the current patch version of Mutagen.
	VersionPatch = 0
	// VersionTag represents a tag to be appended to the Mutagen version string.
	// It must not contain spaces. If empty, no tag is appended to the version
	// string.
	VersionTag = "dev"
)

// Version provides a stringified version of the current Mutagen version.
var Version string

// init performs global initialization.
func init() {
	// Compute the stringified version.
	if VersionTag != "" {
		Version = fmt.Sprintf("%d.%d.%d-%s", VersionMajor, VersionMinor, VersionPatch, VersionTag)
	} else {
		Version = fmt.Sprintf("%d.%d.%d", VersionMajor, VersionMinor, VersionPatch)
	}
}

// versionBytes is a type that can be used to send and receive version
// information over the wire.
type versionBytes [12]byte

// SendVersion writes the current Mutagen version to the specified writer.
func SendVersion(writer io.Writer) error {
	// Compute the version bytes.
	var data versionBytes
	binary.BigEndian.PutUint32(data[:4], VersionMajor)
	binary.BigEndian.PutUint32(data[4:8], VersionMinor)
	binary.BigEndian.PutUint32(data[8:], VersionPatch)

	// Transmit the bytes.
	_, err := writer.Write(data[:])
	return err
}

// ReceiveVersion reads version information from the specified reader.
func ReceiveVersion(reader io.Reader) (uint32, uint32, uint32, error) {
	// Read the bytes.
	var data versionBytes
	if _, err := io.ReadFull(reader, data[:]); err != nil {
		return 0, 0, 0, err
	}

	// Decode components.
	major := binary.BigEndian.Uint32(data[:4])
	minor := binary.BigEndian.Uint32(data[4:8])
	patch := binary.BigEndian.Uint32(data[8:])

	// Done.
	return major, minor, patch, nil
}

// ReceiveAndCompareVersion reads version information from the specified reader
// and ensures that it matches the current Mutagen version.
func ReceiveAndCompareVersion(reader io.Reader) (bool, error) {
	// Receive the version.
	major, minor, patch, err := ReceiveVersion(reader)
	if err != nil {
		return false, err
	}

	// Compare the version.
	return major == VersionMajor &&
		minor == VersionMinor &&
		patch == VersionPatch, nil
}
<commit_msg>Bumped version to v0.9.0-beta1.<commit_after>// +build go1.12

package mutagen

import (
	"encoding/binary"
	"fmt"
	"io"
)

const (
	// VersionMajor represents the current major version of Mutagen.
	VersionMajor = 0
	// VersionMinor represents the current minor version of Mutagen.
	VersionMinor = 9
	// VersionPatch represents the current patch version of Mutagen.
	VersionPatch = 0
	// VersionTag represents a tag to be appended to the Mutagen version string.
	// It must not contain spaces. If empty, no tag is appended to the version
	// string.
	VersionTag = "beta1"
)

// Version provides a stringified version of the current Mutagen version.
var Version string

// init performs global initialization.
func init() {
	// Compute the stringified version.
	if VersionTag != "" {
		Version = fmt.Sprintf("%d.%d.%d-%s", VersionMajor, VersionMinor, VersionPatch, VersionTag)
	} else {
		Version = fmt.Sprintf("%d.%d.%d", VersionMajor, VersionMinor, VersionPatch)
	}
}

// versionBytes is a type that can be used to send and receive version
// information over the wire.
type versionBytes [12]byte

// SendVersion writes the current Mutagen version to the specified writer.
func SendVersion(writer io.Writer) error {
	// Compute the version bytes.
	var data versionBytes
	binary.BigEndian.PutUint32(data[:4], VersionMajor)
	binary.BigEndian.PutUint32(data[4:8], VersionMinor)
	binary.BigEndian.PutUint32(data[8:], VersionPatch)

	// Transmit the bytes.
	_, err := writer.Write(data[:])
	return err
}

// ReceiveVersion reads version information from the specified reader.
func ReceiveVersion(reader io.Reader) (uint32, uint32, uint32, error) {
	// Read the bytes.
	var data versionBytes
	if _, err := io.ReadFull(reader, data[:]); err != nil {
		return 0, 0, 0, err
	}

	// Decode components.
	major := binary.BigEndian.Uint32(data[:4])
	minor := binary.BigEndian.Uint32(data[4:8])
	patch := binary.BigEndian.Uint32(data[8:])

	// Done.
	return major, minor, patch, nil
}

// ReceiveAndCompareVersion reads version information from the specified reader
// and ensures that it matches the current Mutagen version.
func ReceiveAndCompareVersion(reader io.Reader) (bool, error) {
	// Receive the version.
	major, minor, patch, err := ReceiveVersion(reader)
	if err != nil {
		return false, err
	}

	// Compare the version.
	return major == VersionMajor &&
		minor == VersionMinor &&
		patch == VersionPatch, nil
}
<|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            = "5.0.1-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>debug project.go<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            = "5.0.1-masterupgrade"
)

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            = "5.17.0"
)

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>Bump version to 5.17.1-dev (#1642)<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            = "5.17.1-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            = "5.0.0-beta1"
)

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>Bump version to 5.0.1-dev (#1156)<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            = "5.0.1-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 server

import (
	"fmt"
	"github.com/Aptomi/aptomi/pkg/engine/apply"
	"github.com/Aptomi/aptomi/pkg/engine/diff"
	"github.com/Aptomi/aptomi/pkg/engine/resolve"
	"github.com/Aptomi/aptomi/pkg/event"
	"github.com/Aptomi/aptomi/pkg/lang"
	"github.com/Aptomi/aptomi/pkg/plugin"
	"github.com/Aptomi/aptomi/pkg/plugin/helm"
	"github.com/Aptomi/aptomi/pkg/runtime"
	log "github.com/Sirupsen/logrus"
	"runtime/debug"
	"time"
)

func logError(err interface{}) {
	log.Errorf("Error while enforcing policy: %s", err)

	// todo make configurable
	debug.PrintStack()
}

func (server *Server) enforceLoop() error {
	for {
		err := server.enforce()
		if err != nil {
			logError(err)
		}
		time.Sleep(5 * time.Second)
	}
}

func (server *Server) enforce() error {
	server.enforcementIdx++

	defer func() {
		if err := recover(); err != nil {
			logError(err)
		}
	}()

	desiredPolicy, desiredPolicyGen, err := server.store.GetPolicy(runtime.LastGen)
	if err != nil {
		return fmt.Errorf("error while getting desiredPolicy: %s", err)
	}

	// if policy is not found, it means it somehow was not initialized correctly. let's return error
	if desiredPolicy == nil {
		return fmt.Errorf("desiredPolicy is nil, does not exist in the store")
	}

	actualState, err := server.store.GetActualState()
	if err != nil {
		return fmt.Errorf("error while getting actual state: %s", err)
	}

	eventLog := event.NewLog(fmt.Sprintf("enforce-%d-resolve", server.enforcementIdx), true)
	resolver := resolve.NewPolicyResolver(desiredPolicy, server.externalData, eventLog)
	desiredState, err := resolver.ResolveAllDependencies()
	if err != nil {
		// todo save eventlog
		return fmt.Errorf("cannot resolve desiredPolicy: %v %v %v", err, desiredState, actualState)
	}

	// todo think about initial state when there is no revision at all
	currRevision, err := server.store.GetRevision(runtime.LastGen)
	if err != nil {
		return fmt.Errorf("unable to get curr revision: %s", err)
	}

	stateDiff := diff.NewPolicyResolutionDiff(desiredState, actualState)

	nextRevision, err := server.store.NewRevision(desiredPolicyGen)
	if err != nil {
		return fmt.Errorf("unable to get next revision: %s", err)
	}

	// policy changed while no actions needed to achieve desired state
	if len(stateDiff.Actions) <= 0 && currRevision != nil && currRevision.Policy == nextRevision.Policy {
		log.Infof("(enforce-%d) No changes, policy gen %d", server.enforcementIdx, desiredPolicyGen)
		return nil
	}
	log.Infof("(enforce-%d) New revision %d, policy gen %d, %d actions need to be applied", server.enforcementIdx, nextRevision.GetGeneration(), desiredPolicyGen, len(stateDiff.Actions))

	// todo save eventlog (if there were changes?)

	// todo if policy gen changed, we still need to save revision but with progress == done

	// Save revision
	err = server.store.SaveRevision(nextRevision)
	if err != nil {
		return fmt.Errorf("error while saving new revision: %s", err)
	}

	// Build plugin registry
	var pluginRegistry plugin.Registry
	if server.cfg.Enforcer.Noop {
		log.Infof("(enforce-%d) Applying changes in noop mode (sleep per action = %d seconds)", server.enforcementIdx, server.cfg.Enforcer.NoopSleep)
		pluginRegistry = &plugin.MockRegistry{
			DeployPlugin:      &plugin.MockDeployPlugin{SleepTime: time.Second * time.Duration(server.cfg.Enforcer.NoopSleep)},
			PostProcessPlugin: &plugin.MockPostProcessPlugin{},
		}
	} else {
		log.Infof("(enforce-%d) Applying changes", server.enforcementIdx)
		helmIstio := helm.NewPlugin(server.cfg.Helm)
		pluginRegistry = plugin.NewRegistry(
			[]plugin.DeployPlugin{helmIstio},
			[]plugin.PostProcessPlugin{helmIstio},
		)
	}

	actualPolicy, err := server.getActualPolicy()
	if err != nil {
		return fmt.Errorf("error while getting actual policy: %s", err)
	}

	eventLog = event.NewLog(fmt.Sprintf("enforce-%d-apply", server.enforcementIdx), true)
	applier := apply.NewEngineApply(desiredPolicy, desiredState, actualPolicy, actualState, server.store.GetActualStateUpdater(), server.externalData, pluginRegistry, stateDiff.Actions, eventLog, server.store.GetRevisionProgressUpdater(nextRevision))
	_, err = applier.Apply()

	// todo save eventlog

	if err != nil {
		return fmt.Errorf("error while applying new revision: %s", err)
	}
	log.Infof("(enforce-%d) New revision %d successfully applied, %d component instances", server.enforcementIdx, nextRevision.GetGeneration(), len(desiredState.ComponentProcessingOrder))

	return nil
}

func (server *Server) getActualPolicy() (*lang.Policy, error) {
	currRevision, err := server.store.GetRevision(runtime.LastGen)
	if err != nil {
		return nil, fmt.Errorf("unable to get current revision: %s", err)
	}

	// it's just a first revision
	if currRevision == nil {
		return lang.NewPolicy(), nil
	}

	actualPolicy, _, err := server.store.GetPolicy(currRevision.Policy)
	if err != nil {
		return nil, fmt.Errorf("unable to get actual policy: %s", err)
	}

	return actualPolicy, nil
}
<commit_msg>removed PrintStack(). it was pretty useless, as it was printing the current stack anyway<commit_after>package server

import (
	"fmt"
	"github.com/Aptomi/aptomi/pkg/engine/apply"
	"github.com/Aptomi/aptomi/pkg/engine/diff"
	"github.com/Aptomi/aptomi/pkg/engine/resolve"
	"github.com/Aptomi/aptomi/pkg/event"
	"github.com/Aptomi/aptomi/pkg/lang"
	"github.com/Aptomi/aptomi/pkg/plugin"
	"github.com/Aptomi/aptomi/pkg/plugin/helm"
	"github.com/Aptomi/aptomi/pkg/runtime"
	log "github.com/Sirupsen/logrus"
	"time"
)

func logError(err interface{}) {
	log.Errorf("Error while enforcing policy: %s", err)
}

func (server *Server) enforceLoop() error {
	for {
		err := server.enforce()
		if err != nil {
			logError(err)
		}
		time.Sleep(5 * time.Second)
	}
}

func (server *Server) enforce() error {
	server.enforcementIdx++

	defer func() {
		if err := recover(); err != nil {
			logError(err)
		}
	}()

	desiredPolicy, desiredPolicyGen, err := server.store.GetPolicy(runtime.LastGen)
	if err != nil {
		return fmt.Errorf("error while getting desiredPolicy: %s", err)
	}

	// if policy is not found, it means it somehow was not initialized correctly. let's return error
	if desiredPolicy == nil {
		return fmt.Errorf("desiredPolicy is nil, does not exist in the store")
	}

	actualState, err := server.store.GetActualState()
	if err != nil {
		return fmt.Errorf("error while getting actual state: %s", err)
	}

	eventLog := event.NewLog(fmt.Sprintf("enforce-%d-resolve", server.enforcementIdx), true)
	resolver := resolve.NewPolicyResolver(desiredPolicy, server.externalData, eventLog)
	desiredState, err := resolver.ResolveAllDependencies()
	if err != nil {
		// todo save eventlog
		return fmt.Errorf("cannot resolve desiredPolicy: %v %v %v", err, desiredState, actualState)
	}

	// todo think about initial state when there is no revision at all
	currRevision, err := server.store.GetRevision(runtime.LastGen)
	if err != nil {
		return fmt.Errorf("unable to get curr revision: %s", err)
	}

	stateDiff := diff.NewPolicyResolutionDiff(desiredState, actualState)

	nextRevision, err := server.store.NewRevision(desiredPolicyGen)
	if err != nil {
		return fmt.Errorf("unable to get next revision: %s", err)
	}

	// policy changed while no actions needed to achieve desired state
	if len(stateDiff.Actions) <= 0 && currRevision != nil && currRevision.Policy == nextRevision.Policy {
		log.Infof("(enforce-%d) No changes, policy gen %d", server.enforcementIdx, desiredPolicyGen)
		return nil
	}
	log.Infof("(enforce-%d) New revision %d, policy gen %d, %d actions need to be applied", server.enforcementIdx, nextRevision.GetGeneration(), desiredPolicyGen, len(stateDiff.Actions))

	// todo save eventlog (if there were changes?)

	// todo if policy gen changed, we still need to save revision but with progress == done

	// Save revision
	err = server.store.SaveRevision(nextRevision)
	if err != nil {
		return fmt.Errorf("error while saving new revision: %s", err)
	}

	// Build plugin registry
	var pluginRegistry plugin.Registry
	if server.cfg.Enforcer.Noop {
		log.Infof("(enforce-%d) Applying changes in noop mode (sleep per action = %d seconds)", server.enforcementIdx, server.cfg.Enforcer.NoopSleep)
		pluginRegistry = &plugin.MockRegistry{
			DeployPlugin:      &plugin.MockDeployPlugin{SleepTime: time.Second * time.Duration(server.cfg.Enforcer.NoopSleep)},
			PostProcessPlugin: &plugin.MockPostProcessPlugin{},
		}
	} else {
		log.Infof("(enforce-%d) Applying changes", server.enforcementIdx)
		helmIstio := helm.NewPlugin(server.cfg.Helm)
		pluginRegistry = plugin.NewRegistry(
			[]plugin.DeployPlugin{helmIstio},
			[]plugin.PostProcessPlugin{helmIstio},
		)
	}

	actualPolicy, err := server.getActualPolicy()
	if err != nil {
		return fmt.Errorf("error while getting actual policy: %s", err)
	}

	eventLog = event.NewLog(fmt.Sprintf("enforce-%d-apply", server.enforcementIdx), true)
	applier := apply.NewEngineApply(desiredPolicy, desiredState, actualPolicy, actualState, server.store.GetActualStateUpdater(), server.externalData, pluginRegistry, stateDiff.Actions, eventLog, server.store.GetRevisionProgressUpdater(nextRevision))
	_, err = applier.Apply()

	// todo save eventlog

	if err != nil {
		return fmt.Errorf("error while applying new revision: %s", err)
	}
	log.Infof("(enforce-%d) New revision %d successfully applied, %d component instances", server.enforcementIdx, nextRevision.GetGeneration(), len(desiredState.ComponentProcessingOrder))

	return nil
}

func (server *Server) getActualPolicy() (*lang.Policy, error) {
	currRevision, err := server.store.GetRevision(runtime.LastGen)
	if err != nil {
		return nil, fmt.Errorf("unable to get current revision: %s", err)
	}

	// it's just a first revision
	if currRevision == nil {
		return lang.NewPolicy(), nil
	}

	actualPolicy, _, err := server.store.GetPolicy(currRevision.Policy)
	if err != nil {
		return nil, fmt.Errorf("unable to get actual policy: %s", err)
	}

	return actualPolicy, nil
}
<|endoftext|>


<commit_before>package server

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"

	"github.com/golang/glog"
	"github.com/gorilla/mux"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"

	vmapi "github.com/rancher/vm/pkg/apis/ranchervm/v1alpha1"
)

type InstanceList struct {
	Instances []*vmapi.VirtualMachine `json:"data"`
}

func (s *server) InstanceList(w http.ResponseWriter, r *http.Request) {
	vms, err := s.vmLister.List(labels.Everything())
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	resp, err := json.Marshal(InstanceList{
		Instances: vms,
	})

	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

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

type InstanceCreate struct {
	Name        string   `json:"name"`
	Cpus        int32    `json:"cpus"`
	Memory      int32    `json:"memory"`
	Image       string   `json:"image"`
	Action      string   `json:"action"`
	PublicKeys  []string `json:"pubkey"`
	HostedNovnc bool     `json:"novnc"`
	Instances   int32    `json:"instances"`
}

func (s *server) InstanceCreate(w http.ResponseWriter, r *http.Request) {
	var ic InstanceCreate
	switch {
	case strings.HasPrefix(r.Header.Get("Content-Type"), "application/x-www-form-urlencoded"):
		r.ParseForm()

		if len(r.PostForm["name"]) != 1 ||
			len(r.PostForm["cpus"]) != 1 ||
			len(r.PostForm["mem"]) != 1 ||
			len(r.PostForm["image"]) != 1 ||
			len(r.PostForm["pubkey"]) < 1 ||
			len(r.PostForm["action"]) != 1 ||
			len(r.PostForm["novnc"]) != 1 ||
			len(r.PostForm["instances"]) != 1 {

			w.WriteHeader(http.StatusBadRequest)
			return
		}

		cpus, _ := strconv.Atoi(r.PostForm["cpus"][0])
		mem, _ := strconv.Atoi(r.PostForm["mem"][0])
		instances, _ := strconv.Atoi(r.PostForm["instances"][0])
		ic = InstanceCreate{
			Name:        r.PostForm["name"][0],
			Cpus:        int32(cpus),
			Memory:      int32(mem),
			Image:       r.PostForm["image"][0],
			Action:      r.PostForm["action"][0],
			PublicKeys:  r.PostForm["pubkey"],
			HostedNovnc: (r.PostForm["novnc"][0] == "true"),
			Instances:   int32(instances),
		}
	default:
		defer r.Body.Close()
		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		err = json.Unmarshal(body, &ic)
		if err != nil {
			glog.V(3).Infof("error unmarshaling json: %v", err)
			w.WriteHeader(http.StatusBadRequest)
			return
		}
	}

	if !isValidName(ic.Name) ||
		!isValidCpus(ic.Cpus) ||
		!isValidMemory(ic.Memory) ||
		!isValidImage(ic.Image) ||
		!isValidAction(vmapi.ActionType(ic.Action)) ||
		!isValidPublicKeys(ic.PublicKeys) ||
		!isValidInstanceCount(ic.Instances) {

		w.WriteHeader(http.StatusBadRequest)
		return
	}

	if ic.Instances == 1 {
		s.instanceCreateOne(w, r, &ic)
	} else {
		s.instanceCreateMany(w, r, &ic)
	}
}

func (s *server) instanceCreateOne(w http.ResponseWriter, r *http.Request, ic *InstanceCreate) {
	vm := &vmapi.VirtualMachine{
		ObjectMeta: metav1.ObjectMeta{
			Name: ic.Name,
		},
		Spec: vmapi.VirtualMachineSpec{
			Cpus:         ic.Cpus,
			MemoryMB:     ic.Memory,
			MachineImage: vmapi.MachineImageType(ic.Image),
			Action:       vmapi.ActionType(ic.Action),
			PublicKeys:   ic.PublicKeys,
			HostedNovnc:  ic.HostedNovnc,
		},
	}

	vm, err := s.vmClient.VirtualmachineV1alpha1().VirtualMachines().Create(vm)
	switch {
	case err == nil:
		w.WriteHeader(http.StatusCreated)
	case apierrors.IsAlreadyExists(err):
		w.WriteHeader(http.StatusConflict)
	default:
		w.WriteHeader(http.StatusInternalServerError)
	}
}

func (s *server) instanceCreateMany(w http.ResponseWriter, r *http.Request, ic *InstanceCreate) {
	for i := int32(1); i <= ic.Instances; i++ {
		vm := &vmapi.VirtualMachine{
			ObjectMeta: metav1.ObjectMeta{
				Name: fmt.Sprintf("%s-%02d", ic.Name, i),
			},
			Spec: vmapi.VirtualMachineSpec{
				Cpus:         ic.Cpus,
				MemoryMB:     ic.Memory,
				MachineImage: vmapi.MachineImageType(ic.Image),
				Action:       vmapi.ActionType(ic.Action),
				PublicKeys:   ic.PublicKeys,
				HostedNovnc:  ic.HostedNovnc,
			},
		}

		vm, err := s.vmClient.VirtualmachineV1alpha1().VirtualMachines().Create(vm)
		switch {
		case err == nil:
			continue
		case apierrors.IsAlreadyExists(err):
			w.WriteHeader(http.StatusConflict)
			return
		default:
			glog.V(3).Infof("error creating instance: %v", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	}
	w.WriteHeader(http.StatusCreated)
}

func (s *server) InstanceDelete(w http.ResponseWriter, r *http.Request) {
	name := mux.Vars(r)["name"]

	if !isValidName(name) {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	err := s.vmClient.VirtualmachineV1alpha1().VirtualMachines().Delete(name, &metav1.DeleteOptions{})
	switch {
	case err == nil:
		w.WriteHeader(http.StatusNoContent)
	case apierrors.IsNotFound(err):
		w.WriteHeader(http.StatusNotFound)
	default:
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(err.Error()))
	}
}

type InstanceNames struct {
	Names []string `json:"names"`
}

func parseInstanceNames(w http.ResponseWriter, r *http.Request) *InstanceNames {
	var in InstanceNames
	switch {
	case strings.HasPrefix(r.Header.Get("Content-Type"), "application/x-www-form-urlencoded"):
		r.ParseForm()
		if len(r.PostForm["names"]) == 0 {
			w.WriteHeader(http.StatusBadRequest)
			return nil
		}
		in = InstanceNames{
			Names: r.PostForm["names"],
		}

	default:
		defer r.Body.Close()
		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			return nil
		}
		err = json.Unmarshal(body, &in)
		if err != nil {
			glog.V(3).Infof("error unmarshaling json: %v", err)
			w.WriteHeader(http.StatusBadRequest)
			return nil
		}
	}
	return &in
}

func (s *server) InstanceDeleteMulti(w http.ResponseWriter, r *http.Request) {
	in := parseInstanceNames(w, r)
	if in == nil {
		return
	}

	if !isValidName(in.Names...) {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	for _, name := range in.Names {
		err := s.vmClient.VirtualmachineV1alpha1().VirtualMachines().Delete(name, &metav1.DeleteOptions{})
		switch {
		case err == nil:
			continue
		case apierrors.IsNotFound(err):
			w.WriteHeader(http.StatusNotFound)
			return
		default:
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte(err.Error()))
			return
		}
	}
	w.WriteHeader(http.StatusNoContent)
}

func (s *server) InstanceAction(w http.ResponseWriter, r *http.Request) {
	name := mux.Vars(r)["name"]
	action := mux.Vars(r)["action"]
	actionType := vmapi.ActionType(action)

	if !isValidName(name) || !isValidAction(actionType) {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	vm, err := s.vmLister.Get(name)
	switch {
	case err == nil:
		break
	case apierrors.IsNotFound(err):
		w.WriteHeader(http.StatusNotFound)
		return
	default:
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(err.Error()))
		return
	}

	vm2 := vm.DeepCopy()
	vm2.Spec.Action = vmapi.ActionType(action)
	if vm.Spec.Action == vm2.Spec.Action {
		w.WriteHeader(http.StatusNotModified)
		return
	}

	vm2, err = s.vmClient.VirtualmachineV1alpha1().VirtualMachines().Update(vm2)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
	} else {
		w.WriteHeader(http.StatusNoContent)
	}
}

func (s *server) InstanceActionMulti(w http.ResponseWriter, r *http.Request) {
	action := mux.Vars(r)["action"]
	actionType := vmapi.ActionType(action)
	in := parseInstanceNames(w, r)
	if in == nil {
		return
	}

	if !isValidAction(actionType) || !isValidName(in.Names...) {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	for _, name := range in.Names {
		vm, err := s.vmLister.Get(name)
		switch {
		case err == nil:
			break
		case apierrors.IsNotFound(err):
			w.WriteHeader(http.StatusNotFound)
			return
		default:
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte(err.Error()))
			return
		}

		vm2 := vm.DeepCopy()
		vm2.Spec.Action = vmapi.ActionType(action)
		if vm.Spec.Action == vm2.Spec.Action {
			// In multi scenario we behave idempotently
			continue
		}

		if vm2, err = s.vmClient.VirtualmachineV1alpha1().VirtualMachines().Update(vm2); err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	}
	w.WriteHeader(http.StatusNoContent)
}
<commit_msg>Disallow migration of vm in non-running state<commit_after>package server

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"

	"github.com/golang/glog"
	"github.com/gorilla/mux"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"

	vmapi "github.com/rancher/vm/pkg/apis/ranchervm/v1alpha1"
)

type InstanceList struct {
	Instances []*vmapi.VirtualMachine `json:"data"`
}

func (s *server) InstanceList(w http.ResponseWriter, r *http.Request) {
	vms, err := s.vmLister.List(labels.Everything())
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	resp, err := json.Marshal(InstanceList{
		Instances: vms,
	})

	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

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

type InstanceCreate struct {
	Name        string   `json:"name"`
	Cpus        int32    `json:"cpus"`
	Memory      int32    `json:"memory"`
	Image       string   `json:"image"`
	Action      string   `json:"action"`
	PublicKeys  []string `json:"pubkey"`
	HostedNovnc bool     `json:"novnc"`
	Instances   int32    `json:"instances"`
}

func (s *server) InstanceCreate(w http.ResponseWriter, r *http.Request) {
	var ic InstanceCreate
	switch {
	case strings.HasPrefix(r.Header.Get("Content-Type"), "application/x-www-form-urlencoded"):
		r.ParseForm()

		if len(r.PostForm["name"]) != 1 ||
			len(r.PostForm["cpus"]) != 1 ||
			len(r.PostForm["mem"]) != 1 ||
			len(r.PostForm["image"]) != 1 ||
			len(r.PostForm["pubkey"]) < 1 ||
			len(r.PostForm["action"]) != 1 ||
			len(r.PostForm["novnc"]) != 1 ||
			len(r.PostForm["instances"]) != 1 {

			w.WriteHeader(http.StatusBadRequest)
			return
		}

		cpus, _ := strconv.Atoi(r.PostForm["cpus"][0])
		mem, _ := strconv.Atoi(r.PostForm["mem"][0])
		instances, _ := strconv.Atoi(r.PostForm["instances"][0])
		ic = InstanceCreate{
			Name:        r.PostForm["name"][0],
			Cpus:        int32(cpus),
			Memory:      int32(mem),
			Image:       r.PostForm["image"][0],
			Action:      r.PostForm["action"][0],
			PublicKeys:  r.PostForm["pubkey"],
			HostedNovnc: (r.PostForm["novnc"][0] == "true"),
			Instances:   int32(instances),
		}
	default:
		defer r.Body.Close()
		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		err = json.Unmarshal(body, &ic)
		if err != nil {
			glog.V(3).Infof("error unmarshaling json: %v", err)
			w.WriteHeader(http.StatusBadRequest)
			return
		}
	}

	if !isValidName(ic.Name) ||
		!isValidCpus(ic.Cpus) ||
		!isValidMemory(ic.Memory) ||
		!isValidImage(ic.Image) ||
		!isValidAction(vmapi.ActionType(ic.Action)) ||
		!isValidPublicKeys(ic.PublicKeys) ||
		!isValidInstanceCount(ic.Instances) {

		w.WriteHeader(http.StatusBadRequest)
		return
	}

	if ic.Instances == 1 {
		s.instanceCreateOne(w, r, &ic)
	} else {
		s.instanceCreateMany(w, r, &ic)
	}
}

func (s *server) instanceCreateOne(w http.ResponseWriter, r *http.Request, ic *InstanceCreate) {
	vm := &vmapi.VirtualMachine{
		ObjectMeta: metav1.ObjectMeta{
			Name: ic.Name,
		},
		Spec: vmapi.VirtualMachineSpec{
			Cpus:         ic.Cpus,
			MemoryMB:     ic.Memory,
			MachineImage: vmapi.MachineImageType(ic.Image),
			Action:       vmapi.ActionType(ic.Action),
			PublicKeys:   ic.PublicKeys,
			HostedNovnc:  ic.HostedNovnc,
		},
	}

	vm, err := s.vmClient.VirtualmachineV1alpha1().VirtualMachines().Create(vm)
	switch {
	case err == nil:
		w.WriteHeader(http.StatusCreated)
	case apierrors.IsAlreadyExists(err):
		w.WriteHeader(http.StatusConflict)
	default:
		w.WriteHeader(http.StatusInternalServerError)
	}
}

func (s *server) instanceCreateMany(w http.ResponseWriter, r *http.Request, ic *InstanceCreate) {
	for i := int32(1); i <= ic.Instances; i++ {
		vm := &vmapi.VirtualMachine{
			ObjectMeta: metav1.ObjectMeta{
				Name: fmt.Sprintf("%s-%02d", ic.Name, i),
			},
			Spec: vmapi.VirtualMachineSpec{
				Cpus:         ic.Cpus,
				MemoryMB:     ic.Memory,
				MachineImage: vmapi.MachineImageType(ic.Image),
				Action:       vmapi.ActionType(ic.Action),
				PublicKeys:   ic.PublicKeys,
				HostedNovnc:  ic.HostedNovnc,
			},
		}

		vm, err := s.vmClient.VirtualmachineV1alpha1().VirtualMachines().Create(vm)
		switch {
		case err == nil:
			continue
		case apierrors.IsAlreadyExists(err):
			w.WriteHeader(http.StatusConflict)
			return
		default:
			glog.V(3).Infof("error creating instance: %v", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	}
	w.WriteHeader(http.StatusCreated)
}

func (s *server) InstanceDelete(w http.ResponseWriter, r *http.Request) {
	name := mux.Vars(r)["name"]

	if !isValidName(name) {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	err := s.vmClient.VirtualmachineV1alpha1().VirtualMachines().Delete(name, &metav1.DeleteOptions{})
	switch {
	case err == nil:
		w.WriteHeader(http.StatusNoContent)
	case apierrors.IsNotFound(err):
		w.WriteHeader(http.StatusNotFound)
	default:
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(err.Error()))
	}
}

type InstanceNames struct {
	Names []string `json:"names"`
}

func parseInstanceNames(w http.ResponseWriter, r *http.Request) *InstanceNames {
	var in InstanceNames
	switch {
	case strings.HasPrefix(r.Header.Get("Content-Type"), "application/x-www-form-urlencoded"):
		r.ParseForm()
		if len(r.PostForm["names"]) == 0 {
			w.WriteHeader(http.StatusBadRequest)
			return nil
		}
		in = InstanceNames{
			Names: r.PostForm["names"],
		}

	default:
		defer r.Body.Close()
		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			return nil
		}
		err = json.Unmarshal(body, &in)
		if err != nil {
			glog.V(3).Infof("error unmarshaling json: %v", err)
			w.WriteHeader(http.StatusBadRequest)
			return nil
		}
	}
	return &in
}

func (s *server) InstanceDeleteMulti(w http.ResponseWriter, r *http.Request) {
	in := parseInstanceNames(w, r)
	if in == nil {
		return
	}

	if !isValidName(in.Names...) {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	for _, name := range in.Names {
		err := s.vmClient.VirtualmachineV1alpha1().VirtualMachines().Delete(name, &metav1.DeleteOptions{})
		switch {
		case err == nil:
			continue
		case apierrors.IsNotFound(err):
			w.WriteHeader(http.StatusNotFound)
			return
		default:
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte(err.Error()))
			return
		}
	}
	w.WriteHeader(http.StatusNoContent)
}

func (s *server) InstanceAction(w http.ResponseWriter, r *http.Request) {
	name := mux.Vars(r)["name"]
	action := mux.Vars(r)["action"]
	actionType := vmapi.ActionType(action)

	if !isValidName(name) || !isValidAction(actionType) {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	vm, err := s.vmLister.Get(name)
	switch {
	case err == nil:
		break
	case apierrors.IsNotFound(err):
		w.WriteHeader(http.StatusNotFound)
		return
	default:
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(err.Error()))
		return
	}

	vm2 := vm.DeepCopy()
	vm2.Spec.Action = vmapi.ActionType(action)
	if vm.Spec.Action == vm2.Spec.Action {
		w.WriteHeader(http.StatusNotModified)
		return
	}

	vm2, err = s.vmClient.VirtualmachineV1alpha1().VirtualMachines().Update(vm2)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
	} else {
		w.WriteHeader(http.StatusNoContent)
	}
}

func (s *server) InstanceActionMulti(w http.ResponseWriter, r *http.Request) {
	action := mux.Vars(r)["action"]
	actionType := vmapi.ActionType(action)
	in := parseInstanceNames(w, r)
	if in == nil {
		return
	}

	if !isValidAction(actionType) || !isValidName(in.Names...) {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	for _, name := range in.Names {
		vm, err := s.vmLister.Get(name)
		switch {
		case err == nil:
			break
		case apierrors.IsNotFound(err):
			w.WriteHeader(http.StatusNotFound)
			return
		default:
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte(err.Error()))
			return
		}

		vm2 := vm.DeepCopy()
		vm2.Spec.Action = vmapi.ActionType(action)
		if vm.Spec.Action == vm2.Spec.Action {
			// In multi scenario we behave idempotently
			continue
		}
		// migration requires vm in a running phase
		if vm2.Spec.Action == vmapi.ActionMigrate && vm2.Status.State != vmapi.StateRunning {
			continue
		}

		if vm2, err = s.vmClient.VirtualmachineV1alpha1().VirtualMachines().Update(vm2); err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	}
	w.WriteHeader(http.StatusNoContent)
}
<|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"
	"path/filepath"
	"runtime"
	"time"

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

	"kubevirt.io/client-go/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
	MACOS_TIGER_VNC_PATTERN = `/Applications/TigerVNC Viewer*.app/Contents/MacOS/TigerVNC Viewer`

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

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

	REMOTE_VIEWER = "remote-viewer"
	TIGER_VNC     = "vncviewer"
)

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:    templates.ExactArgs("vnc", 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(MACOS_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(MACOS_CHICKEN_VNC); err == nil {
				vncBin = MACOS_CHICKEN_VNC
				args = chickenVncArgs(port)
			} else if !os.IsNotExist(err) {
				viewResChan <- err
				return
			} else if _, err := os.Stat(MACOS_REAL_VNC); err == nil {
				vncBin = MACOS_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", "windows":
			if _, err := exec.LookPath(REMOTE_VIEWER); err == nil {
				vncBin = REMOTE_VIEWER
				args = remoteViewerArgs(port)
			} else if _, err := exec.LookPath(TIGER_VNC); err == nil {
				vncBin = TIGER_VNC
				args = tigerVncArgs(port)
			} else {
				viewResChan <- fmt.Errorf("could not find %s or %s binary in $PATH",
					REMOTE_VIEWER, TIGER_VNC)
				viewResChan <- err
				return
			}
		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 {
	return `  # Connect to 'testvmi' via remote-viewer:\n"
  {{ProgramName}} vnc testvmi`
}
<commit_msg>Add option to run only VNC Proxy in virtctl<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 (
	"encoding/json"
	"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/client-go/kubecli"
	"kubevirt.io/kubevirt/pkg/virtctl/templates"
)

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

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

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

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

	REMOTE_VIEWER = "remote-viewer"
	TIGER_VNC     = "vncviewer"
)

var proxyOnly bool

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:    templates.ExactArgs("vnc", 1),
		RunE: func(cmd *cobra.Command, args []string) error {
			c := VNC{clientConfig: clientConfig}
			return c.Run(cmd, args)
		},
	}
	cmd.Flags().BoolVar(&proxyOnly, "proxy-only", proxyOnly, "--proxy-only=false: Setting this true will run only the virtctl vnc proxy and show the localhost port where VNC viewers can connect")
	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
	}()

	port := ln.Addr().(*net.TCPAddr).Port

	if proxyOnly {
		defer close(doneChan)
		optionString, err := json.Marshal(struct {
			Port int `json:"port"`
		}{port})
		if err != nil {
			return fmt.Errorf("Error encountered: %s", err.Error())
			fmt.Println(string(optionString))
		} else {
			// execute VNC Viewer
			go checkAndRunVNCViewer(doneChan, viewResChan, port)
		}
	}

	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 checkAndRunVNCViewer(doneChan chan struct{}, viewResChan chan error, port int) {
	defer close(doneChan)
	var err error
	args := []string{}

	vncBin := ""
	osType := runtime.GOOS
	switch osType {
	case "darwin":
		if matches, err := filepath.Glob(MACOS_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(MACOS_CHICKEN_VNC); err == nil {
			vncBin = MACOS_CHICKEN_VNC
			args = chickenVncArgs(port)
		} else if !os.IsNotExist(err) {
			viewResChan <- err
			return
		} else if _, err := os.Stat(MACOS_REAL_VNC); err == nil {
			vncBin = MACOS_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", "windows":
		if _, err := exec.LookPath(REMOTE_VIEWER); err == nil {
			vncBin = REMOTE_VIEWER
			args = remoteViewerArgs(port)
		} else if _, err := exec.LookPath(TIGER_VNC); err == nil {
			vncBin = TIGER_VNC
			args = tigerVncArgs(port)
		} else {
			viewResChan <- fmt.Errorf("could not find %s or %s binary in $PATH",
				REMOTE_VIEWER, TIGER_VNC)
			viewResChan <- err
			return
		}
	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
}

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 {
	return `  # Connect to 'testvmi' via remote-viewer:\n"
  {{ProgramName}} vnc testvmi`
}
<|endoftext|>


<commit_before>/*
Copyright 2011 Google Inc.

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 blobref

import (
	"crypto/sha1"
	"fmt"
	"hash"
	"io"
	"reflect"
	"regexp"
)

// Pattern is the regular expression which matches a blobref.
// It does not contain ^ or $.
const Pattern = `\b([a-z][a-z0-9]*)-([a-f0-9]+)\b`

// whole blobref pattern
var kBlobRefPattern = regexp.MustCompile("^" + Pattern + "$")

var supportedDigests = map[string]func() hash.Hash{
	"sha1": func() hash.Hash {
		return sha1.New()
	},
}

// BlobRef is an immutable reference to a blob.
type BlobRef struct {
	hashName string
	digest   string

	strValue string // "<hashname>-<digest>"
}

func (br *BlobRef) GobEncode() ([]byte, error) {
	return []byte(br.String()), nil
}

func (br *BlobRef) GobDecode(b []byte) error {
	dec := Parse(string(b))
	if dec == nil {
		return fmt.Errorf("invalid blobref %q", string(b))
	}
	*br = *dec
	return nil
}

// SizedBlobRef is like a BlobRef but includes because it includes a
// potentially mutable 'Size', this should be used as a stack value,
// not a *SizedBlobRef.
type SizedBlobRef struct {
	*BlobRef
	Size int64
}

func (sb *SizedBlobRef) Equal(o SizedBlobRef) bool {
	return sb.Size == o.Size && sb.BlobRef.String() == o.BlobRef.String()
}

func (sb SizedBlobRef) String() string {
	return fmt.Sprintf("[%s; %d bytes]", sb.BlobRef.String(), sb.Size)
}

type ReadSeekCloser interface {
	io.Reader
	io.Seeker
	io.Closer
}

func (b *BlobRef) HashName() string {
	return b.hashName
}

func (b *BlobRef) Digest() string {
	return b.digest
}

func (b *BlobRef) DigestPrefix(digits int) string {
	if len(b.digest) < digits {
		return b.digest
	}
	return b.digest[:digits]
}

func (b *BlobRef) String() string {
	if b == nil {
		return "<nil-BlobRef>"
	}
	return b.strValue
}

func (b *BlobRef) DomID() string {
	if b == nil {
		return ""
	}
	return "camli-" + b.String()
}

func (o *BlobRef) Equal(other *BlobRef) bool {
	if (o == nil) != (other == nil) {
		return false
	}
	if o == nil {
		return true
	}
	return o.hashName == other.hashName && o.digest == other.digest
}

func (o *BlobRef) Hash() hash.Hash {
	fn, ok := supportedDigests[o.hashName]
	if !ok {
		return nil // TODO: return an error here, not nil
	}
	return fn()
}

func (o *BlobRef) HashMatches(h hash.Hash) bool {
	return fmt.Sprintf("%x", h.Sum(nil)) == o.digest
}

func (o *BlobRef) IsSupported() bool {
	_, ok := supportedDigests[o.hashName]
	return ok
}

func (o *BlobRef) Sum32() uint32 {
	var h32 uint32
	n, err := fmt.Sscanf(o.digest[len(o.digest)-8:], "%8x", &h32)
	if err != nil {
		panic(err)
	}
	if n != 1 {
		panic("sum32")
	}
	return h32
}

var kExpectedDigestSize = map[string]int{
	"md5":  32,
	"sha1": 40,
}

func newBlob(hashName, digest string) *BlobRef {
	strValue := fmt.Sprintf("%s-%s", hashName, digest)
	return &BlobRef{
		hashName: strValue[0:len(hashName)],
		digest:   strValue[len(hashName)+1:],
		strValue: strValue,
	}
}

func blobIfValid(hashname, digest string) *BlobRef {
	expectedSize := kExpectedDigestSize[hashname]
	if expectedSize != 0 && len(digest) != expectedSize {
		return nil
	}
	return newBlob(hashname, digest)
}

// NewHash returns a new hash.Hash of the currently recommended hash type.
// Currently this is just SHA-1, but will likely change within the next
// year or so.
func NewHash() hash.Hash {
	return sha1.New()
}

var sha1Type = reflect.TypeOf(sha1.New())

// FromHash returns a BlobRef representing the given hash.
func FromHash(h hash.Hash) *BlobRef {
	if reflect.TypeOf(h) == sha1Type {
		return newBlob("sha1", fmt.Sprintf("%x", h.Sum(nil)))
	}
	panic(fmt.Sprintf("Currently-unsupported hash type %T", h))
}

// SHA1FromString returns a SHA-1 blobref of the provided string.
func SHA1FromString(s string) *BlobRef {
	s1 := sha1.New()
	s1.Write([]byte(s))
	return FromHash(s1)
}

// FromPattern takes a pattern and if it matches 's' with two exactly two valid
// submatches, returns a BlobRef, else returns nil.
func FromPattern(r *regexp.Regexp, s string) *BlobRef {
	matches := r.FindStringSubmatch(s)
	if len(matches) != 3 {
		return nil
	}
	return blobIfValid(matches[1], matches[2])
}

func Parse(ref string) *BlobRef {
	return FromPattern(kBlobRefPattern, ref)
}

func (br *BlobRef) UnmarshalJSON(d []byte) error {
	if len(d) < 2 || d[0] != '"' || d[len(d)-1] != '"' {
		return fmt.Errorf("blobref: expecting a JSON string to unmarshal, got %q", d)
	}
	refStr := string(d[1 : len(d)-1])
	p := Parse(refStr)
	if p == nil {
		return fmt.Errorf("blobref: invalid blobref %q (%d)", refStr, len(refStr))
	}
	*br = *p
	return nil
}

func (br *BlobRef) MarshalJSON() ([]byte, error) {
	return []byte(fmt.Sprintf("%q", br.String())), nil
}

func MustParse(ref string) *BlobRef {
	br := Parse(ref)
	if br == nil {
		panic("Failed to parse blobref: " + ref)
	}
	return br
}

// May return nil in list positions where the blobref could not be parsed.
func ParseMulti(refs []string) (parsed []*BlobRef) {
	parsed = make([]*BlobRef, 0, len(refs))
	for _, ref := range refs {
		parsed = append(parsed, Parse(ref))
	}
	return
}
<commit_msg>blobref: consistent receiver names, add SHA1FromBytes<commit_after>/*
Copyright 2011 Google Inc.

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 blobref

import (
	"crypto/sha1"
	"fmt"
	"hash"
	"io"
	"reflect"
	"regexp"
)

// Pattern is the regular expression which matches a blobref.
// It does not contain ^ or $.
const Pattern = `\b([a-z][a-z0-9]*)-([a-f0-9]+)\b`

// whole blobref pattern
var kBlobRefPattern = regexp.MustCompile("^" + Pattern + "$")

var supportedDigests = map[string]func() hash.Hash{
	"sha1": func() hash.Hash {
		return sha1.New()
	},
}

// BlobRef is an immutable reference to a blob.
type BlobRef struct {
	hashName string
	digest   string

	strValue string // "<hashname>-<digest>"
}

func (br *BlobRef) GobEncode() ([]byte, error) {
	return []byte(br.String()), nil
}

func (br *BlobRef) GobDecode(b []byte) error {
	dec := Parse(string(b))
	if dec == nil {
		return fmt.Errorf("invalid blobref %q", string(b))
	}
	*br = *dec
	return nil
}

// SizedBlobRef is like a BlobRef but includes because it includes a
// potentially mutable 'Size', this should be used as a stack value,
// not a *SizedBlobRef.
type SizedBlobRef struct {
	*BlobRef
	Size int64
}

func (sb *SizedBlobRef) Equal(o SizedBlobRef) bool {
	return sb.Size == o.Size && sb.BlobRef.String() == o.BlobRef.String()
}

func (sb SizedBlobRef) String() string {
	return fmt.Sprintf("[%s; %d bytes]", sb.BlobRef.String(), sb.Size)
}

type ReadSeekCloser interface {
	io.Reader
	io.Seeker
	io.Closer
}

func (br *BlobRef) HashName() string {
	return br.hashName
}

func (br *BlobRef) Digest() string {
	return br.digest
}

func (br *BlobRef) DigestPrefix(digits int) string {
	if len(br.digest) < digits {
		return br.digest
	}
	return br.digest[:digits]
}

func (br *BlobRef) String() string {
	if br == nil {
		return "<nil-BlobRef>"
	}
	return br.strValue
}

func (br *BlobRef) DomID() string {
	if br == nil {
		return ""
	}
	return "camli-" + br.String()
}

func (br *BlobRef) Equal(other *BlobRef) bool {
	if (br == nil) != (other == nil) {
		return false
	}
	if br == nil {
		return true
	}
	return br.hashName == other.hashName && br.digest == other.digest
}

func (br *BlobRef) Hash() hash.Hash {
	fn, ok := supportedDigests[br.hashName]
	if !ok {
		return nil // TODO: return an error here, not nil
	}
	return fn()
}

func (br *BlobRef) HashMatches(h hash.Hash) bool {
	return fmt.Sprintf("%x", h.Sum(nil)) == br.digest
}

func (br *BlobRef) IsSupported() bool {
	_, ok := supportedDigests[br.hashName]
	return ok
}

func (br *BlobRef) Sum32() uint32 {
	var h32 uint32
	n, err := fmt.Sscanf(br.digest[len(br.digest)-8:], "%8x", &h32)
	if err != nil {
		panic(err)
	}
	if n != 1 {
		panic("sum32")
	}
	return h32
}

var kExpectedDigestSize = map[string]int{
	"md5":  32,
	"sha1": 40,
}

func newBlob(hashName, digest string) *BlobRef {
	strValue := fmt.Sprintf("%s-%s", hashName, digest)
	return &BlobRef{
		hashName: strValue[0:len(hashName)],
		digest:   strValue[len(hashName)+1:],
		strValue: strValue,
	}
}

func blobIfValid(hashname, digest string) *BlobRef {
	expectedSize := kExpectedDigestSize[hashname]
	if expectedSize != 0 && len(digest) != expectedSize {
		return nil
	}
	return newBlob(hashname, digest)
}

// NewHash returns a new hash.Hash of the currently recommended hash type.
// Currently this is just SHA-1, but will likely change within the next
// year or so.
func NewHash() hash.Hash {
	return sha1.New()
}

var sha1Type = reflect.TypeOf(sha1.New())

// FromHash returns a BlobRef representing the given hash.
func FromHash(h hash.Hash) *BlobRef {
	if reflect.TypeOf(h) == sha1Type {
		return newBlob("sha1", fmt.Sprintf("%x", h.Sum(nil)))
	}
	panic(fmt.Sprintf("Currently-unsupported hash type %T", h))
}

// SHA1FromString returns a SHA-1 blobref of the provided string.
func SHA1FromString(s string) *BlobRef {
	s1 := sha1.New()
	s1.Write([]byte(s))
	return FromHash(s1)
}

// SHA1FromBytes returns a SHA-1 blobref of the provided bytes.
func SHA1FromBytes(b []byte) *BlobRef {
	s1 := sha1.New()
	s1.Write(b)
	return FromHash(s1)
}

// FromPattern takes a pattern and if it matches 's' with two exactly two valid
// submatches, returns a BlobRef, else returns nil.
func FromPattern(r *regexp.Regexp, s string) *BlobRef {
	matches := r.FindStringSubmatch(s)
	if len(matches) != 3 {
		return nil
	}
	return blobIfValid(matches[1], matches[2])
}

func Parse(ref string) *BlobRef {
	return FromPattern(kBlobRefPattern, ref)
}

func (br *BlobRef) UnmarshalJSON(d []byte) error {
	if len(d) < 2 || d[0] != '"' || d[len(d)-1] != '"' {
		return fmt.Errorf("blobref: expecting a JSON string to unmarshal, got %q", d)
	}
	refStr := string(d[1 : len(d)-1])
	p := Parse(refStr)
	if p == nil {
		return fmt.Errorf("blobref: invalid blobref %q (%d)", refStr, len(refStr))
	}
	*br = *p
	return nil
}

func (br *BlobRef) MarshalJSON() ([]byte, error) {
	return []byte(fmt.Sprintf("%q", br.String())), nil
}

func MustParse(ref string) *BlobRef {
	br := Parse(ref)
	if br == nil {
		panic("Failed to parse blobref: " + ref)
	}
	return br
}

// May return nil in list positions where the blobref could not be parsed.
func ParseMulti(refs []string) (parsed []*BlobRef) {
	parsed = make([]*BlobRef, 0, len(refs))
	for _, ref := range refs {
		parsed = append(parsed, Parse(ref))
	}
	return
}
<|endoftext|>


<commit_before>package command

const (
	// Version is the current Pgweb application version
	Version = "0.11.7"
)

var (
	// GitCommit contains the Git commit SHA for the binary
	GitCommit string

	// BuildTime contains the binary build time
	BuildTime string

	// GoVersion contains the Go runtime version
	GoVersion string
)
<commit_msg>Version bump: 0.11.8<commit_after>package command

const (
	// Version is the current Pgweb application version
	Version = "0.11.8"
)

var (
	// GitCommit contains the Git commit SHA for the binary
	GitCommit string

	// BuildTime contains the binary build time
	BuildTime string

	// GoVersion contains the Go runtime version
	GoVersion string
)
<|endoftext|>