<commit_before>/*
Copyright 2018 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 main

import (
	"fmt"
	"strings"
	"testing"
	"time"

	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
	"k8s.io/apimachinery/pkg/util/wait"

	"k8s.io/ingress-gce/pkg/annotations"
	backendconfigv1beta1 "k8s.io/ingress-gce/pkg/apis/backendconfig/v1beta1"
	"k8s.io/ingress-gce/pkg/e2e"
	"k8s.io/ingress-gce/pkg/fuzz"
)

var (
	eventPollInterval = 15 * time.Second
	eventPollTimeout  = 3 * time.Minute
)

func TestBackendConfigNegatives(t *testing.T) {
	t.Parallel()

	for _, tc := range []struct {
		desc           string
		svcAnnotations map[string]string
		backendConfig  *backendconfigv1beta1.BackendConfig
		expectedMsg    string
	}{
		{
			desc: "backend config not exist",
			svcAnnotations: map[string]string{
				annotations.BackendConfigKey: `{"default":"backendconfig-1"}`,
			},
			expectedMsg: "no BackendConfig",
		},
		{
			desc: "invalid format in backend config annotation",
			svcAnnotations: map[string]string{
				annotations.BackendConfigKey: `invalid`,
			},
			expectedMsg: fmt.Sprintf("%v", annotations.ErrBackendConfigInvalidJSON),
		},
		{
			desc: "enable both IAP and CDN in backend config",
			svcAnnotations: map[string]string{
				annotations.BackendConfigKey: `{"default":"backendconfig-1"}`,
			},
			backendConfig: fuzz.NewBackendConfigBuilder("", "backendconfig-1").
				EnableCDN(true).
				SetIAPConfig(true, "bar").
				Build(),
			expectedMsg: "is not valid",
		},
	} {
		tc := tc // Capture tc as we are running this in parallel.
		Framework.RunWithSandbox(tc.desc, t, func(t *testing.T, s *e2e.Sandbox) {
			t.Parallel()

			if tc.backendConfig != nil {
				if _, err := Framework.BackendConfigClient.CloudV1beta1().BackendConfigs(s.Namespace).Create(tc.backendConfig); err != nil {
					t.Fatalf("Error creating backend config: %v", err)
				}
				t.Logf("Backend config %s/%s created", s.Namespace, tc.backendConfig.Name)
			}

			if _, _, err := e2e.CreateEchoService(s, "service-1", tc.svcAnnotations); err != nil {
				t.Fatalf("e2e.CreateEchoService(s, service-1, %q) = _, _, %v, want _, _, nil", tc.svcAnnotations, err)
			}

			port80 := intstr.FromInt(80)
			testIng := fuzz.NewIngressBuilder("", "ingress-1", "").
				AddPath("test.com", "/", "service-1", port80).
				Build()
			testIng, err := Framework.Clientset.Extensions().Ingresses(s.Namespace).Create(testIng)
			if err != nil {
				t.Fatalf("error creating Ingress spec: %v", err)
			}
			t.Logf("Ingress %s/%s created", s.Namespace, testIng.Name)

			t.Logf("Waiting for warning event to be emitted")
			if err := wait.Poll(eventPollInterval, eventPollTimeout, func() (bool, error) {
				events, err := Framework.Clientset.CoreV1().Events(s.Namespace).List(metav1.ListOptions{})
				if err != nil {
					return false, fmt.Errorf("error in listing events: %s", err)
				}
				for _, event := range events.Items {
					if event.InvolvedObject.Kind != "Ingress" ||
						event.InvolvedObject.Name != "ingress-1" ||
						event.Type != v1.EventTypeWarning {
						continue
					}
					if strings.Contains(event.Message, tc.expectedMsg) {
						t.Logf("Warning event emitted")
						return true, nil
					}
				}
				t.Logf("No warning event is emitted yet")
				return false, nil
			}); err != nil {
				t.Fatalf("error waiting for BackendConfig warning event: %v", err)
			}

			testIng, err = Framework.Clientset.Extensions().Ingresses(s.Namespace).Get(testIng.Name, metav1.GetOptions{})
			if err != nil {
				t.Fatalf("error retrieving Ingress %q: %v", testIng.Name, err)
			}
			if len(testIng.Status.LoadBalancer.Ingress) > 0 {
				t.Fatalf("Ingress should not have an IP: %+v", testIng.Status)
			}
		})
	}
}
<commit_msg>Actually Create secret for IAP for testing<commit_after>/*
Copyright 2018 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 main

import (
	"fmt"
	"strings"
	"testing"
	"time"

	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
	"k8s.io/apimachinery/pkg/util/wait"

	"k8s.io/ingress-gce/pkg/annotations"
	backendconfigv1beta1 "k8s.io/ingress-gce/pkg/apis/backendconfig/v1beta1"
	"k8s.io/ingress-gce/pkg/e2e"
	"k8s.io/ingress-gce/pkg/fuzz"
)

var (
	eventPollInterval = 15 * time.Second
	eventPollTimeout  = 3 * time.Minute
)

func TestBackendConfigNegatives(t *testing.T) {
	t.Parallel()

	for _, tc := range []struct {
		desc           string
		svcAnnotations map[string]string
		backendConfig  *backendconfigv1beta1.BackendConfig
		secretName     string
		expectedMsg    string
	}{
		{
			desc: "backend config not exist",
			svcAnnotations: map[string]string{
				annotations.BackendConfigKey: `{"default":"backendconfig-1"}`,
			},
			expectedMsg: "no BackendConfig",
		},
		{
			desc: "invalid format in backend config annotation",
			svcAnnotations: map[string]string{
				annotations.BackendConfigKey: `invalid`,
			},
			expectedMsg: fmt.Sprintf("%v", annotations.ErrBackendConfigInvalidJSON),
		},
		{
			desc: "enable both IAP and CDN in backend config",
			svcAnnotations: map[string]string{
				annotations.BackendConfigKey: `{"default":"backendconfig-1"}`,
			},
			backendConfig: fuzz.NewBackendConfigBuilder("", "backendconfig-1").
				EnableCDN(true).
				SetIAPConfig(true, "bar").
				Build(),
			secretName:  "bar",
			expectedMsg: "iap and cdn cannot be enabled at the same time",
		},
	} {
		tc := tc // Capture tc as we are running this in parallel.
		Framework.RunWithSandbox(tc.desc, t, func(t *testing.T, s *e2e.Sandbox) {
			t.Parallel()

			if tc.backendConfig != nil {
				if _, err := Framework.BackendConfigClient.CloudV1beta1().BackendConfigs(s.Namespace).Create(tc.backendConfig); err != nil {
					t.Fatalf("Error creating backend config: %v", err)
				}
				t.Logf("Backend config %s/%s created", s.Namespace, tc.backendConfig.Name)
			}

			if tc.secretName != "" {
				if _, err := e2e.CreateSecret(s, tc.secretName,
					map[string][]byte{
						"client_id":     []byte("my-id"),
						"client_secret": []byte("my-secret"),
					}); err != nil {
					t.Fatalf("Error creating secret %q: %v", tc.secretName, err)
				}
			}

			if _, _, err := e2e.CreateEchoService(s, "service-1", tc.svcAnnotations); err != nil {
				t.Fatalf("e2e.CreateEchoService(s, service-1, %q) = _, _, %v, want _, _, nil", tc.svcAnnotations, err)
			}

			port80 := intstr.FromInt(80)
			testIng := fuzz.NewIngressBuilder("", "ingress-1", "").
				AddPath("test.com", "/", "service-1", port80).
				Build()
			testIng, err := Framework.Clientset.Extensions().Ingresses(s.Namespace).Create(testIng)
			if err != nil {
				t.Fatalf("error creating Ingress spec: %v", err)
			}
			t.Logf("Ingress %s/%s created", s.Namespace, testIng.Name)

			t.Logf("Waiting for warning event to be emitted")
			if err := wait.Poll(eventPollInterval, eventPollTimeout, func() (bool, error) {
				events, err := Framework.Clientset.CoreV1().Events(s.Namespace).List(metav1.ListOptions{})
				if err != nil {
					return false, fmt.Errorf("error in listing events: %s", err)
				}
				for _, event := range events.Items {
					if event.InvolvedObject.Kind != "Ingress" ||
						event.InvolvedObject.Name != "ingress-1" ||
						event.Type != v1.EventTypeWarning {
						continue
					}
					if strings.Contains(event.Message, tc.expectedMsg) {
						t.Logf("Warning event emitted")
						return true, nil
					}
				}
				t.Logf("No warning event is emitted yet")
				return false, nil
			}); err != nil {
				t.Fatalf("error waiting for BackendConfig warning event: %v", err)
			}

			testIng, err = Framework.Clientset.Extensions().Ingresses(s.Namespace).Get(testIng.Name, metav1.GetOptions{})
			if err != nil {
				t.Fatalf("error retrieving Ingress %q: %v", testIng.Name, err)
			}
			if len(testIng.Status.LoadBalancer.Ingress) > 0 {
				t.Fatalf("Ingress should not have an IP: %+v", testIng.Status)
			}
		})
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"
)

var (
	// I'm not sure these make sense. However they can be overridden at runtime
	// and in the configuration, so we have some flexibility.
	defaultConfigFile        = os.Getenv("SYSTEMDRIVE") + `\ProgramData\MaxMind\GeoIP.conf`
	defaultDatabaseDirectory = os.Getenv("SYSTEMDRIVE") + `\ProgramData\MaxMind\GeoIP`
)
<commit_msg>Use a GeoIPUpdate subdirectory on Windows<commit_after>package main

import (
	"os"
)

var (
	// I'm not sure these make sense. However they can be overridden at runtime
	// and in the configuration, so we have some flexibility.
	defaultConfigFile        = os.Getenv("SYSTEMDRIVE") + `\ProgramData\MaxMind\GeoIPUpdate\GeoIP.conf`
	defaultDatabaseDirectory = os.Getenv("SYSTEMDRIVE") + `\ProgramData\MaxMind\GeoIPUpdate\GeoIP`
)
<|endoftext|>


<commit_before>/*
Copyright 2018 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 upgrade

import (
	"os"

	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	flag "github.com/spf13/pflag"

	clientset "k8s.io/client-go/kubernetes"
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
	phases "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/upgrade/node"
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
	"k8s.io/kubernetes/cmd/kubeadm/app/constants"
	kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
	configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
)

// nodeOptions defines all the options exposed via flags by kubeadm upgrade node.
// Please note that this structure includes the public kubeadm config API, but only a subset of the options
// supported by this api will be exposed as a flag.
type nodeOptions struct {
	kubeConfigPath string
	kubeletVersion string
	etcdUpgrade    bool
	renewCerts     bool
	dryRun         bool
	kustomizeDir   string
}

// compile-time assert that the local data object satisfies the phases data interface.
var _ phases.Data = &nodeData{}

// nodeData defines all the runtime information used when running the kubeadm upgrade node worklow;
// this data is shared across all the phases that are included in the workflow.
type nodeData struct {
	etcdUpgrade        bool
	renewCerts         bool
	dryRun             bool
	kubeletVersion     string
	cfg                *kubeadmapi.InitConfiguration
	isControlPlaneNode bool
	client             clientset.Interface
	kustomizeDir       string
}

// NewCmdNode returns the cobra command for `kubeadm upgrade node`
func NewCmdNode() *cobra.Command {
	nodeOptions := newNodeOptions()
	nodeRunner := workflow.NewRunner()

	cmd := &cobra.Command{
		Use:   "node",
		Short: "Upgrade commands for a node in the cluster",
		RunE: func(cmd *cobra.Command, args []string) error {
			return nodeRunner.Run(args)
		},
		Args: cobra.NoArgs,
	}

	// adds flags to the node command
	// flags could be eventually inherited by the sub-commands automatically generated for phases
	addUpgradeNodeFlags(cmd.Flags(), nodeOptions)
	options.AddKustomizePodsFlag(cmd.Flags(), &nodeOptions.kustomizeDir)

	// initialize the workflow runner with the list of phases
	nodeRunner.AppendPhase(phases.NewControlPlane())
	nodeRunner.AppendPhase(phases.NewKubeletConfigPhase())

	// sets the data builder function, that will be used by the runner
	// both when running the entire workflow or single phases
	nodeRunner.SetDataInitializer(func(cmd *cobra.Command, args []string) (workflow.RunData, error) {
		return newNodeData(cmd, args, nodeOptions)
	})

	// binds the Runner to kubeadm upgrade node command by altering
	// command help, adding --skip-phases flag and by adding phases subcommands
	nodeRunner.BindToCommand(cmd)

	// upgrade node config command is subject to GA deprecation policy, so we should deprecate it
	// and keep it here for one year or three releases - the longer of the two - starting from v1.15 included
	cmd.AddCommand(NewCmdUpgradeNodeConfig())

	return cmd
}

// newNodeOptions returns a struct ready for being used for creating cmd kubeadm upgrade node flags.
func newNodeOptions() *nodeOptions {
	return &nodeOptions{
		kubeConfigPath: constants.GetKubeletKubeConfigPath(),
		dryRun:         false,
	}
}

func addUpgradeNodeFlags(flagSet *flag.FlagSet, nodeOptions *nodeOptions) {
	options.AddKubeConfigFlag(flagSet, &nodeOptions.kubeConfigPath)
	flagSet.BoolVar(&nodeOptions.dryRun, options.DryRun, nodeOptions.dryRun, "Do not change any state, just output the actions that would be performed.")
	flagSet.StringVar(&nodeOptions.kubeletVersion, options.KubeletVersion, nodeOptions.kubeletVersion, "The *desired* version for the kubelet config after the upgrade. If not specified, the KubernetesVersion from the kubeadm-config ConfigMap will be used")
	flagSet.BoolVar(&nodeOptions.renewCerts, options.CertificateRenewal, nodeOptions.renewCerts, "Perform the renewal of certificates used by component changed during upgrades.")
	flagSet.BoolVar(&nodeOptions.etcdUpgrade, options.EtcdUpgrade, nodeOptions.etcdUpgrade, "Perform the upgrade of etcd.")
}

// newNodeData returns a new nodeData struct to be used for the execution of the kubeadm upgrade node workflow.
// This func takes care of validating nodeOptions passed to the command, and then it converts
// options into the internal InitConfiguration type that is used as input all the phases in the kubeadm upgrade node workflow
func newNodeData(cmd *cobra.Command, args []string, options *nodeOptions) (*nodeData, error) {
	client, err := getClient(options.kubeConfigPath, options.dryRun)
	if err != nil {
		return nil, errors.Wrapf(err, "couldn't create a Kubernetes client from file %q", options.kubeConfigPath)
	}

	// isControlPlane checks if a node is a control-plane node by looking up
	// the kube-apiserver manifest file
	isControlPlaneNode := true
	filepath := kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.KubeAPIServer, kubeadmconstants.GetStaticPodDirectory())
	if _, err := os.Stat(filepath); os.IsNotExist(err) {
		isControlPlaneNode = false
	}

	// Fetches the cluster configuration
	// NB in case of control-plane node, we are reading all the info for the node; in case of NOT control-plane node
	//    (worker node), we are not reading local API address and the CRI socket from the node object
	cfg, err := configutil.FetchInitConfigurationFromCluster(client, os.Stdout, "upgrade", !isControlPlaneNode)
	if err != nil {
		return nil, errors.Wrap(err, "unable to fetch the kubeadm-config ConfigMap")
	}

	return &nodeData{
		etcdUpgrade:        options.etcdUpgrade,
		renewCerts:         options.renewCerts,
		dryRun:             options.dryRun,
		kubeletVersion:     options.kubeletVersion,
		cfg:                cfg,
		client:             client,
		isControlPlaneNode: isControlPlaneNode,
		kustomizeDir:       options.kustomizeDir,
	}, nil
}

// DryRun returns the dryRun flag.
func (d *nodeData) DryRun() bool {
	return d.dryRun
}

// EtcdUpgrade returns the etcdUpgrade flag.
func (d *nodeData) EtcdUpgrade() bool {
	return d.etcdUpgrade
}

// RenewCerts returns the renewCerts flag.
func (d *nodeData) RenewCerts() bool {
	return d.renewCerts
}

// KubeletVersion returns the kubeletVersion flag.
func (d *nodeData) KubeletVersion() string {
	return d.kubeletVersion
}

// Cfg returns initConfiguration.
func (d *nodeData) Cfg() *kubeadmapi.InitConfiguration {
	return d.cfg
}

// IsControlPlaneNode returns the isControlPlaneNode flag.
func (d *nodeData) IsControlPlaneNode() bool {
	return d.isControlPlaneNode
}

// Client returns a Kubernetes client to be used by kubeadm.
func (d *nodeData) Client() clientset.Interface {
	return d.client
}

// KustomizeDir returns the folder where kustomize patches for static pod manifest are stored
func (d *nodeData) KustomizeDir() string {
	return d.kustomizeDir
}

// NewCmdUpgradeNodeConfig returns the cobra.Command for downloading the new/upgrading the kubelet configuration from the kubelet-config-1.X
// ConfigMap in the cluster
// TODO: to remove when 1.18 is released
func NewCmdUpgradeNodeConfig() *cobra.Command {
	nodeOptions := newNodeOptions()
	nodeRunner := workflow.NewRunner()

	cmd := &cobra.Command{
		Use:        "config",
		Short:      "Download the kubelet configuration from the cluster ConfigMap kubelet-config-1.X, where X is the minor version of the kubelet",
		Deprecated: "use \"kubeadm upgrade node\" instead",
		RunE: func(cmd *cobra.Command, args []string) error {
			// This is required for preserving the old behavior of `kubeadm upgrade node config`.
			// The new implementation exposed as a phase under `kubeadm upgrade node` infers the target
			// kubelet config version from the kubeadm-config ConfigMap
			if len(nodeOptions.kubeletVersion) == 0 {
				return errors.New("the --kubelet-version argument is required")
			}

			return nodeRunner.Run(args)
		},
	}

	// adds flags to the node command
	addUpgradeNodeFlags(cmd.Flags(), nodeOptions)

	// initialize the workflow runner with the list of phases
	nodeRunner.AppendPhase(phases.NewKubeletConfigPhase())

	// sets the data builder function, that will be used by the runner
	// both when running the entire workflow or single phases
	nodeRunner.SetDataInitializer(func(cmd *cobra.Command, args []string) (workflow.RunData, error) {
		return newNodeData(cmd, args, nodeOptions)
	})

	return cmd
}
<commit_msg>kubeadm: renew certificates on "upgrade node" by default<commit_after>/*
Copyright 2018 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 upgrade

import (
	"os"

	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	flag "github.com/spf13/pflag"

	clientset "k8s.io/client-go/kubernetes"
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
	phases "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/upgrade/node"
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
	"k8s.io/kubernetes/cmd/kubeadm/app/constants"
	kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
	configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
)

// nodeOptions defines all the options exposed via flags by kubeadm upgrade node.
// Please note that this structure includes the public kubeadm config API, but only a subset of the options
// supported by this api will be exposed as a flag.
type nodeOptions struct {
	kubeConfigPath string
	kubeletVersion string
	etcdUpgrade    bool
	renewCerts     bool
	dryRun         bool
	kustomizeDir   string
}

// compile-time assert that the local data object satisfies the phases data interface.
var _ phases.Data = &nodeData{}

// nodeData defines all the runtime information used when running the kubeadm upgrade node worklow;
// this data is shared across all the phases that are included in the workflow.
type nodeData struct {
	etcdUpgrade        bool
	renewCerts         bool
	dryRun             bool
	kubeletVersion     string
	cfg                *kubeadmapi.InitConfiguration
	isControlPlaneNode bool
	client             clientset.Interface
	kustomizeDir       string
}

// NewCmdNode returns the cobra command for `kubeadm upgrade node`
func NewCmdNode() *cobra.Command {
	nodeOptions := newNodeOptions()
	nodeRunner := workflow.NewRunner()

	cmd := &cobra.Command{
		Use:   "node",
		Short: "Upgrade commands for a node in the cluster",
		RunE: func(cmd *cobra.Command, args []string) error {
			return nodeRunner.Run(args)
		},
		Args: cobra.NoArgs,
	}

	// adds flags to the node command
	// flags could be eventually inherited by the sub-commands automatically generated for phases
	addUpgradeNodeFlags(cmd.Flags(), nodeOptions)
	options.AddKustomizePodsFlag(cmd.Flags(), &nodeOptions.kustomizeDir)

	// initialize the workflow runner with the list of phases
	nodeRunner.AppendPhase(phases.NewControlPlane())
	nodeRunner.AppendPhase(phases.NewKubeletConfigPhase())

	// sets the data builder function, that will be used by the runner
	// both when running the entire workflow or single phases
	nodeRunner.SetDataInitializer(func(cmd *cobra.Command, args []string) (workflow.RunData, error) {
		return newNodeData(cmd, args, nodeOptions)
	})

	// binds the Runner to kubeadm upgrade node command by altering
	// command help, adding --skip-phases flag and by adding phases subcommands
	nodeRunner.BindToCommand(cmd)

	// upgrade node config command is subject to GA deprecation policy, so we should deprecate it
	// and keep it here for one year or three releases - the longer of the two - starting from v1.15 included
	cmd.AddCommand(NewCmdUpgradeNodeConfig())

	return cmd
}

// newNodeOptions returns a struct ready for being used for creating cmd kubeadm upgrade node flags.
func newNodeOptions() *nodeOptions {
	return &nodeOptions{
		kubeConfigPath: constants.GetKubeletKubeConfigPath(),
		dryRun:         false,
		renewCerts:     true,
	}
}

func addUpgradeNodeFlags(flagSet *flag.FlagSet, nodeOptions *nodeOptions) {
	options.AddKubeConfigFlag(flagSet, &nodeOptions.kubeConfigPath)
	flagSet.BoolVar(&nodeOptions.dryRun, options.DryRun, nodeOptions.dryRun, "Do not change any state, just output the actions that would be performed.")
	flagSet.StringVar(&nodeOptions.kubeletVersion, options.KubeletVersion, nodeOptions.kubeletVersion, "The *desired* version for the kubelet config after the upgrade. If not specified, the KubernetesVersion from the kubeadm-config ConfigMap will be used")
	flagSet.BoolVar(&nodeOptions.renewCerts, options.CertificateRenewal, nodeOptions.renewCerts, "Perform the renewal of certificates used by component changed during upgrades.")
	flagSet.BoolVar(&nodeOptions.etcdUpgrade, options.EtcdUpgrade, nodeOptions.etcdUpgrade, "Perform the upgrade of etcd.")
}

// newNodeData returns a new nodeData struct to be used for the execution of the kubeadm upgrade node workflow.
// This func takes care of validating nodeOptions passed to the command, and then it converts
// options into the internal InitConfiguration type that is used as input all the phases in the kubeadm upgrade node workflow
func newNodeData(cmd *cobra.Command, args []string, options *nodeOptions) (*nodeData, error) {
	client, err := getClient(options.kubeConfigPath, options.dryRun)
	if err != nil {
		return nil, errors.Wrapf(err, "couldn't create a Kubernetes client from file %q", options.kubeConfigPath)
	}

	// isControlPlane checks if a node is a control-plane node by looking up
	// the kube-apiserver manifest file
	isControlPlaneNode := true
	filepath := kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.KubeAPIServer, kubeadmconstants.GetStaticPodDirectory())
	if _, err := os.Stat(filepath); os.IsNotExist(err) {
		isControlPlaneNode = false
	}

	// Fetches the cluster configuration
	// NB in case of control-plane node, we are reading all the info for the node; in case of NOT control-plane node
	//    (worker node), we are not reading local API address and the CRI socket from the node object
	cfg, err := configutil.FetchInitConfigurationFromCluster(client, os.Stdout, "upgrade", !isControlPlaneNode)
	if err != nil {
		return nil, errors.Wrap(err, "unable to fetch the kubeadm-config ConfigMap")
	}

	return &nodeData{
		etcdUpgrade:        options.etcdUpgrade,
		renewCerts:         options.renewCerts,
		dryRun:             options.dryRun,
		kubeletVersion:     options.kubeletVersion,
		cfg:                cfg,
		client:             client,
		isControlPlaneNode: isControlPlaneNode,
		kustomizeDir:       options.kustomizeDir,
	}, nil
}

// DryRun returns the dryRun flag.
func (d *nodeData) DryRun() bool {
	return d.dryRun
}

// EtcdUpgrade returns the etcdUpgrade flag.
func (d *nodeData) EtcdUpgrade() bool {
	return d.etcdUpgrade
}

// RenewCerts returns the renewCerts flag.
func (d *nodeData) RenewCerts() bool {
	return d.renewCerts
}

// KubeletVersion returns the kubeletVersion flag.
func (d *nodeData) KubeletVersion() string {
	return d.kubeletVersion
}

// Cfg returns initConfiguration.
func (d *nodeData) Cfg() *kubeadmapi.InitConfiguration {
	return d.cfg
}

// IsControlPlaneNode returns the isControlPlaneNode flag.
func (d *nodeData) IsControlPlaneNode() bool {
	return d.isControlPlaneNode
}

// Client returns a Kubernetes client to be used by kubeadm.
func (d *nodeData) Client() clientset.Interface {
	return d.client
}

// KustomizeDir returns the folder where kustomize patches for static pod manifest are stored
func (d *nodeData) KustomizeDir() string {
	return d.kustomizeDir
}

// NewCmdUpgradeNodeConfig returns the cobra.Command for downloading the new/upgrading the kubelet configuration from the kubelet-config-1.X
// ConfigMap in the cluster
// TODO: to remove when 1.18 is released
func NewCmdUpgradeNodeConfig() *cobra.Command {
	nodeOptions := newNodeOptions()
	nodeRunner := workflow.NewRunner()

	cmd := &cobra.Command{
		Use:        "config",
		Short:      "Download the kubelet configuration from the cluster ConfigMap kubelet-config-1.X, where X is the minor version of the kubelet",
		Deprecated: "use \"kubeadm upgrade node\" instead",
		RunE: func(cmd *cobra.Command, args []string) error {
			// This is required for preserving the old behavior of `kubeadm upgrade node config`.
			// The new implementation exposed as a phase under `kubeadm upgrade node` infers the target
			// kubelet config version from the kubeadm-config ConfigMap
			if len(nodeOptions.kubeletVersion) == 0 {
				return errors.New("the --kubelet-version argument is required")
			}

			return nodeRunner.Run(args)
		},
	}

	// adds flags to the node command
	addUpgradeNodeFlags(cmd.Flags(), nodeOptions)

	// initialize the workflow runner with the list of phases
	nodeRunner.AppendPhase(phases.NewKubeletConfigPhase())

	// sets the data builder function, that will be used by the runner
	// both when running the entire workflow or single phases
	nodeRunner.SetDataInitializer(func(cmd *cobra.Command, args []string) (workflow.RunData, error) {
		return newNodeData(cmd, args, nodeOptions)
	})

	return cmd
}
<|endoftext|>


<commit_before>/*
Copyright 2019 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 model

import (
	"fmt"
	"strings"

	"k8s.io/kops/nodeup/pkg/distros"
	"k8s.io/kops/pkg/apis/kops/util"
	"k8s.io/kops/pkg/systemd"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/nodeup/nodetasks"

	"k8s.io/klog"
)

// LogrotateBuilder installs logrotate.d and configures log rotation for kubernetes logs
type LogrotateBuilder struct {
	*NodeupModelContext
}

var _ fi.ModelBuilder = &LogrotateBuilder{}

// Build is responsible for configuring logrotate
func (b *LogrotateBuilder) Build(c *fi.ModelBuilderContext) error {

	switch b.Distribution {
	case distros.DistributionContainerOS:
		klog.Infof("Detected ContainerOS; won't install logrotate")
		return nil
	case distros.DistributionCoreOS:
		klog.Infof("Detected CoreOS; won't install logrotate")
	case distros.DistributionFlatcar:
		klog.Infof("Detected Flatcar; won't install logrotate")
	default:
		c.AddTask(&nodetasks.Package{Name: "logrotate"})
	}

	k8sVersion, err := util.ParseKubernetesVersion(b.Cluster.Spec.KubernetesVersion)
	if err != nil || k8sVersion == nil {
		return fmt.Errorf("unable to parse KubernetesVersion %q", b.Cluster.Spec.KubernetesVersion)
	}

	if k8sVersion.Major == 1 && k8sVersion.Minor < 6 {
		// In version 1.6, we move log rotation to docker, but prior to that we need a logrotate rule
		b.addLogRotate(c, "docker-containers", "/var/lib/docker/containers/*/*-json.log", logRotateOptions{MaxSize: "10M"})
	}

	b.addLogRotate(c, "docker", "/var/log/docker.log", logRotateOptions{})
	b.addLogRotate(c, "kube-addons", "/var/log/kube-addons.log", logRotateOptions{})
	b.addLogRotate(c, "kube-apiserver", "/var/log/kube-apiserver.log", logRotateOptions{})
	b.addLogRotate(c, "kube-controller-manager", "/var/log/kube-controller-manager.log", logRotateOptions{})
	b.addLogRotate(c, "kube-proxy", "/var/log/kube-proxy.log", logRotateOptions{})
	b.addLogRotate(c, "kube-scheduler", "/var/log/kube-scheduler.log", logRotateOptions{})
	b.addLogRotate(c, "kubelet", "/var/log/kubelet.log", logRotateOptions{})

	if err := b.addLogrotateService(c); err != nil {
		return err
	}

	// Add timer to run hourly.
	{
		unit := &systemd.Manifest{}
		unit.Set("Unit", "Description", "Hourly Log Rotation")
		unit.Set("Timer", "OnCalendar", "hourly")

		service := &nodetasks.Service{
			Name:       "logrotate.timer", // Override (by name) any existing timer
			Definition: s(unit.Render()),
		}

		service.InitDefaults()

		c.AddTask(service)
	}

	return nil
}

// addLogrotateService creates a logrotate systemd task to act as target for the timer, if one is needed
func (b *LogrotateBuilder) addLogrotateService(c *fi.ModelBuilderContext) error {
	switch b.Distribution {
	case distros.DistributionCoreOS, distros.DistributionFlatcar, distros.DistributionContainerOS:
		// logrotate service already exists
		return nil
	}

	manifest := &systemd.Manifest{}
	manifest.Set("Unit", "Description", "Rotate and Compress System Logs")
	manifest.Set("Service", "ExecStart", "/usr/sbin/logrotate /etc/logrotate.conf")

	service := &nodetasks.Service{
		Name:       "logrotate.service",
		Definition: s(manifest.Render()),
	}
	service.InitDefaults()
	c.AddTask(service)

	return nil
}

type logRotateOptions struct {
	MaxSize    string
	DateFormat string
}

func (b *LogrotateBuilder) addLogRotate(c *fi.ModelBuilderContext, name, path string, options logRotateOptions) {
	if options.MaxSize == "" {
		options.MaxSize = "100M"
	}

	// CoreOS sets "dateext" options, and maxsize-based rotation will fail if
	// the file has been previously rotated on the same calendar date.
	if b.Distribution == distros.DistributionCoreOS {
		options.DateFormat = "-%Y%m%d-%s"
	}

	// Flatcar sets "dateext" options, and maxsize-based rotation will fail if
	// the file has been previously rotated on the same calendar date.
	if b.Distribution == distros.DistributionFlatcar {
		options.DateFormat = "-%Y%m%d-%s"
	}

	lines := []string{
		path + "{",
		"  rotate 5",
		"  copytruncate",
		"  missingok",
		"  notifempty",
		"  delaycompress",
		"  maxsize " + options.MaxSize,
	}

	if options.DateFormat != "" {
		lines = append(lines, "  dateformat "+options.DateFormat)
	}

	lines = append(
		lines,
		"  daily",
		"  create 0644 root root",
		"}",
	)

	contents := strings.Join(lines, "\n") + "\n"

	c.AddTask(&nodetasks.File{
		Path:     "/etc/logrotate.d/" + name,
		Contents: fi.NewStringResource(contents),
		Type:     nodetasks.FileType_File,
		Mode:     s("0644"),
	})
}
<commit_msg>Add logrotate for etcd/etcd-events.log<commit_after>/*
Copyright 2019 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 model

import (
	"fmt"
	"strings"

	"k8s.io/kops/nodeup/pkg/distros"
	"k8s.io/kops/pkg/apis/kops/util"
	"k8s.io/kops/pkg/systemd"
	"k8s.io/kops/upup/pkg/fi"
	"k8s.io/kops/upup/pkg/fi/nodeup/nodetasks"

	"k8s.io/klog"
)

// LogrotateBuilder installs logrotate.d and configures log rotation for kubernetes logs
type LogrotateBuilder struct {
	*NodeupModelContext
}

var _ fi.ModelBuilder = &LogrotateBuilder{}

// Build is responsible for configuring logrotate
func (b *LogrotateBuilder) Build(c *fi.ModelBuilderContext) error {

	switch b.Distribution {
	case distros.DistributionContainerOS:
		klog.Infof("Detected ContainerOS; won't install logrotate")
		return nil
	case distros.DistributionCoreOS:
		klog.Infof("Detected CoreOS; won't install logrotate")
	case distros.DistributionFlatcar:
		klog.Infof("Detected Flatcar; won't install logrotate")
	default:
		c.AddTask(&nodetasks.Package{Name: "logrotate"})
	}

	k8sVersion, err := util.ParseKubernetesVersion(b.Cluster.Spec.KubernetesVersion)
	if err != nil || k8sVersion == nil {
		return fmt.Errorf("unable to parse KubernetesVersion %q", b.Cluster.Spec.KubernetesVersion)
	}

	if k8sVersion.Major == 1 && k8sVersion.Minor < 6 {
		// In version 1.6, we move log rotation to docker, but prior to that we need a logrotate rule
		b.addLogRotate(c, "docker-containers", "/var/lib/docker/containers/*/*-json.log", logRotateOptions{MaxSize: "10M"})
	}

	b.addLogRotate(c, "docker", "/var/log/docker.log", logRotateOptions{})
	b.addLogRotate(c, "kube-addons", "/var/log/kube-addons.log", logRotateOptions{})
	b.addLogRotate(c, "kube-apiserver", "/var/log/kube-apiserver.log", logRotateOptions{})
	b.addLogRotate(c, "kube-controller-manager", "/var/log/kube-controller-manager.log", logRotateOptions{})
	b.addLogRotate(c, "kube-proxy", "/var/log/kube-proxy.log", logRotateOptions{})
	b.addLogRotate(c, "kube-scheduler", "/var/log/kube-scheduler.log", logRotateOptions{})
	b.addLogRotate(c, "kubelet", "/var/log/kubelet.log", logRotateOptions{})
	b.addLogRotate(c, "etcd", "/var/log/etcd.log", logRotateOptions{})
	b.addLogRotate(c, "etcd-events", "/var/log/etcd-events.log", logRotateOptions{})

	if err := b.addLogrotateService(c); err != nil {
		return err
	}

	// Add timer to run hourly.
	{
		unit := &systemd.Manifest{}
		unit.Set("Unit", "Description", "Hourly Log Rotation")
		unit.Set("Timer", "OnCalendar", "hourly")

		service := &nodetasks.Service{
			Name:       "logrotate.timer", // Override (by name) any existing timer
			Definition: s(unit.Render()),
		}

		service.InitDefaults()

		c.AddTask(service)
	}

	return nil
}

// addLogrotateService creates a logrotate systemd task to act as target for the timer, if one is needed
func (b *LogrotateBuilder) addLogrotateService(c *fi.ModelBuilderContext) error {
	switch b.Distribution {
	case distros.DistributionCoreOS, distros.DistributionFlatcar, distros.DistributionContainerOS:
		// logrotate service already exists
		return nil
	}

	manifest := &systemd.Manifest{}
	manifest.Set("Unit", "Description", "Rotate and Compress System Logs")
	manifest.Set("Service", "ExecStart", "/usr/sbin/logrotate /etc/logrotate.conf")

	service := &nodetasks.Service{
		Name:       "logrotate.service",
		Definition: s(manifest.Render()),
	}
	service.InitDefaults()
	c.AddTask(service)

	return nil
}

type logRotateOptions struct {
	MaxSize    string
	DateFormat string
}

func (b *LogrotateBuilder) addLogRotate(c *fi.ModelBuilderContext, name, path string, options logRotateOptions) {
	if options.MaxSize == "" {
		options.MaxSize = "100M"
	}

	// CoreOS sets "dateext" options, and maxsize-based rotation will fail if
	// the file has been previously rotated on the same calendar date.
	if b.Distribution == distros.DistributionCoreOS {
		options.DateFormat = "-%Y%m%d-%s"
	}

	// Flatcar sets "dateext" options, and maxsize-based rotation will fail if
	// the file has been previously rotated on the same calendar date.
	if b.Distribution == distros.DistributionFlatcar {
		options.DateFormat = "-%Y%m%d-%s"
	}

	lines := []string{
		path + "{",
		"  rotate 5",
		"  copytruncate",
		"  missingok",
		"  notifempty",
		"  delaycompress",
		"  maxsize " + options.MaxSize,
	}

	if options.DateFormat != "" {
		lines = append(lines, "  dateformat "+options.DateFormat)
	}

	lines = append(
		lines,
		"  daily",
		"  create 0644 root root",
		"}",
	)

	contents := strings.Join(lines, "\n") + "\n"

	c.AddTask(&nodetasks.File{
		Path:     "/etc/logrotate.d/" + name,
		Contents: fi.NewStringResource(contents),
		Type:     nodetasks.FileType_File,
		Mode:     s("0644"),
	})
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"net"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"syscall"
	"time"

	pb "github.com/viru/berrybot/proto"

	log "github.com/Sirupsen/logrus"
	"github.com/kidoman/embd"
	_ "github.com/kidoman/embd/host/rpi" // This loads the RPi driver
	"google.golang.org/grpc"
)

// server is used to implement hellowrld.GreeterServer.
type server struct {
	front, rear *echo
	driver      driver
	shutdown    bool
}

type echo struct {
	name       string
	echo       embd.DigitalPin
	trig       embd.DigitalPin
	quit, done chan bool
	dist       int64
	last       time.Time
}

func newEcho(name string, trigPin, echoPin int) (*echo, error) {
	var e echo
	e.name = name
	e.quit = make(chan bool)
	e.done = make(chan bool)
	var err error
	e.trig, err = embd.NewDigitalPin(trigPin)
	if err != nil {
		return nil, fmt.Errorf("can't init trigger pin: %v", err)
	}
	e.echo, err = embd.NewDigitalPin(echoPin)
	if err != nil {
		return nil, fmt.Errorf("can't init echo pin: %v", err)
	}

	// Set direction.
	if err := e.trig.SetDirection(embd.Out); err != nil {
		return nil, fmt.Errorf("can't set trigger direction: %v", err)
	}
	if err := e.echo.SetDirection(embd.In); err != nil {
		return nil, fmt.Errorf("can't set echo direction: %v", err)
	}
	return &e, nil
}

func (e *echo) runDistancer() {
	if err := e.trig.Write(embd.Low); err != nil {
		log.Warnf("can't set trigger to low: %v", err)
	}
	time.Sleep(time.Second * 1)
	tick := time.NewTicker(time.Millisecond * 500)
	defer tick.Stop()
	for {
		select {
		case <-e.quit:
			e.done <- true
			return
		case <-tick.C:
			log.Infof("%s: measuring...", e.name)
			if err := e.trig.Write(embd.High); err != nil {
				log.Warnf("can't set trigger to high: %v", err)
			}
			time.Sleep(time.Microsecond * 10)
			if err := e.trig.Write(embd.Low); err != nil {
				log.Warnf("can't set trigger to low: %v", err)
			}
			dur, err := e.echo.TimePulse(embd.High)
			if err != nil {
				log.Warnf("can't time pulse: %v", err)
			}
			log.Infof("%s: distance: %dcm", e.name, dur.Nanoseconds()/1000*34/1000/2)
			e.dist = dur.Nanoseconds() / 1000 * 34 / 1000 / 2
		}
	}
}

func (e *echo) close() {
	e.quit <- true
	<-e.done
	e.echo.Close()
	e.trig.Close()
}

type driver struct {
	left, right *engine
	last        time.Time
}

func (d *driver) safetyStop() {
	ticker := time.NewTicker(time.Second)
	for range ticker.C {
		if d.last.Add(time.Second).Before(time.Now()) {
			log.Warn("Stopping driver!")
			d.stop()
		}
	}
}

func (d *driver) stop() {
	d.left.pwr.Write(embd.Low)
	d.right.pwr.Write(embd.Low)
	log.Info("driver STOP")
}

func (d *driver) forward() {
	d.left.pwr.Write(embd.High)
	d.left.fwd.Write(embd.High)
	d.right.pwr.Write(embd.High)
	d.right.fwd.Write(embd.High)
	d.last = time.Now()
	log.Info("driver FWD")
}

func (d *driver) backward() {
	d.left.pwr.Write(embd.High)
	d.left.fwd.Write(embd.Low)
	d.right.pwr.Write(embd.High)
	d.right.fwd.Write(embd.Low)
	d.last = time.Now()
	// log.Info("driver BACK")
}

const (
	safeStraightDist = 20
	safeTurningDist  = 10
)

func (s *server) drive(dir *pb.Direction) {
	switch {
	case dir.Dy > -5 && dir.Dy < 5 && dir.Dx > -5 && dir.Dx < 5:
		// Full stop.
		s.driver.stop()
	case dir.Dy > 5 && dir.Dx > -5 && dir.Dx < 5:
		// Forward.
		s.front.measure()
		if s.front.dist < safeStraightDist {
			s.driver.stop()
			return
		}
		s.driver.forward()
	case dir.Dy < -5 && dir.Dx > -5 && dir.Dx < 5:
		// Backward.
		s.rear.measure()
		if s.rear.dist < safeStraightDist {
			s.driver.stop()
			return
		}
		s.driver.backward()

	case dir.Dx > 5 && dir.Dy > -5 && dir.Dy < 5:
		// Sharp right.
		s.driver.left.pwr.Write(embd.High)
		s.driver.left.fwd.Write(embd.High)
		s.driver.right.pwr.Write(embd.High)
		s.driver.right.fwd.Write(embd.Low)
		log.Info("driver TURN RIGHT")
	case dir.Dx < -5 && dir.Dy > -5 && dir.Dy < 5:
		// Sharp left.
		s.driver.left.pwr.Write(embd.High)
		s.driver.left.fwd.Write(embd.Low)
		s.driver.right.pwr.Write(embd.High)
		s.driver.right.fwd.Write(embd.High)
		log.Info("driver TURN LEFT")
	case dir.Dx > 5 && dir.Dy > 5:
		// Forward + right.
		s.driver.left.pwr.Write(embd.High)
		s.driver.left.fwd.Write(embd.High)
		s.driver.right.pwr.Write(embd.Low)
		s.driver.right.fwd.Write(embd.High)
		log.Info("driver FWD RIGHT")
	case dir.Dx < -5 && dir.Dy > 5:
		// Forward + left.
		s.driver.left.pwr.Write(embd.Low)
		s.driver.left.fwd.Write(embd.High)
		s.driver.right.pwr.Write(embd.High)
		s.driver.right.fwd.Write(embd.High)
		log.Info("driver FWD LEFT")
	case dir.Dx > 5 && dir.Dy < -5:
		// Backward + right.
		s.driver.left.pwr.Write(embd.High)
		s.driver.left.fwd.Write(embd.Low)
		s.driver.right.pwr.Write(embd.Low)
		s.driver.right.fwd.Write(embd.Low)
		log.Info("driver BACK RIGHT")
	case dir.Dx < -5 && dir.Dy < -5:
		// Backward + left.
		s.driver.left.pwr.Write(embd.Low)
		s.driver.left.fwd.Write(embd.Low)
		s.driver.right.pwr.Write(embd.High)
		s.driver.right.fwd.Write(embd.Low)
		log.Info("driver BACK LEFT")
	}
}

type engine struct {
	fwd, pwr embd.DigitalPin
}

func newEngine(pwrPin, fwdPin int) (*engine, error) {
	var e engine
	var err error
	e.pwr, err = embd.NewDigitalPin(pwrPin)
	if err != nil {
		return nil, fmt.Errorf("can't init power pin: %v", err)
	}
	e.fwd, err = embd.NewDigitalPin(fwdPin)
	if err != nil {
		return nil, fmt.Errorf("can't init forward pin: %v", err)
	}

	// Set direction.
	if err := e.pwr.SetDirection(embd.Out); err != nil {
		return nil, fmt.Errorf("can't set power direction: %v", err)
	}
	if err := e.fwd.SetDirection(embd.Out); err != nil {
		return nil, fmt.Errorf("can't set forward direction: %v", err)
	}
	return &e, nil
}

func (e *engine) close() {
	e.pwr.Close()
	e.fwd.Close()
}

const (
	sensorUnknown = iota
	sensorFront
	sensorRear
)

func (s *server) Drive(stream pb.Driver_DriveServer) error {
	waitc := make(chan struct{})
	go func() {
		for {
			d, err := stream.Recv()
			if err != nil {
				log.Warnf("ERR from client: %v", err)
				close(waitc)
				return
			}
			// log.WithFields(log.Fields{
			// 	"dx": d.Dx,
			// 	"dy": d.Dy,
			// }).Info("Direction")
			s.drive(d)
		}
	}()

	for {
		select {
		case <-time.After(time.Minute):
			if err := stream.Send(&pb.Telemetry{Speed: 1, DistFront: int32(s.front.dist), DistRear: int32(s.rear.dist)}); err != nil {
				log.Errorf("can't send telemetry: %v", err)
				return err
			}
			log.Info("Sending telemetry!")
		case <-waitc:
			log.Info("got ERR from client, closing sending loop")
			return nil
		}
	}
}

var grpcPort = flag.String("grpc-port", "31337", "gRPC listen port")

func main() {
	flag.Parse()

	go http.ListenAndServe(":9191", nil)

	// Initialize GPIO.
	var err error
	if err = embd.InitGPIO(); err != nil {
		log.Fatalf("Can't init GPIO: %v", err)
	}
	defer embd.CloseGPIO()
	front, err := newEcho("front", 9, 10)
	if err != nil {
		log.Fatalf("Can't init front echo: %v", err)
	}
	defer front.close()
	rear, err := newEcho("rear", 19, 20)
	if err != nil {
		log.Fatalf("Can't init rear echo: %v", err)
	}
	defer rear.close()
	go front.runDistancer()
	go rear.runDistancer()

	left, err := newEngine(23, 4)
	if err != nil {
		log.Fatalf("Can't init left engine: %v", err)
	}
	defer left.close()
	right, err := newEngine(24, 17)
	if err != nil {
		log.Fatalf("Can't init right engine: %v", err)
	}
	defer right.close()

	// Listen for GRPC connections.
	lis, err := net.Listen("tcp", ":"+*grpcPort)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	defer lis.Close()

	drv := driver{left: left, right: right}
	go drv.safetyStop()

	srv := server{front: front, rear: rear, driver: drv}
	s := grpc.NewServer()
	pb.RegisterDriverServer(s, &srv)

	// Open broadcast connection.
	bcast, err := net.ListenPacket("udp", ":0")
	if err != nil {
		log.Fatal(err)
	}
	defer bcast.Close()

	broadcastAddr := "255.255.255.255:8032"
	dst, err := net.ResolveUDPAddr("udp", broadcastAddr)
	if err != nil {
		log.Fatal(err)
	}

	go func() {
		log.Infof("Starting to broadcast our port %s on %s", *grpcPort, broadcastAddr)
		for {
			if _, err := bcast.WriteTo([]byte(*grpcPort), dst); err != nil {
				log.Warn(err)
			}
			time.Sleep(time.Second)
		}
	}()

	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGTERM, syscall.SIGINT)
	go func() {
		sig := <-c
		log.Infof("Got %s, trying to shutdown gracefully", sig.String())
		srv.shutdown = true
		front.close()
		rear.close()
		left.close()
		right.close()
		embd.CloseGPIO()
		lis.Close()
		bcast.Close()
		os.Exit(0)
	}()

	// Start serving GRPC.
	log.Fatal(s.Serve(lis))
}
<commit_msg>Refactor driver turns<commit_after>package main

import (
	"flag"
	"fmt"
	"net"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"

	pb "github.com/viru/berrybot/proto"

	log "github.com/Sirupsen/logrus"
	"github.com/kidoman/embd"
	_ "github.com/kidoman/embd/host/rpi" // This loads the RPi driver
	"google.golang.org/grpc"
)

// server is used to implement hellowrld.GreeterServer.
type server struct {
	front, rear *echo
	driver      *driver
}

type echo struct {
	name       string
	echo       embd.DigitalPin
	trig       embd.DigitalPin
	quit, done chan bool
	dist       int64
	last       time.Time
	enabled    bool
}

func newEcho(name string, trigPin, echoPin int) (*echo, error) {
	var e echo
	e.name = name
	e.quit = make(chan bool)
	e.done = make(chan bool)
	var err error
	e.trig, err = embd.NewDigitalPin(trigPin)
	if err != nil {
		return nil, fmt.Errorf("can't init trigger pin: %v", err)
	}
	e.echo, err = embd.NewDigitalPin(echoPin)
	if err != nil {
		return nil, fmt.Errorf("can't init echo pin: %v", err)
	}

	// Set direction.
	if err := e.trig.SetDirection(embd.Out); err != nil {
		return nil, fmt.Errorf("can't set trigger direction: %v", err)
	}
	if err := e.echo.SetDirection(embd.In); err != nil {
		return nil, fmt.Errorf("can't set echo direction: %v", err)
	}
	return &e, nil
}

func (e *echo) runDistancer() {
	if err := e.trig.Write(embd.Low); err != nil {
		log.Warnf("can't set trigger to low: %v", err)
	}
	time.Sleep(time.Second * 1)
	tick := time.NewTicker(time.Millisecond * 500)
	defer tick.Stop()
	for {
		select {
		case <-e.quit:
			e.done <- true
			return
		case <-tick.C:
			if !e.enabled {
				continue
			}
			log.Infof("%s: measuring...", e.name)
			if err := e.trig.Write(embd.High); err != nil {
				log.Warnf("can't set trigger to high: %v", err)
			}
			time.Sleep(time.Microsecond * 10)
			if err := e.trig.Write(embd.Low); err != nil {
				log.Warnf("can't set trigger to low: %v", err)
			}
			dur, err := e.echo.TimePulse(embd.High)
			if err != nil {
				log.Warnf("can't time pulse: %v", err)
			}
			log.Infof("%s: distance: %dcm", e.name, dur.Nanoseconds()/1000*34/1000/2)
			e.dist = dur.Nanoseconds() / 1000 * 34 / 1000 / 2
		}
	}
}

func (e *echo) close() {
	e.quit <- true
	<-e.done
	e.echo.Close()
	e.trig.Close()
}

type driver struct {
	left, right *engine
	mu          sync.Mutex
	moving      bool
	last        time.Time
}

func (d *driver) safetyStop() {
	ticker := time.NewTicker(time.Second)
	for range ticker.C {
		d.mu.Lock()
		if d.moving && d.last.Add(time.Second).Before(time.Now()) {
			d.mu.Unlock()
			d.stop()
			log.Warn("Emergency stop!")
			continue
		}
		d.mu.Unlock()
	}
}

func (d *driver) setMoving(moving bool) {
	d.mu.Lock()
	d.last = time.Now()
	d.moving = moving
	d.mu.Unlock()
}

func (d *driver) stop() {
	d.left.pwr.Write(embd.Low)
	d.right.pwr.Write(embd.Low)
	d.setMoving(false)
}

func (d *driver) forward() {
	d.left.pwr.Write(embd.High)
	d.left.fwd.Write(embd.High)
	d.right.pwr.Write(embd.High)
	d.right.fwd.Write(embd.High)
	d.setMoving(true)
}

func (d *driver) backward() {
	d.left.pwr.Write(embd.High)
	d.left.fwd.Write(embd.Low)
	d.right.pwr.Write(embd.High)
	d.right.fwd.Write(embd.Low)
	d.setMoving(true)
}

func (d *driver) sharpRight() {
	d.left.pwr.Write(embd.High)
	d.left.fwd.Write(embd.High)
	d.right.pwr.Write(embd.High)
	d.right.fwd.Write(embd.Low)
	d.setMoving(true)
}

func (d *driver) sharpLeft() {
	d.left.pwr.Write(embd.High)
	d.left.fwd.Write(embd.Low)
	d.right.pwr.Write(embd.High)
	d.right.fwd.Write(embd.High)
	d.setMoving(true)
}

func (d *driver) fwdRight() {
	d.left.pwr.Write(embd.High)
	d.left.fwd.Write(embd.High)
	d.right.pwr.Write(embd.Low)
	d.right.fwd.Write(embd.High)
	d.setMoving(true)
}

func (d *driver) fwdLeft() {
	d.left.pwr.Write(embd.Low)
	d.left.fwd.Write(embd.High)
	d.right.pwr.Write(embd.High)
	d.right.fwd.Write(embd.High)
	d.setMoving(true)
}

func (d *driver) backRight() {
	d.left.pwr.Write(embd.High)
	d.left.fwd.Write(embd.Low)
	d.right.pwr.Write(embd.Low)
	d.right.fwd.Write(embd.Low)
	d.setMoving(true)
}

func (d *driver) backLeft() {
	d.left.pwr.Write(embd.Low)
	d.left.fwd.Write(embd.Low)
	d.right.pwr.Write(embd.High)
	d.right.fwd.Write(embd.Low)
	d.setMoving(true)
}

const (
	safeStraightDist = 20
	safeTurningDist  = 10
)

func (s *server) drive(dir *pb.Direction) {
	switch {
	case dir.Dy > -5 && dir.Dy < 5 && dir.Dx > -5 && dir.Dx < 5:
		s.front.enabled = false
		s.rear.enabled = false
		s.driver.stop()
	case dir.Dy > 5 && dir.Dx > -5 && dir.Dx < 5:
		s.front.enabled = true
		s.driver.forward()
	case dir.Dy < -5 && dir.Dx > -5 && dir.Dx < 5:
		s.rear.enabled = true
		s.driver.backward()
	case dir.Dx > 5 && dir.Dy > -5 && dir.Dy < 5:
		s.driver.sharpRight()
	case dir.Dx < -5 && dir.Dy > -5 && dir.Dy < 5:
		s.driver.sharpLeft()
	case dir.Dx > 5 && dir.Dy > 5:
		s.driver.fwdRight()
	case dir.Dx < -5 && dir.Dy > 5:
		s.driver.fwdLeft()
	case dir.Dx > 5 && dir.Dy < -5:
		s.driver.backRight()
	case dir.Dx < -5 && dir.Dy < -5:
		s.driver.backLeft()
	}
}

type engine struct {
	fwd, pwr embd.DigitalPin
}

func newEngine(pwrPin, fwdPin int) (*engine, error) {
	var e engine
	var err error
	e.pwr, err = embd.NewDigitalPin(pwrPin)
	if err != nil {
		return nil, fmt.Errorf("can't init power pin: %v", err)
	}
	e.fwd, err = embd.NewDigitalPin(fwdPin)
	if err != nil {
		return nil, fmt.Errorf("can't init forward pin: %v", err)
	}

	// Set direction.
	if err := e.pwr.SetDirection(embd.Out); err != nil {
		return nil, fmt.Errorf("can't set power direction: %v", err)
	}
	if err := e.fwd.SetDirection(embd.Out); err != nil {
		return nil, fmt.Errorf("can't set forward direction: %v", err)
	}
	return &e, nil
}

func (e *engine) close() {
	e.pwr.Close()
	e.fwd.Close()
}

const (
	sensorUnknown = iota
	sensorFront
	sensorRear
)

func (s *server) Drive(stream pb.Driver_DriveServer) error {
	waitc := make(chan struct{})
	go func() {
		for {
			d, err := stream.Recv()
			if err != nil {
				log.Warnf("ERR from client: %v", err)
				close(waitc)
				return
			}
			s.drive(d)
		}
	}()

	for {
		select {
		case <-time.After(time.Second):
			if !s.front.enabled && !s.rear.enabled {
				continue
			}
			if err := stream.Send(&pb.Telemetry{Speed: 1, DistFront: int32(s.front.dist), DistRear: int32(s.rear.dist)}); err != nil {
				log.Errorf("can't send telemetry: %v", err)
				return err
			}
			log.Info("Sending telemetry!")
		case <-waitc:
			log.Info("got ERR from client, closing sending loop")
			return nil
		}
	}
}

var grpcPort = flag.String("grpc-port", "31337", "gRPC listen port")

func main() {
	flag.Parse()

	go http.ListenAndServe(":9191", nil)

	// Initialize GPIO.
	var err error
	if err = embd.InitGPIO(); err != nil {
		log.Fatalf("Can't init GPIO: %v", err)
	}
	defer embd.CloseGPIO()
	front, err := newEcho("front", 9, 10)
	if err != nil {
		log.Fatalf("Can't init front echo: %v", err)
	}
	defer front.close()
	rear, err := newEcho("rear", 19, 20)
	if err != nil {
		log.Fatalf("Can't init rear echo: %v", err)
	}
	defer rear.close()
	go front.runDistancer()
	go rear.runDistancer()

	left, err := newEngine(23, 4)
	if err != nil {
		log.Fatalf("Can't init left engine: %v", err)
	}
	defer left.close()
	right, err := newEngine(24, 17)
	if err != nil {
		log.Fatalf("Can't init right engine: %v", err)
	}
	defer right.close()

	// Listen for GRPC connections.
	lis, err := net.Listen("tcp", ":"+*grpcPort)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	defer lis.Close()

	drv := driver{left: left, right: right}
	go drv.safetyStop()

	srv := server{front: front, rear: rear, driver: &drv}
	s := grpc.NewServer()
	pb.RegisterDriverServer(s, &srv)

	// Open broadcast connection.
	bcast, err := net.ListenPacket("udp", ":0")
	if err != nil {
		log.Fatal(err)
	}
	defer bcast.Close()

	broadcastAddr := "255.255.255.255:8032"
	dst, err := net.ResolveUDPAddr("udp", broadcastAddr)
	if err != nil {
		log.Fatal(err)
	}

	go func() {
		log.Infof("Starting to broadcast our port %s on %s", *grpcPort, broadcastAddr)
		for {
			if _, err := bcast.WriteTo([]byte(*grpcPort), dst); err != nil {
				log.Warn(err)
			}
			time.Sleep(time.Second)
		}
	}()

	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGTERM, syscall.SIGINT)
	go func() {
		sig := <-c
		log.Infof("Got %s, trying to shutdown gracefully", sig.String())
		front.close()
		rear.close()
		left.close()
		right.close()
		embd.CloseGPIO()
		lis.Close()
		bcast.Close()
		os.Exit(0)
	}()

	// Start serving GRPC.
	log.Fatal(s.Serve(lis))
}
<|endoftext|>


<commit_before>package server

import (
	"fmt"
	"math/rand"
	"strings"
	"testing"
	"time"

	"firepear.net/petrel"
	"firepear.net/petrel/client"
)

func TestMultiServer(t *testing.T) {
	// implement an echo server
	c := &Config{Sockname: "/tmp/test03.sock", Msglvl: petrel.Conn}
	as, err := NewUnix(c, 700)
	if err != nil {
		t.Errorf("Couldn't create socket: %v", err)
	}
	as.AddFunc("echo", "args", echo)

	// launch clients
	rand.Seed(time.Now().Unix())
	x := 5
	for i := 0; i < x; i++ {
		go multiclient(as.s, t)
	}
	// wait for all clients to finish
	j := 0
	for i := 0; i < x; i++ {
		for {
			msg := <-as.Msgr
			j++
			if strings.Contains(msg.Txt, "disconnected") {
				break
			}
		}
	}
	// setting message level to Conn in New() should have resulted in
	// us seeing 10 messages instead of about 250
	if j != 10 {
		t.Errorf("Expected to see 10 Msgs but saw %v", j)
	}
	// shut down petrel
	as.Quit()
}

// connect and send 50 messages, separated by small random sleeps
func multiclient(sn string, t *testing.T) {
	ac, err := client.NewUnix(&client.Config{Addr: sn})
	if err != nil {
		t.Fatalf("client instantiation failed! %s", err)
	}
	defer ac.Close()

	for i := 0; i < 50; i++ {
		msg  := fmt.Sprintf("echo message %d (which should be longer than 128 bytes to exercise a path) Lorem ipsum dolor sit amet, consectetur adipiscing elit posuere.", i)
		rmsg := fmt.Sprintf("message %d (which should be longer than 128 bytes to exercise a path) Lorem ipsum dolor sit amet, consectetur adipiscing elit posuere.", i)
		resp, err := ac.Dispatch([]byte(msg))
		if err != nil {
			t.Errorf("Error on read: %v", err)
		}
		if string(resp) != rmsg {
			t.Errorf("Expected '%v' but got '%v'", rmsg, string(resp))
		}
		time.Sleep(time.Duration(rand.Intn(25)) * time.Millisecond)
	}
}
<commit_msg>wip debugging<commit_after>package server

import (
	"log"
	"fmt"
	"math/rand"
	"strings"
	"testing"
	"time"

	"firepear.net/petrel"
	"firepear.net/petrel/client"
)

func TestMultiServer(t *testing.T) {
	// implement an echo server
	c := &Config{Sockname: "/tmp/test03.sock", Msglvl: petrel.Conn}
	as, err := NewUnix(c, 700)
	if err != nil {
		t.Errorf("Couldn't create socket: %v", err)
	}
	as.AddFunc("echo", "args", echo)

	// launch clients
	rand.Seed(time.Now().Unix())
	x := 5
	for i := 0; i < x; i++ {
		go multiclient(as.s, t)
	}
	// wait for all clients to finish
	j := 0
	for i := 0; i < x; i++ {
		for {
			msg := <-as.Msgr
			j++
			if strings.Contains(msg.Txt, "disconnected") {
				break
			}
		}
	}
	// setting message level to Conn in New() should have resulted in
	// us seeing 10 messages instead of about 250
	if j != 10 {
		t.Errorf("Expected to see 10 Msgs but saw %v", j)
	}
	// shut down petrel
	as.Quit()
}

// connect and send 50 messages, separated by small random sleeps
func multiclient(sn string, t *testing.T) {
	ac, err := client.NewUnix(&client.Config{Addr: sn})
	if err != nil {
		t.Fatalf("client instantiation failed! %s", err)
	}
	defer ac.Close()

	for i := 0; i < 50; i++ {
		msg  := fmt.Sprintf("echo message %d (which should be longer than 128 bytes to exercise a path) Lorem ipsum dolor sit amet, consectetur adipiscing elit posuere.", i)
		rmsg := fmt.Sprintf("message %d (which should be longer than 128 bytes to exercise a path) Lorem ipsum dolor sit amet, consectetur adipiscing elit posuere.", i)
		log.Println("send:", string(rmsg))
		resp, err := ac.Dispatch([]byte(msg))
		if err != nil {
			t.Errorf("Error on read: %v", err)
		}
		log.Println("recv", string(resp))
		if string(resp) != rmsg {
			t.Errorf("Expected '%v' but got '%v'", rmsg, string(resp))
		}
		time.Sleep(time.Duration(rand.Intn(25)) * time.Millisecond)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.

// +build go1.9

package codec

import "reflect"

func makeMapReflect(t reflect.Type, size int) reflect.Value {
	if size < 0 {
		return reflect.MakeMapWithSize(t, 4)
	}
	return reflect.MakeMapWithSize(t, size)
}
<commit_msg>codec: makeMapReflect always takes a size >= 0<commit_after>// Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.

// +build go1.9

package codec

import "reflect"

func makeMapReflect(t reflect.Type, size int) reflect.Value {
	// if size < 0 {
	// 	return reflect.MakeMapWithSize(t, 4)
	// }
	return reflect.MakeMapWithSize(t, size)
}
<|endoftext|>


<commit_before>// Go Riemann client
package raidman

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"net"
	"net/url"
	"os"
	"reflect"
	"sync"
	"time"

	"github.com/amir/raidman/proto"
	pb "github.com/golang/protobuf/proto"
	"golang.org/x/net/proxy"
)

type network interface {
	Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error)
}

type tcp struct{}

type udp struct{}

// Client represents a connection to a Riemann server
type Client struct {
	sync.Mutex
	net        network
	connection net.Conn
	timeout    time.Duration
}

// An Event represents a single Riemann event
type Event struct {
	Ttl         float32           `json:"ttl,omitempty"`
	Time        int64             `json:"time,omitempty"`
	Tags        []string          `json:"tags,omitempty"`
	Host        string            `json:"host,omitempty"` // Defaults to os.Hostname()
	State       string            `json:"state,omitempty"`
	Service     string            `json:"service,omitempty"`
	Metric      interface{}       `json:"metric,omitempty"` // Could be Int, Float32, Float64
	Description string            `json:"description,omitempty"`
	Attributes  map[string]string `json:"attributes,omitempty"`
}

// Dial establishes a connection to a Riemann server at addr, on the network
// netwrk, with a timeout of timeout
//
// Known networks are "tcp", "tcp4", "tcp6", "udp", "udp4", and "udp6".
func DialWithTimeout(netwrk, addr string, timeout time.Duration) (c *Client, err error) {
	c = new(Client)

	var cnet network
	switch netwrk {
	case "tcp", "tcp4", "tcp6":
		cnet = new(tcp)
	case "udp", "udp4", "udp6":
		cnet = new(udp)
	default:
		return nil, fmt.Errorf("dial %q: unsupported network %q", netwrk, netwrk)
	}

	dialer, err := newDialer()
	if err != nil {
		return nil, err
	}

	c.net = cnet
	c.timeout = timeout
	c.connection, err = dialer.Dial(netwrk, addr)
	if err != nil {
		return nil, err
	}

	return c, nil
}

func newDialer() (proxy.Dialer, error) {
	var proxyUrl = os.Getenv("RIEMANN_PROXY")
	var dialer proxy.Dialer = proxy.Direct

	// Get a proxy Dialer that will create the connection on our
	// behalf via the SOCKS5 proxy.  Specify the authentication
	// and re-create the dialer/transport/client if tor's
	// IsolateSOCKSAuth is needed.
	if len(proxyUrl) > 0 {
		u, err := url.Parse(proxyUrl)
		if err != nil {
			fmt.Errorf("failed to obtain proxy dialer: %v\n", err)
		}
		if dialer, err = proxy.FromURL(u, dialer); err != nil {
			fmt.Errorf("failed to parse  " + proxyUrl + " as a proxy: " + err.Error())
			return nil, err
		}
	}

	return dialer, nil
}

// Dial establishes a connection to a Riemann server at addr, on the network
// netwrk.
//
// Known networks are "tcp", "tcp4", "tcp6", "udp", "udp4", and "udp6".
func Dial(netwrk, addr string) (c *Client, err error) {
	return DialWithTimeout(netwrk, addr, 0)
}

func (network *tcp) Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error) {
	msg := &proto.Msg{}
	data, err := pb.Marshal(message)
	if err != nil {
		return msg, err
	}
	b := new(bytes.Buffer)
	if err = binary.Write(b, binary.BigEndian, uint32(len(data))); err != nil {
		return msg, err
	}
	if _, err = conn.Write(b.Bytes()); err != nil {
		return msg, err
	}
	if _, err = conn.Write(data); err != nil {
		return msg, err
	}
	var header uint32
	if err = binary.Read(conn, binary.BigEndian, &header); err != nil {
		return msg, err
	}
	response := make([]byte, header)
	if err = readFully(conn, response); err != nil {
		return msg, err
	}
	if err = pb.Unmarshal(response, msg); err != nil {
		return msg, err
	}
	if msg.GetOk() != true {
		return msg, errors.New(msg.GetError())
	}
	return msg, nil
}

func readFully(r io.Reader, p []byte) error {
	for len(p) > 0 {
		n, err := r.Read(p)
		p = p[n:]
		if err != nil {
			return err
		}
	}
	return nil
}

func (network *udp) Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error) {
	data, err := pb.Marshal(message)
	if err != nil {
		return nil, err
	}
	if _, err = conn.Write(data); err != nil {
		return nil, err
	}

	return nil, nil
}

func isZero(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.Map:
		return v.IsNil()
	case reflect.Slice:
		zero := true
		for i := 0; i < v.Len(); i++ {
			zero = zero && isZero(v.Index(i))
		}
		return zero
	}
	zero := reflect.Zero(v.Type())
	return v.Interface() == zero.Interface()
}

func eventToPbEvent(event *Event) (*proto.Event, error) {
	var e proto.Event

	if event.Host == "" {
		event.Host, _ = os.Hostname()
	}
	t := reflect.ValueOf(&e).Elem()
	s := reflect.ValueOf(event).Elem()
	typeOfEvent := s.Type()
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)
		value := reflect.ValueOf(f.Interface())
		if !isZero(f) {
			name := typeOfEvent.Field(i).Name
			switch name {
			case "State", "Service", "Host", "Description":
				tmp := reflect.ValueOf(pb.String(value.String()))
				t.FieldByName(name).Set(tmp)
			case "Ttl":
				tmp := reflect.ValueOf(pb.Float32(float32(value.Float())))
				t.FieldByName(name).Set(tmp)
			case "Time":
				tmp := reflect.ValueOf(pb.Int64(value.Int()))
				t.FieldByName(name).Set(tmp)
			case "Tags":
				tmp := reflect.ValueOf(value.Interface().([]string))
				t.FieldByName(name).Set(tmp)
			case "Metric":
				switch reflect.TypeOf(f.Interface()).Kind() {
				case reflect.Int, reflect.Int64:
					tmp := reflect.ValueOf(pb.Int64(int64(value.Int())))
					t.FieldByName("MetricSint64").Set(tmp)
				case reflect.Uint64:
					tmp := reflect.ValueOf(pb.Int64(int64(value.Uint())))
					t.FieldByName("MetricSint64").Set(tmp)
				case reflect.Float32:
					tmp := reflect.ValueOf(pb.Float32(float32(value.Float())))
					t.FieldByName("MetricF").Set(tmp)
				case reflect.Float64:
					tmp := reflect.ValueOf(pb.Float64(value.Float()))
					t.FieldByName("MetricD").Set(tmp)
				default:
					return nil, fmt.Errorf("Metric of invalid type (type %v)",
						reflect.TypeOf(f.Interface()).Kind())
				}
			case "Attributes":
				var attrs []*proto.Attribute
				for k, v := range value.Interface().(map[string]string) {
					// Copy k,v so we can take
					// pointers to the new
					// temporaries
					k_, v_ := k, v
					attrs = append(attrs, &proto.Attribute{
						Key:   &k_,
						Value: &v_,
					})
				}
				t.FieldByName(name).Set(reflect.ValueOf(attrs))
			}
		}
	}

	return &e, nil
}

func pbEventsToEvents(pbEvents []*proto.Event) []Event {
	var events []Event

	for _, event := range pbEvents {
		e := Event{
			State:       event.GetState(),
			Service:     event.GetService(),
			Host:        event.GetHost(),
			Description: event.GetDescription(),
			Ttl:         event.GetTtl(),
			Time:        event.GetTime(),
			Tags:        event.GetTags(),
		}
		if event.MetricF != nil {
			e.Metric = event.GetMetricF()
		} else if event.MetricD != nil {
			e.Metric = event.GetMetricD()
		} else {
			e.Metric = event.GetMetricSint64()
		}
		if event.Attributes != nil {
			e.Attributes = make(map[string]string, len(event.GetAttributes()))
			for _, attr := range event.GetAttributes() {
				e.Attributes[attr.GetKey()] = attr.GetValue()
			}
		}

		events = append(events, e)
	}

	return events
}

// Send sends an event to Riemann
func (c *Client) Send(event *Event) error {
	return c.SendMulti([]*Event{event})
}

// SendMulti sends multiple events to Riemann
func (c *Client) SendMulti(events []*Event) error {
	message := &proto.Msg{}

	for _, event := range events {
		e, err := eventToPbEvent(event)
		if err != nil {
			return err
		}

		message.Events = append(message.Events, e)
	}

	c.Lock()
	defer c.Unlock()

	if c.timeout > 0 {
		err := c.connection.SetDeadline(time.Now().Add(c.timeout))
		if err != nil {
			return err
		}
	}

	_, err := c.net.Send(message, c.connection)
	if err != nil {
		return err
	}

	return nil
}

// Query returns a list of events matched by query
func (c *Client) Query(q string) ([]Event, error) {
	switch c.net.(type) {
	case *udp:
		return nil, errors.New("Querying over UDP is not supported")
	}
	query := &proto.Query{}
	query.String_ = pb.String(q)
	message := &proto.Msg{}
	message.Query = query
	c.Lock()
	defer c.Unlock()
	response, err := c.net.Send(message, c.connection)
	if err != nil {
		return nil, err
	}
	return pbEventsToEvents(response.GetEvents()), nil
}

// Close closes the connection to Riemann
func (c *Client) Close() {
	c.Lock()
	c.connection.Close()
	c.Unlock()
}
<commit_msg>Fix go vet issues<commit_after>// Go Riemann client
package raidman

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"net"
	"net/url"
	"os"
	"reflect"
	"sync"
	"time"

	"github.com/amir/raidman/proto"
	pb "github.com/golang/protobuf/proto"
	"golang.org/x/net/proxy"
)

type network interface {
	Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error)
}

type tcp struct{}

type udp struct{}

// Client represents a connection to a Riemann server
type Client struct {
	sync.Mutex
	net        network
	connection net.Conn
	timeout    time.Duration
}

// An Event represents a single Riemann event
type Event struct {
	Ttl         float32           `json:"ttl,omitempty"`
	Time        int64             `json:"time,omitempty"`
	Tags        []string          `json:"tags,omitempty"`
	Host        string            `json:"host,omitempty"` // Defaults to os.Hostname()
	State       string            `json:"state,omitempty"`
	Service     string            `json:"service,omitempty"`
	Metric      interface{}       `json:"metric,omitempty"` // Could be Int, Float32, Float64
	Description string            `json:"description,omitempty"`
	Attributes  map[string]string `json:"attributes,omitempty"`
}

// Dial establishes a connection to a Riemann server at addr, on the network
// netwrk, with a timeout of timeout
//
// Known networks are "tcp", "tcp4", "tcp6", "udp", "udp4", and "udp6".
func DialWithTimeout(netwrk, addr string, timeout time.Duration) (c *Client, err error) {
	c = new(Client)

	var cnet network
	switch netwrk {
	case "tcp", "tcp4", "tcp6":
		cnet = new(tcp)
	case "udp", "udp4", "udp6":
		cnet = new(udp)
	default:
		return nil, fmt.Errorf("dial %q: unsupported network %q", netwrk, netwrk)
	}

	dialer, err := newDialer()
	if err != nil {
		return nil, err
	}

	c.net = cnet
	c.timeout = timeout
	c.connection, err = dialer.Dial(netwrk, addr)
	if err != nil {
		return nil, err
	}

	return c, nil
}

func newDialer() (proxy.Dialer, error) {
	var proxyUrl = os.Getenv("RIEMANN_PROXY")
	var dialer proxy.Dialer = proxy.Direct

	// Get a proxy Dialer that will create the connection on our
	// behalf via the SOCKS5 proxy.  Specify the authentication
	// and re-create the dialer/transport/client if tor's
	// IsolateSOCKSAuth is needed.
	if len(proxyUrl) > 0 {
		u, err := url.Parse(proxyUrl)
		if err != nil {
			return nil, fmt.Errorf("failed to obtain proxy dialer: %v\n", err)
		}
		if dialer, err = proxy.FromURL(u, dialer); err != nil {
			return nil, fmt.Errorf("failed to parse  " + proxyUrl + " as a proxy: " + err.Error())
		}
	}

	return dialer, nil
}

// Dial establishes a connection to a Riemann server at addr, on the network
// netwrk.
//
// Known networks are "tcp", "tcp4", "tcp6", "udp", "udp4", and "udp6".
func Dial(netwrk, addr string) (c *Client, err error) {
	return DialWithTimeout(netwrk, addr, 0)
}

func (network *tcp) Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error) {
	msg := &proto.Msg{}
	data, err := pb.Marshal(message)
	if err != nil {
		return msg, err
	}
	b := new(bytes.Buffer)
	if err = binary.Write(b, binary.BigEndian, uint32(len(data))); err != nil {
		return msg, err
	}
	if _, err = conn.Write(b.Bytes()); err != nil {
		return msg, err
	}
	if _, err = conn.Write(data); err != nil {
		return msg, err
	}
	var header uint32
	if err = binary.Read(conn, binary.BigEndian, &header); err != nil {
		return msg, err
	}
	response := make([]byte, header)
	if err = readFully(conn, response); err != nil {
		return msg, err
	}
	if err = pb.Unmarshal(response, msg); err != nil {
		return msg, err
	}
	if msg.GetOk() != true {
		return msg, errors.New(msg.GetError())
	}
	return msg, nil
}

func readFully(r io.Reader, p []byte) error {
	for len(p) > 0 {
		n, err := r.Read(p)
		p = p[n:]
		if err != nil {
			return err
		}
	}
	return nil
}

func (network *udp) Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error) {
	data, err := pb.Marshal(message)
	if err != nil {
		return nil, err
	}
	if _, err = conn.Write(data); err != nil {
		return nil, err
	}

	return nil, nil
}

func isZero(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.Map:
		return v.IsNil()
	case reflect.Slice:
		zero := true
		for i := 0; i < v.Len(); i++ {
			zero = zero && isZero(v.Index(i))
		}
		return zero
	}
	zero := reflect.Zero(v.Type())
	return v.Interface() == zero.Interface()
}

func eventToPbEvent(event *Event) (*proto.Event, error) {
	var e proto.Event

	if event.Host == "" {
		event.Host, _ = os.Hostname()
	}
	t := reflect.ValueOf(&e).Elem()
	s := reflect.ValueOf(event).Elem()
	typeOfEvent := s.Type()
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)
		value := reflect.ValueOf(f.Interface())
		if !isZero(f) {
			name := typeOfEvent.Field(i).Name
			switch name {
			case "State", "Service", "Host", "Description":
				tmp := reflect.ValueOf(pb.String(value.String()))
				t.FieldByName(name).Set(tmp)
			case "Ttl":
				tmp := reflect.ValueOf(pb.Float32(float32(value.Float())))
				t.FieldByName(name).Set(tmp)
			case "Time":
				tmp := reflect.ValueOf(pb.Int64(value.Int()))
				t.FieldByName(name).Set(tmp)
			case "Tags":
				tmp := reflect.ValueOf(value.Interface().([]string))
				t.FieldByName(name).Set(tmp)
			case "Metric":
				switch reflect.TypeOf(f.Interface()).Kind() {
				case reflect.Int, reflect.Int64:
					tmp := reflect.ValueOf(pb.Int64(int64(value.Int())))
					t.FieldByName("MetricSint64").Set(tmp)
				case reflect.Uint64:
					tmp := reflect.ValueOf(pb.Int64(int64(value.Uint())))
					t.FieldByName("MetricSint64").Set(tmp)
				case reflect.Float32:
					tmp := reflect.ValueOf(pb.Float32(float32(value.Float())))
					t.FieldByName("MetricF").Set(tmp)
				case reflect.Float64:
					tmp := reflect.ValueOf(pb.Float64(value.Float()))
					t.FieldByName("MetricD").Set(tmp)
				default:
					return nil, fmt.Errorf("Metric of invalid type (type %v)",
						reflect.TypeOf(f.Interface()).Kind())
				}
			case "Attributes":
				var attrs []*proto.Attribute
				for k, v := range value.Interface().(map[string]string) {
					// Copy k,v so we can take
					// pointers to the new
					// temporaries
					k_, v_ := k, v
					attrs = append(attrs, &proto.Attribute{
						Key:   &k_,
						Value: &v_,
					})
				}
				t.FieldByName(name).Set(reflect.ValueOf(attrs))
			}
		}
	}

	return &e, nil
}

func pbEventsToEvents(pbEvents []*proto.Event) []Event {
	var events []Event

	for _, event := range pbEvents {
		e := Event{
			State:       event.GetState(),
			Service:     event.GetService(),
			Host:        event.GetHost(),
			Description: event.GetDescription(),
			Ttl:         event.GetTtl(),
			Time:        event.GetTime(),
			Tags:        event.GetTags(),
		}
		if event.MetricF != nil {
			e.Metric = event.GetMetricF()
		} else if event.MetricD != nil {
			e.Metric = event.GetMetricD()
		} else {
			e.Metric = event.GetMetricSint64()
		}
		if event.Attributes != nil {
			e.Attributes = make(map[string]string, len(event.GetAttributes()))
			for _, attr := range event.GetAttributes() {
				e.Attributes[attr.GetKey()] = attr.GetValue()
			}
		}

		events = append(events, e)
	}

	return events
}

// Send sends an event to Riemann
func (c *Client) Send(event *Event) error {
	return c.SendMulti([]*Event{event})
}

// SendMulti sends multiple events to Riemann
func (c *Client) SendMulti(events []*Event) error {
	message := &proto.Msg{}

	for _, event := range events {
		e, err := eventToPbEvent(event)
		if err != nil {
			return err
		}

		message.Events = append(message.Events, e)
	}

	c.Lock()
	defer c.Unlock()

	if c.timeout > 0 {
		err := c.connection.SetDeadline(time.Now().Add(c.timeout))
		if err != nil {
			return err
		}
	}

	_, err := c.net.Send(message, c.connection)
	if err != nil {
		return err
	}

	return nil
}

// Query returns a list of events matched by query
func (c *Client) Query(q string) ([]Event, error) {
	switch c.net.(type) {
	case *udp:
		return nil, errors.New("Querying over UDP is not supported")
	}
	query := &proto.Query{}
	query.String_ = pb.String(q)
	message := &proto.Msg{}
	message.Query = query
	c.Lock()
	defer c.Unlock()
	response, err := c.net.Send(message, c.connection)
	if err != nil {
		return nil, err
	}
	return pbEventsToEvents(response.GetEvents()), nil
}

// Close closes the connection to Riemann
func (c *Client) Close() {
	c.Lock()
	c.connection.Close()
	c.Unlock()
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"os"
	"regexp"
	"testing"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccDataSourceAwsWorkspaceBundle_basic(t *testing.T) {
	dataSourceName := "data.aws_workspaces_bundle.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config: testAccDataSourceAwsWorkspaceBundleConfig("wsb-b0s22j3d7"),
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttr(dataSourceName, "bundle_id", "wsb-b0s22j3d7"),
					resource.TestCheckResourceAttr(dataSourceName, "compute_type.#", "1"),
					resource.TestCheckResourceAttr(dataSourceName, "compute_type.0.name", "PERFORMANCE"),
					resource.TestCheckResourceAttrSet(dataSourceName, "description"),
					resource.TestCheckResourceAttr(dataSourceName, "name", "Performance with Windows 7"),
					resource.TestCheckResourceAttr(dataSourceName, "owner", "Amazon"),
					resource.TestCheckResourceAttr(dataSourceName, "root_storage.#", "1"),
					resource.TestCheckResourceAttr(dataSourceName, "root_storage.0.capacity", "80"),
					resource.TestCheckResourceAttr(dataSourceName, "user_storage.#", "1"),
					resource.TestCheckResourceAttr(dataSourceName, "user_storage.0.capacity", "100"),
				),
			},
		},
	})
}

func TestAccDataSourceAwsWorkspaceBundle_byOwnerName(t *testing.T) {
	dataSourceName := "data.aws_workspaces_bundle.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config: testAccDataSourceAwsWorkspaceBundleConfig_byOwnerName("AMAZON", "Value with Windows 10 and Office 2016"),
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttr(dataSourceName, "bundle_id", "wsb-df76rqys9"),
					resource.TestCheckResourceAttr(dataSourceName, "compute_type.#", "1"),
					resource.TestCheckResourceAttr(dataSourceName, "compute_type.0.name", "VALUE"),
					resource.TestCheckResourceAttrSet(dataSourceName, "description"),
					resource.TestCheckResourceAttr(dataSourceName, "name", "Value with Windows 10 and Office 2016"),
					resource.TestCheckResourceAttr(dataSourceName, "owner", "Amazon"),
					resource.TestCheckResourceAttr(dataSourceName, "root_storage.#", "1"),
					resource.TestCheckResourceAttr(dataSourceName, "root_storage.0.capacity", "80"),
					resource.TestCheckResourceAttr(dataSourceName, "user_storage.#", "1"),
					resource.TestCheckResourceAttr(dataSourceName, "user_storage.0.capacity", "10"),
				),
			},
		},
	})
}

func TestAccDataSourceAwsWorkspaceBundle_bundleIDAndNameConflict(t *testing.T) {
	resource.ParallelTest(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config:      testAccDataSourceAwsWorkspaceBundleConfig_bundleIDAndOwnerNameConflict("wsb-df76rqys9", "AMAZON", "Value with Windows 10 and Office 2016"),
				ExpectError: regexp.MustCompile("\"bundle_id\": conflicts with owner"),
			},
		},
	})
}

func TestAccDataSourceAwsWorkspaceBundle_privateOwner(t *testing.T) {
	dataSourceName := "data.aws_workspaces_bundle.test"
	bundleName := os.Getenv("AWS_WORKSPACES_BUNDLE_NAME")

	resource.ParallelTest(t, resource.TestCase{
		PreCheck: func() {
			testAccPreCheck(t)
			testAccWorkspacesBundlePreCheck(t)
		},
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config: testAccDataSourceAwsWorkspaceBundleConfig_privateOwner(bundleName),
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttr(dataSourceName, "name", bundleName),
				),
			},
		},
	})
}

func testAccWorkspacesBundlePreCheck(t *testing.T) {
	if os.Getenv("AWS_WORKSPACES_BUNDLE_NAME") == "" {
		t.Skip("AWS_WORKSPACES_BUNDLE_NAME env var must be set for AWS WorkSpaces private bundle acceptance test. This is required until AWS provides bundle creation API.")
	}
}

func testAccDataSourceAwsWorkspaceBundleConfig(bundleID string) string {
	return fmt.Sprintf(`
data "aws_workspaces_bundle" "test" {
  bundle_id = %q
}
`, bundleID)
}

func testAccDataSourceAwsWorkspaceBundleConfig_byOwnerName(owner, name string) string {
	return fmt.Sprintf(`
data "aws_workspaces_bundle" "test" {
  owner = %q
  name  = %q
}
`, owner, name)
}

func testAccDataSourceAwsWorkspaceBundleConfig_bundleIDAndOwnerNameConflict(bundleID, owner, name string) string {
	return fmt.Sprintf(`
data "aws_workspaces_bundle" "test" {
  bundle_id = %q
  owner     = %q
  name      = %q
}
`, bundleID, owner, name)
}

func testAccDataSourceAwsWorkspaceBundleConfig_privateOwner(name string) string {
	return fmt.Sprintf(`
data "aws_workspaces_bundle" "test" {
  name  = %q
}
`, name)
}
<commit_msg>Gratify linter<commit_after>package aws

import (
	"fmt"
	"os"
	"regexp"
	"testing"

	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccDataSourceAwsWorkspaceBundle_basic(t *testing.T) {
	dataSourceName := "data.aws_workspaces_bundle.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config: testAccDataSourceAwsWorkspaceBundleConfig("wsb-b0s22j3d7"),
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttr(dataSourceName, "bundle_id", "wsb-b0s22j3d7"),
					resource.TestCheckResourceAttr(dataSourceName, "compute_type.#", "1"),
					resource.TestCheckResourceAttr(dataSourceName, "compute_type.0.name", "PERFORMANCE"),
					resource.TestCheckResourceAttrSet(dataSourceName, "description"),
					resource.TestCheckResourceAttr(dataSourceName, "name", "Performance with Windows 7"),
					resource.TestCheckResourceAttr(dataSourceName, "owner", "Amazon"),
					resource.TestCheckResourceAttr(dataSourceName, "root_storage.#", "1"),
					resource.TestCheckResourceAttr(dataSourceName, "root_storage.0.capacity", "80"),
					resource.TestCheckResourceAttr(dataSourceName, "user_storage.#", "1"),
					resource.TestCheckResourceAttr(dataSourceName, "user_storage.0.capacity", "100"),
				),
			},
		},
	})
}

func TestAccDataSourceAwsWorkspaceBundle_byOwnerName(t *testing.T) {
	dataSourceName := "data.aws_workspaces_bundle.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config: testAccDataSourceAwsWorkspaceBundleConfig_byOwnerName("AMAZON", "Value with Windows 10 and Office 2016"),
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttr(dataSourceName, "bundle_id", "wsb-df76rqys9"),
					resource.TestCheckResourceAttr(dataSourceName, "compute_type.#", "1"),
					resource.TestCheckResourceAttr(dataSourceName, "compute_type.0.name", "VALUE"),
					resource.TestCheckResourceAttrSet(dataSourceName, "description"),
					resource.TestCheckResourceAttr(dataSourceName, "name", "Value with Windows 10 and Office 2016"),
					resource.TestCheckResourceAttr(dataSourceName, "owner", "Amazon"),
					resource.TestCheckResourceAttr(dataSourceName, "root_storage.#", "1"),
					resource.TestCheckResourceAttr(dataSourceName, "root_storage.0.capacity", "80"),
					resource.TestCheckResourceAttr(dataSourceName, "user_storage.#", "1"),
					resource.TestCheckResourceAttr(dataSourceName, "user_storage.0.capacity", "10"),
				),
			},
		},
	})
}

func TestAccDataSourceAwsWorkspaceBundle_bundleIDAndNameConflict(t *testing.T) {
	resource.ParallelTest(t, resource.TestCase{
		PreCheck:  func() { testAccPreCheck(t) },
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config:      testAccDataSourceAwsWorkspaceBundleConfig_bundleIDAndOwnerNameConflict("wsb-df76rqys9", "AMAZON", "Value with Windows 10 and Office 2016"),
				ExpectError: regexp.MustCompile("\"bundle_id\": conflicts with owner"),
			},
		},
	})
}

func TestAccDataSourceAwsWorkspaceBundle_privateOwner(t *testing.T) {
	dataSourceName := "data.aws_workspaces_bundle.test"
	bundleName := os.Getenv("AWS_WORKSPACES_BUNDLE_NAME")

	resource.ParallelTest(t, resource.TestCase{
		PreCheck: func() {
			testAccPreCheck(t)
			testAccWorkspacesBundlePreCheck(t)
		},
		Providers: testAccProviders,
		Steps: []resource.TestStep{
			{
				Config: testAccDataSourceAwsWorkspaceBundleConfig_privateOwner(bundleName),
				Check: resource.ComposeTestCheckFunc(
					resource.TestCheckResourceAttr(dataSourceName, "name", bundleName),
				),
			},
		},
	})
}

func testAccWorkspacesBundlePreCheck(t *testing.T) {
	if os.Getenv("AWS_WORKSPACES_BUNDLE_NAME") == "" {
		t.Skip("AWS_WORKSPACES_BUNDLE_NAME env var must be set for AWS WorkSpaces private bundle acceptance test. This is required until AWS provides bundle creation API.")
	}
}

func testAccDataSourceAwsWorkspaceBundleConfig(bundleID string) string {
	return fmt.Sprintf(`
data "aws_workspaces_bundle" "test" {
  bundle_id = %q
}
`, bundleID)
}

func testAccDataSourceAwsWorkspaceBundleConfig_byOwnerName(owner, name string) string {
	return fmt.Sprintf(`
data "aws_workspaces_bundle" "test" {
  owner = %q
  name  = %q
}
`, owner, name)
}

func testAccDataSourceAwsWorkspaceBundleConfig_bundleIDAndOwnerNameConflict(bundleID, owner, name string) string {
	return fmt.Sprintf(`
data "aws_workspaces_bundle" "test" {
  bundle_id = %q
  owner     = %q
  name      = %q
}
`, bundleID, owner, name)
}

func testAccDataSourceAwsWorkspaceBundleConfig_privateOwner(name string) string {
	return fmt.Sprintf(`
data "aws_workspaces_bundle" "test" {
  name = %q
}
`, name)
}
<|endoftext|>