<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 conversion

import (
	"crypto/sha256"
	"encoding/hex"
	"strings"

	corev1 "k8s.io/api/core/v1"
	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/apimachinery/pkg/util/validation"
	v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
	"k8s.io/kubernetes/pkg/kubelet/envvars"

	"github.com/kubernetes-sigs/multi-tenancy/incubator/virtualcluster/pkg/apis/tenancy/v1alpha1"
	"github.com/kubernetes-sigs/multi-tenancy/incubator/virtualcluster/pkg/syncer/constants"
)

const (
	masterServiceNamespace = metav1.NamespaceDefault
)

var masterServices = sets.NewString("kubernetes")

// ToClusterKey make a unique id for a virtual cluster object.
// The key uses the format <namespace>-<name> unless <namespace> is empty, then
// it's just <name>.
func ToClusterKey(vc *v1alpha1.Virtualcluster) string {
	if len(vc.GetNamespace()) > 0 {
		return vc.GetNamespace() + "-" + vc.GetName()
	}
	return vc.GetName()
}

func ToSuperMasterNamespace(cluster, ns string) string {
	targetNamespace := strings.Join([]string{cluster, ns}, "-")
	if len(targetNamespace) > validation.DNS1123SubdomainMaxLength {
		digest := sha256.Sum256([]byte(targetNamespace))
		return targetNamespace[0:57] + "-" + hex.EncodeToString(digest[0:])[0:5]
	}
	return targetNamespace
}

func GetOwner(obj runtime.Object) (cluster, namespace string) {
	meta, err := meta.Accessor(obj)
	if err != nil {
		return "", ""
	}

	cluster = meta.GetAnnotations()[constants.LabelCluster]
	namespace = strings.TrimPrefix(meta.GetNamespace(), cluster+"-")
	return cluster, namespace
}

func BuildMetadata(cluster, targetNamespace string, obj runtime.Object) (runtime.Object, error) {
	target := obj.DeepCopyObject()
	m, err := meta.Accessor(target)
	if err != nil {
		return nil, err
	}

	uid := m.GetUID()

	resetMetadata(m)
	if len(targetNamespace) > 0 {
		m.SetNamespace(targetNamespace)
	}

	anno := m.GetAnnotations()
	if anno == nil {
		anno = map[string]string{}
	}
	anno[constants.LabelCluster] = cluster
	anno[constants.LabelUID] = string(uid)
	m.SetAnnotations(anno)

	return target, nil
}

func BuildSuperMasterNamespace(cluster string, obj runtime.Object) (runtime.Object, error) {
	target := obj.DeepCopyObject()
	m, err := meta.Accessor(target)
	if err != nil {
		return nil, err
	}

	resetMetadata(m)

	targetName := strings.Join([]string{cluster, m.GetName()}, "-")
	m.SetName(targetName)
	return target, nil
}

func resetMetadata(obj metav1.Object) {
	obj.SetGenerateName("")
	obj.SetSelfLink("")
	obj.SetUID("")
	obj.SetResourceVersion("")
	obj.SetGeneration(0)
	obj.SetCreationTimestamp(metav1.Time{})
	obj.SetDeletionTimestamp(nil)
	obj.SetDeletionGracePeriodSeconds(nil)
	obj.SetOwnerReferences(nil)
	obj.SetFinalizers(nil)
	obj.SetClusterName("")
	obj.SetInitializers(nil)
}

// MutatePod convert the meta data of containers to super master namespace.
// replace the service account token volume mounts to super master side one.
func MutatePod(namespace string, pod *corev1.Pod, vSASecret, SASecret *v1.Secret, services []*v1.Service) {
	pod.Status = corev1.PodStatus{}
	pod.Spec.NodeName = ""

	// setup env var map
	serviceEnv := getServiceEnvVarMap(pod.Namespace, *pod.Spec.EnableServiceLinks, services)

	for i := range pod.Spec.Containers {
		// Inject env var from service
		// 1. Do nothing if it conflicts with user-defined one.
		// 2. Add remaining service environment vars
		envNameMap := make(map[string]struct{})
		for j, env := range pod.Spec.Containers[i].Env {
			if env.ValueFrom != nil && env.ValueFrom.FieldRef != nil && env.ValueFrom.FieldRef.FieldPath == "metadata.name" {
				pod.Spec.Containers[i].Env[j].ValueFrom = nil
				pod.Spec.Containers[i].Env[j].Value = pod.Name
			}
			if env.ValueFrom != nil && env.ValueFrom.FieldRef != nil && env.ValueFrom.FieldRef.FieldPath == "metadata.namespace" {
				pod.Spec.Containers[i].Env[j].ValueFrom = nil
				pod.Spec.Containers[i].Env[j].Value = namespace
			}
			envNameMap[env.Name] = struct{}{}
		}
		for k, v := range serviceEnv {
			if _, exists := envNameMap[k]; !exists {
				pod.Spec.Containers[i].Env = append(pod.Spec.Containers[i].Env, v1.EnvVar{Name: k, Value: v})
			}
		}

		for j, volumeMount := range pod.Spec.Containers[i].VolumeMounts {
			if volumeMount.Name == vSASecret.Name {
				pod.Spec.Containers[i].VolumeMounts[j].Name = SASecret.Name
			}
		}
	}

	for i, volume := range pod.Spec.Volumes {
		if volume.Name == vSASecret.Name {
			pod.Spec.Volumes[i].Name = SASecret.Name
			pod.Spec.Volumes[i].Secret.SecretName = SASecret.Name
		}
	}
}

func getServiceEnvVarMap(ns string, enableServiceLinks bool, services []*v1.Service) map[string]string {
	var (
		serviceMap = make(map[string]*v1.Service)
		m          = make(map[string]string)
	)

	// project the services in namespace ns onto the master services
	for i := range services {
		service := services[i]
		// ignore services where ClusterIP is "None" or empty
		if !v1helper.IsServiceIPSet(service) {
			continue
		}
		serviceName := service.Name

		// We always want to add environment variabled for master services
		// from the master service namespace, even if enableServiceLinks is false.
		// We also add environment variables for other services in the same
		// namespace, if enableServiceLinks is true.
		if service.Namespace == masterServiceNamespace && masterServices.Has(serviceName) {
			if _, exists := serviceMap[serviceName]; !exists {
				serviceMap[serviceName] = service
			}
		} else if service.Namespace == ns && enableServiceLinks {
			serviceMap[serviceName] = service
		}
	}

	var mappedServices []*v1.Service
	for key := range serviceMap {
		mappedServices = append(mappedServices, serviceMap[key])
	}

	for _, e := range envvars.FromServices(mappedServices) {
		m[e.Name] = e.Value
	}
	return m
}

func MutateService(newService *corev1.Service) {
	newService.Spec.ClusterIP = ""
	for i := range newService.Spec.Ports {
		newService.Spec.Ports[i].NodePort = 0
	}
}
<commit_msg>fix: mutate spec of init containers of the pod<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 conversion

import (
	"crypto/sha256"
	"encoding/hex"
	"strings"

	corev1 "k8s.io/api/core/v1"
	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/apimachinery/pkg/util/validation"
	v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
	"k8s.io/kubernetes/pkg/kubelet/envvars"

	"github.com/kubernetes-sigs/multi-tenancy/incubator/virtualcluster/pkg/apis/tenancy/v1alpha1"
	"github.com/kubernetes-sigs/multi-tenancy/incubator/virtualcluster/pkg/syncer/constants"
)

const (
	masterServiceNamespace = metav1.NamespaceDefault
)

var masterServices = sets.NewString("kubernetes")

// ToClusterKey make a unique id for a virtual cluster object.
// The key uses the format <namespace>-<name> unless <namespace> is empty, then
// it's just <name>.
func ToClusterKey(vc *v1alpha1.Virtualcluster) string {
	if len(vc.GetNamespace()) > 0 {
		return vc.GetNamespace() + "-" + vc.GetName()
	}
	return vc.GetName()
}

func ToSuperMasterNamespace(cluster, ns string) string {
	targetNamespace := strings.Join([]string{cluster, ns}, "-")
	if len(targetNamespace) > validation.DNS1123SubdomainMaxLength {
		digest := sha256.Sum256([]byte(targetNamespace))
		return targetNamespace[0:57] + "-" + hex.EncodeToString(digest[0:])[0:5]
	}
	return targetNamespace
}

func GetOwner(obj runtime.Object) (cluster, namespace string) {
	meta, err := meta.Accessor(obj)
	if err != nil {
		return "", ""
	}

	cluster = meta.GetAnnotations()[constants.LabelCluster]
	namespace = strings.TrimPrefix(meta.GetNamespace(), cluster+"-")
	return cluster, namespace
}

func BuildMetadata(cluster, targetNamespace string, obj runtime.Object) (runtime.Object, error) {
	target := obj.DeepCopyObject()
	m, err := meta.Accessor(target)
	if err != nil {
		return nil, err
	}

	uid := m.GetUID()

	resetMetadata(m)
	if len(targetNamespace) > 0 {
		m.SetNamespace(targetNamespace)
	}

	anno := m.GetAnnotations()
	if anno == nil {
		anno = map[string]string{}
	}
	anno[constants.LabelCluster] = cluster
	anno[constants.LabelUID] = string(uid)
	m.SetAnnotations(anno)

	return target, nil
}

func BuildSuperMasterNamespace(cluster string, obj runtime.Object) (runtime.Object, error) {
	target := obj.DeepCopyObject()
	m, err := meta.Accessor(target)
	if err != nil {
		return nil, err
	}

	resetMetadata(m)

	targetName := strings.Join([]string{cluster, m.GetName()}, "-")
	m.SetName(targetName)
	return target, nil
}

func resetMetadata(obj metav1.Object) {
	obj.SetGenerateName("")
	obj.SetSelfLink("")
	obj.SetUID("")
	obj.SetResourceVersion("")
	obj.SetGeneration(0)
	obj.SetCreationTimestamp(metav1.Time{})
	obj.SetDeletionTimestamp(nil)
	obj.SetDeletionGracePeriodSeconds(nil)
	obj.SetOwnerReferences(nil)
	obj.SetFinalizers(nil)
	obj.SetClusterName("")
	obj.SetInitializers(nil)
}

// MutatePod convert the meta data of containers to super master namespace.
// replace the service account token volume mounts to super master side one.
func MutatePod(namespace string, pod *corev1.Pod, vSASecret, SASecret *v1.Secret, services []*v1.Service) {
	pod.Status = corev1.PodStatus{}
	pod.Spec.NodeName = ""

	// setup env var map
	serviceEnv := getServiceEnvVarMap(pod.Namespace, *pod.Spec.EnableServiceLinks, services)

	for i := range pod.Spec.Containers {
		mutateContainer(&pod.Spec.Containers[i], pod, vSASecret, SASecret, serviceEnv)
	}

	for i := range pod.Spec.InitContainers {
		mutateContainer(&pod.Spec.InitContainers[i], pod, vSASecret, SASecret, serviceEnv)
	}

	for i, volume := range pod.Spec.Volumes {
		if volume.Name == vSASecret.Name {
			pod.Spec.Volumes[i].Name = SASecret.Name
			pod.Spec.Volumes[i].Secret.SecretName = SASecret.Name
		}
	}
}

func mutateContainer(c *v1.Container, pod *v1.Pod, vSASecret, SASecret *v1.Secret, serviceEnvMap map[string]string) {
	// Inject env var from service
	// 1. Do nothing if it conflicts with user-defined one.
	// 2. Add remaining service environment vars
	envNameMap := make(map[string]struct{})
	for j, env := range c.Env {
		if env.ValueFrom != nil && env.ValueFrom.FieldRef != nil && env.ValueFrom.FieldRef.FieldPath == "metadata.name" {
			c.Env[j].ValueFrom = nil
			c.Env[j].Value = pod.Name
		}
		if env.ValueFrom != nil && env.ValueFrom.FieldRef != nil && env.ValueFrom.FieldRef.FieldPath == "metadata.namespace" {
			c.Env[j].ValueFrom = nil
			c.Env[j].Value = pod.Namespace
		}
		envNameMap[env.Name] = struct{}{}
	}
	for k, v := range serviceEnvMap {
		if _, exists := envNameMap[k]; !exists {
			c.Env = append(c.Env, v1.EnvVar{Name: k, Value: v})
		}
	}

	for j, volumeMount := range c.VolumeMounts {
		if volumeMount.Name == vSASecret.Name {
			c.VolumeMounts[j].Name = SASecret.Name
		}
	}
}

func getServiceEnvVarMap(ns string, enableServiceLinks bool, services []*v1.Service) map[string]string {
	var (
		serviceMap = make(map[string]*v1.Service)
		m          = make(map[string]string)
	)

	// project the services in namespace ns onto the master services
	for i := range services {
		service := services[i]
		// ignore services where ClusterIP is "None" or empty
		if !v1helper.IsServiceIPSet(service) {
			continue
		}
		serviceName := service.Name

		// We always want to add environment variabled for master services
		// from the master service namespace, even if enableServiceLinks is false.
		// We also add environment variables for other services in the same
		// namespace, if enableServiceLinks is true.
		if service.Namespace == masterServiceNamespace && masterServices.Has(serviceName) {
			if _, exists := serviceMap[serviceName]; !exists {
				serviceMap[serviceName] = service
			}
		} else if service.Namespace == ns && enableServiceLinks {
			serviceMap[serviceName] = service
		}
	}

	var mappedServices []*v1.Service
	for key := range serviceMap {
		mappedServices = append(mappedServices, serviceMap[key])
	}

	for _, e := range envvars.FromServices(mappedServices) {
		m[e.Name] = e.Value
	}
	return m
}

func MutateService(newService *corev1.Service) {
	newService.Spec.ClusterIP = ""
	for i := range newService.Spec.Ports {
		newService.Spec.Ports[i].NodePort = 0
	}
}
<|endoftext|>


<commit_before>package players

import (
	//	"errors"
	"encoding/json"
	"github.com/ckpt/backend-services/utils"
	mailgun "github.com/mailgun/mailgun-go"
	"os"
	//	"github.com/m4rw3r/uuid"
)

import "fmt"

func StartEventProcessor() error {
	events, err := eventqueue.Consume()
	if err != nil {
		return err
	}
	go func() {
		fmt.Printf("Entering main event processor loop\n")
		for msg := range events {

			// Fetch event
			var event utils.CKPTEvent
			_ = json.Unmarshal(msg.Body, &event)
			fmt.Printf("Found new event of type: %d\n", event.Type)

			// Notify subscribers
			allPlayers, err := AllPlayers()
			if err != nil {
				msg.Nack(false, true)
				continue
			}
			for _, p := range allPlayers {
				notifyPlayer := false
				fmt.Printf("Checking if user %s should be notified\n", p.Nick)
				if p.User.SubscribedTo(utils.TypeNames[event.Type]) {
					notifyPlayer = true
				}
				for _, rp := range event.RestrictedTo {
					notifyPlayer = false
					if rp == p.UUID {
						notifyPlayer = true
						break
					}
				}
				if notifyPlayer {
					fmt.Printf("Notifying user for event\n")
					NotifyUser(p.Nick, p.Profile.Email, event.Subject, event.Message)
				}
			}
			msg.Ack(false)
		}
	}()

	return nil
}

func NotifyUser(name, email, subject, message string) {
	fmt.Printf("Notifying %s with subject:\n", email)
	fmt.Printf("%s\n", subject)

	mailto := fmt.Sprintf("%s <%s>", name, email)
	gun := mailgun.NewMailgun("mail.ckpt.no", os.Getenv("CKPT_MAILGUN_KEY"), "pubkey-b3e133632123a0da24d1e2c5842039b6")
	m := mailgun.NewMessage("CKPT <notifications@mail.ckpt.no>", subject, message, mailto)
	m.AddHeader("Content-Type", "text/plain; charset=\"utf-8\"")
	response, id, err := gun.Send(m)

	if err != nil {
		fmt.Printf("Error:\n%+v\n", err.Error())
	}
	fmt.Printf("Response ID: %s\n", id)
	fmt.Printf("Message from server: %s\n", response)
}
<commit_msg>Add printout of error on consume setup as well.<commit_after>package players

import (
	//	"errors"
	"encoding/json"
	"github.com/ckpt/backend-services/utils"
	mailgun "github.com/mailgun/mailgun-go"
	"os"
	//	"github.com/m4rw3r/uuid"
)

import "fmt"

func StartEventProcessor() error {
	events, err := eventqueue.Consume()
	if err != nil {
		fmt.Printf("Could not consume events:\nError was:\n%v\n",  err)
		return err
	}
	go func() {
		fmt.Printf("Entering main event processor loop\n")
		for msg := range events {

			// Fetch event
			var event utils.CKPTEvent
			_ = json.Unmarshal(msg.Body, &event)
			fmt.Printf("Found new event of type: %d\n", event.Type)

			// Notify subscribers
			allPlayers, err := AllPlayers()
			if err != nil {
				msg.Nack(false, true)
				continue
			}
			for _, p := range allPlayers {
				notifyPlayer := false
				fmt.Printf("Checking if user %s should be notified\n", p.Nick)
				if p.User.SubscribedTo(utils.TypeNames[event.Type]) {
					notifyPlayer = true
				}
				for _, rp := range event.RestrictedTo {
					notifyPlayer = false
					if rp == p.UUID {
						notifyPlayer = true
						break
					}
				}
				if notifyPlayer {
					fmt.Printf("Notifying user for event\n")
					NotifyUser(p.Nick, p.Profile.Email, event.Subject, event.Message)
				}
			}
			msg.Ack(false)
		}
	}()

	return nil
}

func NotifyUser(name, email, subject, message string) {
	fmt.Printf("Notifying %s with subject:\n", email)
	fmt.Printf("%s\n", subject)

	mailto := fmt.Sprintf("%s <%s>", name, email)
	gun := mailgun.NewMailgun("mail.ckpt.no", os.Getenv("CKPT_MAILGUN_KEY"), "pubkey-b3e133632123a0da24d1e2c5842039b6")
	m := mailgun.NewMessage("CKPT <notifications@mail.ckpt.no>", subject, message, mailto)
	m.AddHeader("Content-Type", "text/plain; charset=\"utf-8\"")
	response, id, err := gun.Send(m)

	if err != nil {
		fmt.Printf("Error:\n%+v\n", err.Error())
	}
	fmt.Printf("Response ID: %s\n", id)
	fmt.Printf("Message from server: %s\n", response)
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"flag"
	"fmt"
	"path"
	"path/filepath"
	"strings"
	"time"

	"go.skia.org/infra/go/depot_tools"
	"go.skia.org/infra/go/emulators"
	"go.skia.org/infra/go/git"
	"go.skia.org/infra/go/recipe_cfg"
	"go.skia.org/infra/task_driver/go/lib/bazel"
	"go.skia.org/infra/task_driver/go/lib/checkout"
	"go.skia.org/infra/task_driver/go/lib/golang"
	"go.skia.org/infra/task_driver/go/lib/os_steps"
	"go.skia.org/infra/task_driver/go/td"
)

var (
	// Required properties for this task.
	projectID          = flag.String("project_id", "", "ID of the Google Cloud project.")
	taskID             = flag.String("task_id", "", "ID of this task.")
	taskName           = flag.String("task_name", "", "Name of the task.")
	workDirFlag        = flag.String("workdir", ".", "Working directory.")
	buildbucketBuildID = flag.String("buildbucket_build_id", "", "ID of the Buildbucket build.")
	rbe                = flag.Bool("rbe", false, "Whether to run Bazel on RBE or locally.")
	rbeKey             = flag.String("rbe_key", "", "Path to the service account key to use for RBE.")

	checkoutFlags = checkout.SetupFlags(nil)

	// Optional flags.
	local  = flag.Bool("local", false, "True if running locally (as opposed to on the bots)")
	output = flag.String("o", "", "If provided, dump a JSON blob of step data to the given file. Prints to stdout if '-' is given.")

	// Various paths.
	workDir string

	gitDir *git.Checkout
)

func main() {
	// Setup.
	ctx := td.StartRun(projectID, taskID, taskName, output, local)
	defer td.EndRun(ctx)

	// Compute various directory paths.
	var err error
	workDir, err = os_steps.Abs(ctx, *workDirFlag)
	if err != nil {
		td.Fatal(ctx, err)
	}

	// Check out the code.
	repoState, err := checkout.GetRepoState(checkoutFlags)
	if err != nil {
		td.Fatal(ctx, err)
	}
	gitDir, err = checkout.EnsureGitCheckout(ctx, path.Join(workDir, "repo"), repoState)
	if err != nil {
		td.Fatal(ctx, err)
	}

	// Set up Bazel.
	bzl, bzlCleanup, err := bazel.New(ctx, gitDir.Dir(), *local, *rbeKey)
	if err != nil {
		td.Fatal(ctx, err)
	}
	defer bzlCleanup()

	// Print out the Bazel version for debugging purposes.
	if _, err := bzl.Do(ctx, "version"); err != nil {
		td.Fatal(ctx, err)
	}

	// Run the tests.
	if *rbe {
		if err := testOnRBE(ctx, bzl); err != nil {
			td.Fatal(ctx, err)
		}
	} else {
		if err := testLocally(ctx, bzl); err != nil {
			td.Fatal(ctx, err)
		}
	}
}

// goldctl invokes goldctl with the given arguments.
func goldctl(ctx context.Context, bzl *bazel.Bazel, args ...string) error {
	bazelCommand := []string{"//gold-client/cmd/goldctl", "--"}
	bazelCommand = append(bazelCommand, args...)
	_, err := bzl.Do(ctx, "run", bazelCommand...)
	return err
}

// uploadPuppeteerScreenshotsToGold gathers all screenshots produced by Puppeteer tests and uploads
// them to Gold.
func uploadPuppeteerScreenshotsToGold(ctx context.Context, bzl *bazel.Bazel) error {
	// Extract screenshots.
	puppeteerScreenshotsDir, err := os_steps.TempDir(ctx, "", "puppeteer-screenshots-*")
	if err != nil {
		return err
	}
	if _, err := bzl.Do(ctx, "run", "//:extract_puppeteer_screenshots", "--", "--output_dir", puppeteerScreenshotsDir); err != nil {
		return err
	}

	// Create working directory for goldctl.
	goldctlWorkDir, err := os_steps.TempDir(ctx, "", "goldctl-workdir-*")
	if err != nil {
		return err
	}

	// Authorize goldctl.
	if *local {
		if err := goldctl(ctx, bzl, "auth", "--work-dir", goldctlWorkDir); err != nil {
			return err
		}
	} else {
		if err := goldctl(ctx, bzl, "auth", "--work-dir", goldctlWorkDir, "--luci"); err != nil {
			return err
		}
	}

	// Initialize goldctl.
	args := []string{
		"imgtest", "init",
		"--work-dir", goldctlWorkDir,
		"--instance", "skia-infra",
		"--git_hash", *checkoutFlags.Revision,
		"--key", "source_type:infra",
	}
	if *checkoutFlags.PatchIssue != "" && *checkoutFlags.PatchSet != "" {
		extraArgs := []string{
			"--crs", "gerrit",
			"--cis", "buildbucket",
			"--changelist", *checkoutFlags.PatchIssue,
			"--patchset", *checkoutFlags.PatchSet, // Note that this is the patchset "order", i.e. a positive integer.
			"--jobid", *buildbucketBuildID,
		}
		args = append(args, extraArgs...)
	}
	if err := goldctl(ctx, bzl, args...); err != nil {
		return err
	}

	// Add screenshots.
	fileInfos, err := os_steps.ReadDir(ctx, puppeteerScreenshotsDir)
	if err != nil {
		return err
	}
	err = td.Do(ctx, td.Props("Add images to goldctl"), func(ctx context.Context) error {
		for _, fileInfo := range fileInfos {
			testName := strings.TrimSuffix(filepath.Base(fileInfo.Name()), filepath.Ext(fileInfo.Name()))
			args := []string{
				"imgtest", "add",
				"--work-dir", goldctlWorkDir,
				"--png-file", filepath.Join(puppeteerScreenshotsDir, fileInfo.Name()),
				"--test-name", testName,
				"--add-test-optional-key", "build_system:bazel",
			}
			if err := goldctl(ctx, bzl, args...); err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		return err
	}

	// Finalize and upload screenshots to Gold.
	return goldctl(ctx, bzl, "imgtest", "finalize", "--work-dir", goldctlWorkDir)
}

func testOnRBE(ctx context.Context, bzl *bazel.Bazel) error {
	// Run all tests in the repository. The tryjob will fail upon any failing tests.
	if _, err := bzl.DoOnRBE(ctx, "test", "//...", "--test_output=errors"); err != nil {
		return err
	}

	// Upload to Gold all screenshots produced by Puppeteer tests in the previous step.
	return uploadPuppeteerScreenshotsToGold(ctx, bzl)
}

func testLocally(ctx context.Context, bzl *bazel.Bazel) (rvErr error) {
	// We skip the following steps when running on a developer's workstation because we assume that
	// the environment already has everything we need to run this task driver (the repository checkout
	// has a .git directory, the Go environment variables are properly set, etc.).
	if !*local {
		// Set up go.
		ctx = golang.WithEnv(ctx, workDir)

		// Check out depot_tools at the exact revision expected by tests (defined in recipes.cfg), and
		// make it available to tests by by adding it to the PATH.
		var depotToolsDir string
		err := td.Do(ctx, td.Props("Check out depot_tools"), func(ctx context.Context) error {
			var err error
			depotToolsDir, err = depot_tools.Sync(ctx, workDir, filepath.Join(gitDir.Dir(), recipe_cfg.RECIPE_CFG_PATH))
			return err
		})
		if err != nil {
			return err
		}
		ctx = td.WithEnv(ctx, []string{"PATH=%(PATH)s:" + depotToolsDir})
	}

	// Start the emulators. When running this task driver locally (e.g. with --local), this will kill
	// any existing emulator instances prior to launching all emulators.
	if err := emulators.StartAllEmulators(); err != nil {
		return err
	}
	defer func() {
		if err := emulators.StopAllEmulators(); err != nil {
			rvErr = err
		}
	}()
	time.Sleep(5 * time.Second) // Give emulators time to boot.

	// Set *_EMULATOR_HOST environment variables.
	emulatorHostEnvVars := []string{}
	for _, emulator := range emulators.AllEmulators {
		// We need to set the *_EMULATOR_HOST variable for the current emulator before we can retrieve
		// its value via emulators.GetEmulatorHostEnvVar().
		if err := emulators.SetEmulatorHostEnvVar(emulator); err != nil {
			return err
		}
		name := emulators.GetEmulatorHostEnvVarName(emulator)
		value := emulators.GetEmulatorHostEnvVar(emulator)
		emulatorHostEnvVars = append(emulatorHostEnvVars, fmt.Sprintf("%s=%s", name, value))
	}
	ctx = td.WithEnv(ctx, emulatorHostEnvVars)

	// Run all tests in the repository. The tryjob will fail upon any failing tests.
	_, err := bzl.DoOnRBE(ctx, "test", "//...", "--test_output=errors")
	return err
}
<commit_msg>Infra-PerCommit-Test-Bazel-Local: Fix bug.<commit_after>package main

import (
	"context"
	"flag"
	"fmt"
	"path"
	"path/filepath"
	"strings"
	"time"

	"go.skia.org/infra/go/depot_tools"
	"go.skia.org/infra/go/emulators"
	"go.skia.org/infra/go/git"
	"go.skia.org/infra/go/recipe_cfg"
	"go.skia.org/infra/task_driver/go/lib/bazel"
	"go.skia.org/infra/task_driver/go/lib/checkout"
	"go.skia.org/infra/task_driver/go/lib/golang"
	"go.skia.org/infra/task_driver/go/lib/os_steps"
	"go.skia.org/infra/task_driver/go/td"
)

var (
	// Required properties for this task.
	projectID          = flag.String("project_id", "", "ID of the Google Cloud project.")
	taskID             = flag.String("task_id", "", "ID of this task.")
	taskName           = flag.String("task_name", "", "Name of the task.")
	workDirFlag        = flag.String("workdir", ".", "Working directory.")
	buildbucketBuildID = flag.String("buildbucket_build_id", "", "ID of the Buildbucket build.")
	rbe                = flag.Bool("rbe", false, "Whether to run Bazel on RBE or locally.")
	rbeKey             = flag.String("rbe_key", "", "Path to the service account key to use for RBE.")

	checkoutFlags = checkout.SetupFlags(nil)

	// Optional flags.
	local  = flag.Bool("local", false, "True if running locally (as opposed to on the bots)")
	output = flag.String("o", "", "If provided, dump a JSON blob of step data to the given file. Prints to stdout if '-' is given.")

	// Various paths.
	workDir string

	gitDir *git.Checkout
)

func main() {
	// Setup.
	ctx := td.StartRun(projectID, taskID, taskName, output, local)
	defer td.EndRun(ctx)

	// Compute various directory paths.
	var err error
	workDir, err = os_steps.Abs(ctx, *workDirFlag)
	if err != nil {
		td.Fatal(ctx, err)
	}

	// Check out the code.
	repoState, err := checkout.GetRepoState(checkoutFlags)
	if err != nil {
		td.Fatal(ctx, err)
	}
	gitDir, err = checkout.EnsureGitCheckout(ctx, path.Join(workDir, "repo"), repoState)
	if err != nil {
		td.Fatal(ctx, err)
	}

	// Set up Bazel.
	bzl, bzlCleanup, err := bazel.New(ctx, gitDir.Dir(), *local, *rbeKey)
	if err != nil {
		td.Fatal(ctx, err)
	}
	defer bzlCleanup()

	// Print out the Bazel version for debugging purposes.
	if _, err := bzl.Do(ctx, "version"); err != nil {
		td.Fatal(ctx, err)
	}

	// Run the tests.
	if *rbe {
		if err := testOnRBE(ctx, bzl); err != nil {
			td.Fatal(ctx, err)
		}
	} else {
		if err := testLocally(ctx, bzl); err != nil {
			td.Fatal(ctx, err)
		}
	}
}

// goldctl invokes goldctl with the given arguments.
func goldctl(ctx context.Context, bzl *bazel.Bazel, args ...string) error {
	bazelCommand := []string{"//gold-client/cmd/goldctl", "--"}
	bazelCommand = append(bazelCommand, args...)
	_, err := bzl.Do(ctx, "run", bazelCommand...)
	return err
}

// uploadPuppeteerScreenshotsToGold gathers all screenshots produced by Puppeteer tests and uploads
// them to Gold.
func uploadPuppeteerScreenshotsToGold(ctx context.Context, bzl *bazel.Bazel) error {
	// Extract screenshots.
	puppeteerScreenshotsDir, err := os_steps.TempDir(ctx, "", "puppeteer-screenshots-*")
	if err != nil {
		return err
	}
	if _, err := bzl.Do(ctx, "run", "//:extract_puppeteer_screenshots", "--", "--output_dir", puppeteerScreenshotsDir); err != nil {
		return err
	}

	// Create working directory for goldctl.
	goldctlWorkDir, err := os_steps.TempDir(ctx, "", "goldctl-workdir-*")
	if err != nil {
		return err
	}

	// Authorize goldctl.
	if *local {
		if err := goldctl(ctx, bzl, "auth", "--work-dir", goldctlWorkDir); err != nil {
			return err
		}
	} else {
		if err := goldctl(ctx, bzl, "auth", "--work-dir", goldctlWorkDir, "--luci"); err != nil {
			return err
		}
	}

	// Initialize goldctl.
	args := []string{
		"imgtest", "init",
		"--work-dir", goldctlWorkDir,
		"--instance", "skia-infra",
		"--git_hash", *checkoutFlags.Revision,
		"--key", "source_type:infra",
	}
	if *checkoutFlags.PatchIssue != "" && *checkoutFlags.PatchSet != "" {
		extraArgs := []string{
			"--crs", "gerrit",
			"--cis", "buildbucket",
			"--changelist", *checkoutFlags.PatchIssue,
			"--patchset", *checkoutFlags.PatchSet, // Note that this is the patchset "order", i.e. a positive integer.
			"--jobid", *buildbucketBuildID,
		}
		args = append(args, extraArgs...)
	}
	if err := goldctl(ctx, bzl, args...); err != nil {
		return err
	}

	// Add screenshots.
	fileInfos, err := os_steps.ReadDir(ctx, puppeteerScreenshotsDir)
	if err != nil {
		return err
	}
	err = td.Do(ctx, td.Props("Add images to goldctl"), func(ctx context.Context) error {
		for _, fileInfo := range fileInfos {
			testName := strings.TrimSuffix(filepath.Base(fileInfo.Name()), filepath.Ext(fileInfo.Name()))
			args := []string{
				"imgtest", "add",
				"--work-dir", goldctlWorkDir,
				"--png-file", filepath.Join(puppeteerScreenshotsDir, fileInfo.Name()),
				"--test-name", testName,
				"--add-test-optional-key", "build_system:bazel",
			}
			if err := goldctl(ctx, bzl, args...); err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		return err
	}

	// Finalize and upload screenshots to Gold.
	return goldctl(ctx, bzl, "imgtest", "finalize", "--work-dir", goldctlWorkDir)
}

func testOnRBE(ctx context.Context, bzl *bazel.Bazel) error {
	// Run all tests in the repository. The tryjob will fail upon any failing tests.
	if _, err := bzl.DoOnRBE(ctx, "test", "//...", "--test_output=errors"); err != nil {
		return err
	}

	// Upload to Gold all screenshots produced by Puppeteer tests in the previous step.
	return uploadPuppeteerScreenshotsToGold(ctx, bzl)
}

func testLocally(ctx context.Context, bzl *bazel.Bazel) (rvErr error) {
	// We skip the following steps when running on a developer's workstation because we assume that
	// the environment already has everything we need to run this task driver (the repository checkout
	// has a .git directory, the Go environment variables are properly set, etc.).
	if !*local {
		// Set up go.
		ctx = golang.WithEnv(ctx, workDir)

		// Check out depot_tools at the exact revision expected by tests (defined in recipes.cfg), and
		// make it available to tests by by adding it to the PATH.
		var depotToolsDir string
		err := td.Do(ctx, td.Props("Check out depot_tools"), func(ctx context.Context) error {
			var err error
			depotToolsDir, err = depot_tools.Sync(ctx, workDir, filepath.Join(gitDir.Dir(), recipe_cfg.RECIPE_CFG_PATH))
			return err
		})
		if err != nil {
			return err
		}
		ctx = td.WithEnv(ctx, []string{"PATH=%(PATH)s:" + depotToolsDir})
	}

	// Start the emulators. When running this task driver locally (e.g. with --local), this will kill
	// any existing emulator instances prior to launching all emulators.
	if err := emulators.StartAllEmulators(); err != nil {
		return err
	}
	defer func() {
		if err := emulators.StopAllEmulators(); err != nil {
			rvErr = err
		}
	}()
	time.Sleep(5 * time.Second) // Give emulators time to boot.

	// Set *_EMULATOR_HOST environment variables.
	emulatorHostEnvVars := []string{}
	for _, emulator := range emulators.AllEmulators {
		// We need to set the *_EMULATOR_HOST variable for the current emulator before we can retrieve
		// its value via emulators.GetEmulatorHostEnvVar().
		if err := emulators.SetEmulatorHostEnvVar(emulator); err != nil {
			return err
		}
		name := emulators.GetEmulatorHostEnvVarName(emulator)
		value := emulators.GetEmulatorHostEnvVar(emulator)
		emulatorHostEnvVars = append(emulatorHostEnvVars, fmt.Sprintf("%s=%s", name, value))
	}
	ctx = td.WithEnv(ctx, emulatorHostEnvVars)

	// Run all tests in the repository. The tryjob will fail upon any failing tests.
	_, err := bzl.Do(ctx, "test", "//...", "--test_output=errors")
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/martinlindhe/imgcat"
	"gopkg.in/alecthomas/kingpin.v2"
)

var (
	file = kingpin.Arg("file", "A image file.").Required().File()
)

func main() {
	// support -h for --help
	kingpin.CommandLine.HelpFlag.Short('h')
	kingpin.Parse()

	inFileName := (*file).Name()

	imgcat.CatImage(inFileName)
}
<commit_msg>cli: cat all images that is specified as parameters<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/martinlindhe/imgcat"

	"gopkg.in/alecthomas/kingpin.v2"
)

type fileList []string

// exists reports whether the named file or directory exists.
func exists(name string) bool {
	if _, err := os.Stat(name); err != nil {
		if os.IsNotExist(err) {
			return false
		}
	}
	return true
}

func (i *fileList) Set(value string) error {

	if !exists(value) {
		return fmt.Errorf("'%s' does not exist", value)
	}
	*i = append(*i, value)
	return nil
}

func (i *fileList) String() string {
	return ""
}

func (i *fileList) IsCumulative() bool {
	return true
}

func ImageList(s kingpin.Settings) (target *[]string) {
	target = new([]string)
	s.SetValue((*fileList)(target))
	return
}

var (
	files   = ImageList(kingpin.Arg("files", "Image files to show."))
	verbose = kingpin.Flag("verbose", "Verbose mode.").Short('v').Bool()
)

func main() {
	// support -h for --help
	kingpin.CommandLine.HelpFlag.Short('h')
	kingpin.Parse()

	heading := false
	if len(*files) > 1 && *verbose {
		heading = true
	}

	for _, file := range *files {
		if heading {
			fmt.Printf("%s:\n", file)
		}
		imgcat.CatImage(file)
	}
}
<|endoftext|>


<commit_before>package xmmsclient

import (
	"bytes"
	"encoding/binary"
	"errors"
	"io"
	"net"
)

type context struct {
	result     chan []byte
	sequenceNr uint32
	broadcast  bool
}

type header struct {
	objectId   uint32
	commandId  uint32
	sequenceNr uint32
	length     uint32
}

type message struct {
	header    header
	broadcast bool
	args      XmmsValue
	result    chan []byte
}

type reply struct {
	sequenceNr uint32
	payload    []byte
}

type Client struct {
	sequenceNr uint32
	clientName string
	clientId   int

	shutdownRegistry chan bool
	shutdownIO       chan bool
	registry         chan message
}

func parseHeader(buf *bytes.Buffer) (*header, error) {
	var hdr header

	err := binary.Read(buf, binary.BigEndian, &hdr.objectId)
	if err != nil {
		return nil, err
	}

	err = binary.Read(buf, binary.BigEndian, &hdr.commandId)
	if err != nil {
		return nil, err
	}

	err = binary.Read(buf, binary.BigEndian, &hdr.sequenceNr)
	if err != nil {
		return nil, err
	}

	err = binary.Read(buf, binary.BigEndian, &hdr.length)
	if err != nil {
		return nil, err
	}

	return &hdr, nil
}

func writeHeader(w io.ReadWriteCloser, hdr *header) error {
	err := binary.Write(w, binary.BigEndian, hdr.objectId)
	if err != nil {
		return err
	}

	err = binary.Write(w, binary.BigEndian, hdr.commandId)
	if err != nil {
		return err
	}

	err = binary.Write(w, binary.BigEndian, hdr.sequenceNr)
	if err != nil {
		return err
	}

	err = binary.Write(w, binary.BigEndian, hdr.length)
	if err != nil {
		return err
	}

	return nil
}

func (c *Client) nextSequenceNr() uint32 {
	c.sequenceNr += 1
	return c.sequenceNr
}

func (c *Client) reader(conn *net.TCPConn, inbound chan reply, errors chan error) {
	var buffer = make([]byte, 16)

	for {
		_, err := io.ReadFull(conn, buffer)
		if err != nil {
			errors <- err
			break
		}

		header, err := parseHeader(bytes.NewBuffer(buffer))
		if err != nil {
			errors <- err
			break
		}

		payload := make([]byte, header.length)

		_, err = io.ReadFull(conn, payload)
		if err != nil {
			errors <- err
			break
		}

		inbound <- reply{header.sequenceNr, payload}
	}
}

func (c *Client) writer(conn *net.TCPConn, outbound chan message, errors chan error) {
writer:
	for {
		select {
		case msg := <-outbound:
			var payload bytes.Buffer

			err := serializeXmmsValue(msg.args, &payload)
			if err != nil {
				errors <- err
				break writer
			}

			msg.header.length = uint32(len(payload.Bytes()))

			err = writeHeader(conn, &msg.header)
			if err != nil {
				errors <- err
				break writer
			}

			payload.WriteTo(conn)
			if err != nil {
				errors <- err
				break writer
			}
		case <-c.shutdownIO:
			break writer
		}
	}

	// TODO: Probably a better place for this.
	conn.Close()
}

func errorToBytes(err string) []byte {
	var payload bytes.Buffer
	serializeXmmsValue(XmmsError(err), &payload)
	return payload.Bytes()
}

func (c *Client) router(inbound chan reply, outbound chan message, errors chan error) {
	var registry = make(map[uint32](context))

router:
	for {
		select {
		case msg := <-c.registry:
			msg.header.sequenceNr = c.nextSequenceNr()
			registry[msg.header.sequenceNr] = context{
				msg.result,
				msg.header.sequenceNr,
				msg.broadcast,
			}
			outbound <- msg
		case reply := <-inbound:
			ctx := registry[reply.sequenceNr]
			go func() {
				ctx.result <- reply.payload
			}()
			if !ctx.broadcast {
				delete(registry, ctx.sequenceNr)
			}
		case err := <-errors:
			payload := errorToBytes(err.Error())
			for _, v := range registry {
				v.result <- payload
			}
			break router
		case <-c.shutdownRegistry:
			payload := errorToBytes(io.EOF.Error())
			for _, v := range registry {
				v.result <- payload
			}
			break router
		}
	}
}

func (c *Client) dispatch(objectId uint32, commandId uint32, args XmmsValue) chan []byte {
	result := make(chan []byte)
	c.registry <- message{
		header: header{
			objectId:  objectId,
			commandId: commandId,
		},
		broadcast: objectId == 0,
		args:      args,
		result:    result,
	}
	return result
}

func (c *Client) Dial(url string) error {
	addr, err := net.ResolveTCPAddr("tcp", url)
	if err != nil {
		return err
	}

	conn, err := net.DialTCP("tcp", nil, addr)
	if err != nil {
		return err
	}

	c.shutdownRegistry = make(chan bool)
	c.shutdownIO = make(chan bool)
	c.registry = make(chan message)

	errors := make(chan error)
	inbound := make(chan reply)
	outbound := make(chan message)

	go c.reader(conn, inbound, errors)
	go c.writer(conn, outbound, errors)
	go c.router(inbound, outbound, errors)

	clientId, err := c.MainHello(24, c.clientName)
	if err != nil {
		return err
	}

	c.clientId = int(clientId)

	return nil
}

func (c *Client) ClientId() (int, error) {
	if c.clientId == -1 {
		return -1, errors.New("Client Id not initialized.")
	}
	return c.clientId, nil
}

func (c *Client) Close() {
	c.shutdownRegistry <- true
	c.shutdownIO <- true
	c.clientId = -1
}

func NewClient(name string) *Client {
	client := Client{
		clientId:   -1,
		clientName: name,
	}

	return &client
}
<commit_msg>Be more strict about socket interfaces passed around.<commit_after>package xmmsclient

import (
	"bytes"
	"encoding/binary"
	"errors"
	"io"
	"net"
)

type context struct {
	result     chan []byte
	sequenceNr uint32
	broadcast  bool
}

type header struct {
	objectId   uint32
	commandId  uint32
	sequenceNr uint32
	length     uint32
}

type message struct {
	header    header
	broadcast bool
	args      XmmsValue
	result    chan []byte
}

type reply struct {
	sequenceNr uint32
	payload    []byte
}

type Client struct {
	sequenceNr uint32
	clientName string
	clientId   int

	shutdownRegistry chan bool
	shutdownIO       chan bool
	registry         chan message
}

func parseHeader(buf *bytes.Buffer) (*header, error) {
	var hdr header

	err := binary.Read(buf, binary.BigEndian, &hdr.objectId)
	if err != nil {
		return nil, err
	}

	err = binary.Read(buf, binary.BigEndian, &hdr.commandId)
	if err != nil {
		return nil, err
	}

	err = binary.Read(buf, binary.BigEndian, &hdr.sequenceNr)
	if err != nil {
		return nil, err
	}

	err = binary.Read(buf, binary.BigEndian, &hdr.length)
	if err != nil {
		return nil, err
	}

	return &hdr, nil
}

func writeHeader(w io.Writer, hdr *header) error {
	err := binary.Write(w, binary.BigEndian, hdr.objectId)
	if err != nil {
		return err
	}

	err = binary.Write(w, binary.BigEndian, hdr.commandId)
	if err != nil {
		return err
	}

	err = binary.Write(w, binary.BigEndian, hdr.sequenceNr)
	if err != nil {
		return err
	}

	err = binary.Write(w, binary.BigEndian, hdr.length)
	if err != nil {
		return err
	}

	return nil
}

func (c *Client) nextSequenceNr() uint32 {
	c.sequenceNr += 1
	return c.sequenceNr
}

func (c *Client) reader(conn io.Reader, inbound chan reply, errors chan error) {
	var buffer = make([]byte, 16)

	for {
		_, err := io.ReadFull(conn, buffer)
		if err != nil {
			errors <- err
			break
		}

		header, err := parseHeader(bytes.NewBuffer(buffer))
		if err != nil {
			errors <- err
			break
		}

		payload := make([]byte, header.length)

		_, err = io.ReadFull(conn, payload)
		if err != nil {
			errors <- err
			break
		}

		inbound <- reply{header.sequenceNr, payload}
	}
}

func (c *Client) writer(conn io.Writer, outbound chan message, errors chan error) {
writer:
	for {
		select {
		case msg := <-outbound:
			var payload bytes.Buffer

			err := serializeXmmsValue(msg.args, &payload)
			if err != nil {
				errors <- err
				break writer
			}

			msg.header.length = uint32(len(payload.Bytes()))

			err = writeHeader(conn, &msg.header)
			if err != nil {
				errors <- err
				break writer
			}

			payload.WriteTo(conn)
			if err != nil {
				errors <- err
				break writer
			}
		case <-c.shutdownIO:
			break writer
		}
	}
}

func errorToBytes(err string) []byte {
	var payload bytes.Buffer
	serializeXmmsValue(XmmsError(err), &payload)
	return payload.Bytes()
}

func (c *Client) router(inbound chan reply, outbound chan message, errors chan error) {
	var registry = make(map[uint32](context))

router:
	for {
		select {
		case msg := <-c.registry:
			msg.header.sequenceNr = c.nextSequenceNr()
			registry[msg.header.sequenceNr] = context{
				msg.result,
				msg.header.sequenceNr,
				msg.broadcast,
			}
			outbound <- msg
		case reply := <-inbound:
			ctx := registry[reply.sequenceNr]
			go func() {
				ctx.result <- reply.payload
			}()
			if !ctx.broadcast {
				delete(registry, ctx.sequenceNr)
			}
		case err := <-errors:
			payload := errorToBytes(err.Error())
			for _, v := range registry {
				v.result <- payload
			}
			break router
		case <-c.shutdownRegistry:
			payload := errorToBytes(io.EOF.Error())
			for _, v := range registry {
				v.result <- payload
			}
			break router
		}
	}
}

func (c *Client) dispatch(objectId uint32, commandId uint32, args XmmsValue) chan []byte {
	result := make(chan []byte)
	c.registry <- message{
		header: header{
			objectId:  objectId,
			commandId: commandId,
		},
		broadcast: objectId == 0,
		args:      args,
		result:    result,
	}
	return result
}

func (c *Client) Dial(url string) error {
	addr, err := net.ResolveTCPAddr("tcp", url)
	if err != nil {
		return err
	}

	conn, err := net.DialTCP("tcp", nil, addr)
	if err != nil {
		return err
	}

	c.shutdownRegistry = make(chan bool)
	c.shutdownIO = make(chan bool)
	c.registry = make(chan message)

	errors := make(chan error)
	inbound := make(chan reply)
	outbound := make(chan message)

	go c.reader(conn, inbound, errors)
	go c.writer(conn, outbound, errors)
	go c.router(inbound, outbound, errors)

	clientId, err := c.MainHello(24, c.clientName)
	if err != nil {
		return err
	}

	c.clientId = int(clientId)

	return nil
}

func (c *Client) ClientId() (int, error) {
	if c.clientId == -1 {
		return -1, errors.New("Client Id not initialized.")
	}
	return c.clientId, nil
}

func (c *Client) Close() {
	c.shutdownRegistry <- true
	c.shutdownIO <- true
	c.clientId = -1
}

func NewClient(name string) *Client {
	client := Client{
		clientId:   -1,
		clientName: name,
	}

	return &client
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The cert-manager 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 gen

import (
	"time"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"

	v1 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
	cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
)

type CertificateModifier func(*v1.Certificate)

func Certificate(name string, mods ...CertificateModifier) *v1.Certificate {
	c := &v1.Certificate{
		ObjectMeta: ObjectMeta(name),
		Spec: v1.CertificateSpec{
			PrivateKey: &v1.CertificatePrivateKey{},
		},
	}
	for _, mod := range mods {
		mod(c)
	}
	return c
}

func CertificateFrom(crt *v1.Certificate, mods ...CertificateModifier) *v1.Certificate {
	crt = crt.DeepCopy()
	for _, mod := range mods {
		mod(crt)
	}
	return crt
}

// SetIssuer sets the Certificate.spec.issuerRef field
func SetCertificateIssuer(o cmmeta.ObjectReference) CertificateModifier {
	return func(c *v1.Certificate) {
		c.Spec.IssuerRef = o
	}
}

func SetCertificateDNSNames(dnsNames ...string) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.DNSNames = dnsNames
	}
}

func SetCertificateCommonName(commonName string) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.CommonName = commonName
	}
}

func SetCertificateIPs(ips ...string) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.IPAddresses = ips
	}
}

func SetCertificateURIs(uris ...string) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.URIs = uris
	}
}

func SetCertificateIsCA(isCA bool) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.IsCA = isCA
	}
}

func SetCertificateKeyAlgorithm(keyAlgorithm v1.PrivateKeyAlgorithm) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.PrivateKey.Algorithm = keyAlgorithm
	}
}

func SetCertificateKeySize(keySize int) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.PrivateKey.Size = keySize
	}
}

func SetCertificateKeyEncoding(keyEncoding v1.PrivateKeyEncoding) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.PrivateKey.Encoding = keyEncoding
	}
}

func SetCertificateSecretName(secretName string) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.SecretName = secretName
	}
}

func SetCertificateDuration(duration time.Duration) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.Duration = &metav1.Duration{Duration: duration}
	}
}

func SetCertificateRenewBefore(renewBefore time.Duration) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.RenewBefore = &metav1.Duration{Duration: renewBefore}
	}
}

func SetCertificateNextPrivateKeySecretName(name string) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Status.NextPrivateKeySecretName = &name
	}
}

func SetCertificateStatusCondition(c v1.CertificateCondition) CertificateModifier {
	return func(crt *v1.Certificate) {
		if len(crt.Status.Conditions) == 0 {
			crt.Status.Conditions = []v1.CertificateCondition{c}
			return
		}
		for i, existingC := range crt.Status.Conditions {
			if existingC.Type == c.Type {
				crt.Status.Conditions[i] = c
				return
			}
		}
		crt.Status.Conditions = append(crt.Status.Conditions, c)
	}
}

func SetCertificateLastFailureTime(p metav1.Time) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Status.LastFailureTime = &p
	}
}

func SetCertificateNotAfter(p metav1.Time) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Status.NotAfter = &p
	}
}

func SetCertificateNotBefore(p metav1.Time) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Status.NotBefore = &p
	}
}

func SetCertificateRenewalTIme(p metav1.Time) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Status.RenewalTime = &p
	}
}

func SetCertificateOrganization(orgs ...string) CertificateModifier {
	return func(ch *v1.Certificate) {
		ch.Spec.Subject.Organizations = orgs
	}
}

func SetCertificateNamespace(namespace string) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.ObjectMeta.Namespace = namespace
	}
}

func SetCertificateKeyUsages(usages ...v1.KeyUsage) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.Usages = usages
	}
}

func SetCertificateRevision(revision int) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Status.Revision = &revision
	}
}

func SetCertificateUID(uid types.UID) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.UID = uid
	}
}

func SetCertificateGeneration(gen int64) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Generation = gen
	}
}

func AddCertificateAnnotations(annotations map[string]string) CertificateModifier {
	return func(crt *v1.Certificate) {
		if crt.Annotations == nil {
			crt.Annotations = make(map[string]string)
		}

		for k, v := range annotations {
			crt.Annotations[k] = v
		}
	}
}

func AddCertificateLabels(labels map[string]string) CertificateModifier {
	return func(crt *v1.Certificate) {
		if crt.Labels == nil {
			crt.Labels = make(map[string]string)
		}
		for k, v := range labels {
			crt.Labels[k] = v
		}
	}
}

// CertificateRef creates an owner reference for a certificate without
// having to give the full certificate.
func CertificateRef(certName, ownedUID string) metav1.OwnerReference {
	return *metav1.NewControllerRef(
		Certificate(certName,
			SetCertificateUID(types.UID(ownedUID)),
		),
		v1.SchemeGroupVersion.WithKind("Certificate"),
	)
}

func SetCertificateRevisionHistoryLimit(limit int32) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.RevisionHistoryLimit = &limit
	}
}
<commit_msg><commit_after>/*
Copyright 2020 The cert-manager 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 gen

import (
	"time"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"

	v1 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
	cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
)

type CertificateModifier func(*v1.Certificate)

func Certificate(name string, mods ...CertificateModifier) *v1.Certificate {
	c := &v1.Certificate{
		ObjectMeta: ObjectMeta(name),
		Spec: v1.CertificateSpec{
			PrivateKey: &v1.CertificatePrivateKey{},
		},
	}
	for _, mod := range mods {
		mod(c)
	}
	return c
}

func CertificateFrom(crt *v1.Certificate, mods ...CertificateModifier) *v1.Certificate {
	crt = crt.DeepCopy()
	for _, mod := range mods {
		mod(crt)
	}
	return crt
}

// SetIssuer sets the Certificate.spec.issuerRef field
func SetCertificateIssuer(o cmmeta.ObjectReference) CertificateModifier {
	return func(c *v1.Certificate) {
		c.Spec.IssuerRef = o
	}
}

func SetCertificateDNSNames(dnsNames ...string) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.DNSNames = dnsNames
	}
}

func SetCertificateCommonName(commonName string) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.CommonName = commonName
	}
}

func SetCertificateIPs(ips ...string) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.IPAddresses = ips
	}
}

func SetCertificateURIs(uris ...string) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.URIs = uris
	}
}

func SetCertificateIsCA(isCA bool) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.IsCA = isCA
	}
}

func SetCertificateKeyAlgorithm(keyAlgorithm v1.PrivateKeyAlgorithm) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.PrivateKey.Algorithm = keyAlgorithm
	}
}

func SetCertificateKeySize(keySize int) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.PrivateKey.Size = keySize
	}
}

func SetCertificateKeyEncoding(keyEncoding v1.PrivateKeyEncoding) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.PrivateKey.Encoding = keyEncoding
	}
}

func SetCertificateSecretName(secretName string) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.SecretName = secretName
	}
}

func SetCertificateDuration(duration time.Duration) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.Duration = &metav1.Duration{Duration: duration}
	}
}

func SetCertificateRenewBefore(renewBefore time.Duration) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.RenewBefore = &metav1.Duration{Duration: renewBefore}
	}
}

func SetCertificateNextPrivateKeySecretName(name string) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Status.NextPrivateKeySecretName = &name
	}
}

func SetCertificateStatusCondition(c v1.CertificateCondition) CertificateModifier {
	return func(crt *v1.Certificate) {
		if len(crt.Status.Conditions) == 0 {
			crt.Status.Conditions = []v1.CertificateCondition{c}
			return
		}
		for i, existingC := range crt.Status.Conditions {
			if existingC.Type == c.Type {
				crt.Status.Conditions[i] = c
				return
			}
		}
		crt.Status.Conditions = append(crt.Status.Conditions, c)
	}
}

func SetCertificateLastFailureTime(p metav1.Time) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Status.LastFailureTime = &p
	}
}

func SetCertificateNotAfter(p metav1.Time) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Status.NotAfter = &p
	}
}

func SetCertificateNotBefore(p metav1.Time) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Status.NotBefore = &p
	}
}

func SetCertificateRenewalTIme(p metav1.Time) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Status.RenewalTime = &p
	}
}

func SetCertificateOrganization(orgs ...string) CertificateModifier {
	return func(ch *v1.Certificate) {
		ch.Spec.Subject.Organizations = orgs
	}
}

func SetCertificateNamespace(namespace string) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.ObjectMeta.Namespace = namespace
	}
}

func SetCertificateKeyUsages(usages ...v1.KeyUsage) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.Usages = usages
	}
}

func SetCertificateRevision(revision int) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Status.Revision = &revision
	}
}

func SetCertificateUID(uid types.UID) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.UID = uid
	}
}

func SetCertificateGeneration(gen int64) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Generation = gen
	}
}

func AddCertificateAnnotations(annotations map[string]string) CertificateModifier {
	return func(crt *v1.Certificate) {
		if crt.Annotations == nil {
			crt.Annotations = make(map[string]string)
		}

		for k, v := range annotations {
			crt.Annotations[k] = v
		}
	}
}

func AddCertificateLabels(labels map[string]string) CertificateModifier {
	return func(crt *v1.Certificate) {
		if crt.Labels == nil {
			crt.Labels = make(map[string]string)
		}
		for k, v := range labels {
			crt.Labels[k] = v
		}
	}
}

// CertificateRef creates an owner reference for a certificate without having to
// give the full certificate. Only use this function for testing purposes.
//
// Note that the only "important" field that must be filled in ownerReference
// [1] is the UID. Must notably, the IsControlledBy function [2] only cares
// about the UID. The apiVersion, kind and name are only used for information
// purposes.
//
//  [1]: https://github.com/kubernetes/apimachinery/blob/10b3882/pkg/apis/meta/v1/types.go#L273-L275
//  [2]: https://github.com/kubernetes/apimachinery/blob/10b3882/pkg/apis/meta/v1/controller_ref.go#L29
func CertificateRef(certName, certUID string) metav1.OwnerReference {
	return *metav1.NewControllerRef(
		Certificate(certName,
			SetCertificateUID(types.UID(certUID)),
		),
		v1.SchemeGroupVersion.WithKind("Certificate"),
	)
}

func SetCertificateRevisionHistoryLimit(limit int32) CertificateModifier {
	return func(crt *v1.Certificate) {
		crt.Spec.RevisionHistoryLimit = &limit
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Arista Networks, Inc.
// Use of this source code is governed by the Apache License 2.0
// that can be found in the COPYING file.

package gnmi

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"path"

	pb "github.com/openconfig/gnmi/proto/gnmi"
	"google.golang.org/grpc/codes"
)

// Get sents a GetRequest to the given client.
func Get(ctx context.Context, client pb.GNMIClient, paths [][]string) error {
	req, err := NewGetRequest(paths)
	if err != nil {
		return err
	}
	resp, err := client.Get(ctx, req)
	if err != nil {
		return err
	}
	for _, notif := range resp.Notification {
		for _, update := range notif.Update {
			fmt.Printf("%s:\n", StrPath(update.Path))
			fmt.Println(strUpdateVal(update))
		}
	}
	return nil
}

// Capabilities retuns the capabilities of the client.
func Capabilities(ctx context.Context, client pb.GNMIClient) error {
	resp, err := client.Capabilities(ctx, &pb.CapabilityRequest{})
	if err != nil {
		return err
	}
	fmt.Printf("Version: %s\n", resp.GNMIVersion)
	for _, mod := range resp.SupportedModels {
		fmt.Printf("SupportedModel: %s\n", mod)
	}
	for _, enc := range resp.SupportedEncodings {
		fmt.Printf("SupportedEncoding: %s\n", enc)
	}
	return nil
}

// val may be a path to a file or it may be json. First see if it is a
// file, if so return its contents, otherwise return val
func extractJSON(val string) []byte {
	jsonBytes, err := ioutil.ReadFile(val)
	if err != nil {
		jsonBytes = []byte(val)
	}
	return jsonBytes
}

// strUpdateVal will return a string representing the value within the supplied update
func strUpdateVal(u *pb.Update) string {
	if u.Value != nil {
		return string(u.Value.Value) // Backwards compatibility with pre-v0.4 gnmi
	}
	return strVal(u.Val)
}

// strVal will return a string representing the supplied value
func strVal(val *pb.TypedValue) string {
	switch v := val.GetValue().(type) {
	case *pb.TypedValue_StringVal:
		return v.StringVal
	case *pb.TypedValue_JsonIetfVal:
		return string(v.JsonIetfVal)
	case *pb.TypedValue_IntVal:
		return fmt.Sprintf("%v", v.IntVal)
	case *pb.TypedValue_UintVal:
		return fmt.Sprintf("%v", v.UintVal)
	case *pb.TypedValue_BoolVal:
		return fmt.Sprintf("%v", v.BoolVal)
	case *pb.TypedValue_BytesVal:
		return string(v.BytesVal)
	case *pb.TypedValue_DecimalVal:
		return strDecimal64(v.DecimalVal)
	case *pb.TypedValue_LeaflistVal:
		return strLeaflist(v.LeaflistVal)
	default:
		panic(v)
	}
}

func strDecimal64(d *pb.Decimal64) string {
	var i, frac uint64
	if d.Precision > 0 {
		div := uint64(10)
		it := d.Precision - 1
		for it > 0 {
			div *= 10
			it--
		}
		i = d.Digits / div
		frac = d.Digits % div
	} else {
		i = d.Digits
	}
	return fmt.Sprintf("%d.%d", i, frac)
}

// strLeafList builds a human-readable form of a leaf-list. e.g. [1,2,3] or [a,b,c]
func strLeaflist(v *pb.ScalarArray) string {
	s := make([]string, 0, len(v.Element))
	sz := 2 // []

	// convert arbitrary TypedValues to string form
	for _, elm := range v.Element {
		str := strVal(elm)
		s = append(s, str)
		sz += len(str) + 1 // %v + ,
	}

	b := make([]byte, sz)
	buf := bytes.NewBuffer(b)

	buf.WriteRune('[')
	for i := range v.Element {
		buf.WriteString(s[i])
		if i < len(v.Element)-1 {
			buf.WriteRune(',')
		}
	}
	buf.WriteRune(']')
	return buf.String()
}

func update(p *pb.Path, val string) *pb.Update {
	var v *pb.TypedValue
	switch p.Origin {
	case "":
		v = &pb.TypedValue{
			Value: &pb.TypedValue_JsonIetfVal{JsonIetfVal: extractJSON(val)}}
	case "cli":
		v = &pb.TypedValue{
			Value: &pb.TypedValue_AsciiVal{AsciiVal: val}}
	default:
		panic(fmt.Errorf("unexpected origin: %q", p.Origin))
	}

	return &pb.Update{Path: p, Val: v}
}

// Operation describes an gNMI operation.
type Operation struct {
	Type string
	Path []string
	Val  string
}

func newSetRequest(setOps []*Operation) (*pb.SetRequest, error) {
	req := &pb.SetRequest{}
	for _, op := range setOps {
		p, err := ParseGNMIElements(op.Path)
		if err != nil {
			return nil, err
		}

		switch op.Type {
		case "delete":
			req.Delete = append(req.Delete, p)
		case "update":
			req.Update = append(req.Update, update(p, op.Val))
		case "replace":
			req.Replace = append(req.Replace, update(p, op.Val))
		}
	}
	return req, nil
}

// Set sends a SetRequest to the given client.
func Set(ctx context.Context, client pb.GNMIClient, setOps []*Operation) error {
	req, err := newSetRequest(setOps)
	if err != nil {
		return err
	}
	resp, err := client.Set(ctx, req)
	if err != nil {
		return err
	}
	if resp.Message != nil && codes.Code(resp.Message.Code) != codes.OK {
		return errors.New(resp.Message.Message)
	}
	// TODO: Iterate over SetResponse.Response for more detailed error message?

	return nil
}

// Subscribe sends a SubscribeRequest to the given client.
func Subscribe(ctx context.Context, client pb.GNMIClient, paths [][]string,
	respChan chan<- *pb.SubscribeResponse, errChan chan<- error) {
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()
	stream, err := client.Subscribe(ctx)
	if err != nil {
		errChan <- err
		return
	}
	req, err := NewSubscribeRequest(paths)
	if err != nil {
		errChan <- err
		return
	}
	if err := stream.Send(req); err != nil {
		errChan <- err
		return
	}

	for {
		resp, err := stream.Recv()
		if err != nil {
			if err == io.EOF {
				return
			}
			errChan <- err
			return
		}
		respChan <- resp
	}
}

// LogSubscribeResponse logs update responses to stderr.
func LogSubscribeResponse(response *pb.SubscribeResponse) error {
	switch resp := response.Response.(type) {
	case *pb.SubscribeResponse_Error:
		return errors.New(resp.Error.Message)
	case *pb.SubscribeResponse_SyncResponse:
		if !resp.SyncResponse {
			return errors.New("initial sync failed")
		}
	case *pb.SubscribeResponse_Update:
		prefix := StrPath(resp.Update.Prefix)
		for _, update := range resp.Update.Update {
			fmt.Printf("%s = %s\n", path.Join(prefix, StrPath(update.Path)),
				strUpdateVal(update))
		}
	}
	return nil
}
<commit_msg>gnmi: Add support for missing types in strVal<commit_after>// Copyright (c) 2017 Arista Networks, Inc.
// Use of this source code is governed by the Apache License 2.0
// that can be found in the COPYING file.

package gnmi

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"path"

	pb "github.com/openconfig/gnmi/proto/gnmi"
	"google.golang.org/grpc/codes"
)

// Get sents a GetRequest to the given client.
func Get(ctx context.Context, client pb.GNMIClient, paths [][]string) error {
	req, err := NewGetRequest(paths)
	if err != nil {
		return err
	}
	resp, err := client.Get(ctx, req)
	if err != nil {
		return err
	}
	for _, notif := range resp.Notification {
		for _, update := range notif.Update {
			fmt.Printf("%s:\n", StrPath(update.Path))
			fmt.Println(strUpdateVal(update))
		}
	}
	return nil
}

// Capabilities retuns the capabilities of the client.
func Capabilities(ctx context.Context, client pb.GNMIClient) error {
	resp, err := client.Capabilities(ctx, &pb.CapabilityRequest{})
	if err != nil {
		return err
	}
	fmt.Printf("Version: %s\n", resp.GNMIVersion)
	for _, mod := range resp.SupportedModels {
		fmt.Printf("SupportedModel: %s\n", mod)
	}
	for _, enc := range resp.SupportedEncodings {
		fmt.Printf("SupportedEncoding: %s\n", enc)
	}
	return nil
}

// val may be a path to a file or it may be json. First see if it is a
// file, if so return its contents, otherwise return val
func extractJSON(val string) []byte {
	jsonBytes, err := ioutil.ReadFile(val)
	if err != nil {
		jsonBytes = []byte(val)
	}
	return jsonBytes
}

// strUpdateVal will return a string representing the value within the supplied update
func strUpdateVal(u *pb.Update) string {
	if u.Value != nil {
		return string(u.Value.Value) // Backwards compatibility with pre-v0.4 gnmi
	}
	return strVal(u.Val)
}

// strVal will return a string representing the supplied value
func strVal(val *pb.TypedValue) string {
	switch v := val.GetValue().(type) {
	case *pb.TypedValue_StringVal:
		return v.StringVal
	case *pb.TypedValue_JsonIetfVal:
		return string(v.JsonIetfVal)
	case *pb.TypedValue_JsonVal:
		return string(v.JsonVal)
	case *pb.TypedValue_IntVal:
		return fmt.Sprintf("%v", v.IntVal)
	case *pb.TypedValue_UintVal:
		return fmt.Sprintf("%v", v.UintVal)
	case *pb.TypedValue_BoolVal:
		return fmt.Sprintf("%v", v.BoolVal)
	case *pb.TypedValue_BytesVal:
		return string(v.BytesVal)
	case *pb.TypedValue_DecimalVal:
		return strDecimal64(v.DecimalVal)
	case *pb.TypedValue_FloatVal:
		return fmt.Sprintf("%v", v.FloatVal)
	case *pb.TypedValue_LeaflistVal:
		return strLeaflist(v.LeaflistVal)
	case *pb.TypedValue_AsciiVal:
		return v.AsciiVal
	case *pb.TypedValue_AnyVal:
		return v.AnyVal.String()
	default:
		panic(v)
	}
}

func strDecimal64(d *pb.Decimal64) string {
	var i, frac uint64
	if d.Precision > 0 {
		div := uint64(10)
		it := d.Precision - 1
		for it > 0 {
			div *= 10
			it--
		}
		i = d.Digits / div
		frac = d.Digits % div
	} else {
		i = d.Digits
	}
	return fmt.Sprintf("%d.%d", i, frac)
}

// strLeafList builds a human-readable form of a leaf-list. e.g. [1,2,3] or [a,b,c]
func strLeaflist(v *pb.ScalarArray) string {
	s := make([]string, 0, len(v.Element))
	sz := 2 // []

	// convert arbitrary TypedValues to string form
	for _, elm := range v.Element {
		str := strVal(elm)
		s = append(s, str)
		sz += len(str) + 1 // %v + ,
	}

	b := make([]byte, sz)
	buf := bytes.NewBuffer(b)

	buf.WriteRune('[')
	for i := range v.Element {
		buf.WriteString(s[i])
		if i < len(v.Element)-1 {
			buf.WriteRune(',')
		}
	}
	buf.WriteRune(']')
	return buf.String()
}

func update(p *pb.Path, val string) *pb.Update {
	var v *pb.TypedValue
	switch p.Origin {
	case "":
		v = &pb.TypedValue{
			Value: &pb.TypedValue_JsonIetfVal{JsonIetfVal: extractJSON(val)}}
	case "cli":
		v = &pb.TypedValue{
			Value: &pb.TypedValue_AsciiVal{AsciiVal: val}}
	default:
		panic(fmt.Errorf("unexpected origin: %q", p.Origin))
	}

	return &pb.Update{Path: p, Val: v}
}

// Operation describes an gNMI operation.
type Operation struct {
	Type string
	Path []string
	Val  string
}

func newSetRequest(setOps []*Operation) (*pb.SetRequest, error) {
	req := &pb.SetRequest{}
	for _, op := range setOps {
		p, err := ParseGNMIElements(op.Path)
		if err != nil {
			return nil, err
		}

		switch op.Type {
		case "delete":
			req.Delete = append(req.Delete, p)
		case "update":
			req.Update = append(req.Update, update(p, op.Val))
		case "replace":
			req.Replace = append(req.Replace, update(p, op.Val))
		}
	}
	return req, nil
}

// Set sends a SetRequest to the given client.
func Set(ctx context.Context, client pb.GNMIClient, setOps []*Operation) error {
	req, err := newSetRequest(setOps)
	if err != nil {
		return err
	}
	resp, err := client.Set(ctx, req)
	if err != nil {
		return err
	}
	if resp.Message != nil && codes.Code(resp.Message.Code) != codes.OK {
		return errors.New(resp.Message.Message)
	}
	// TODO: Iterate over SetResponse.Response for more detailed error message?

	return nil
}

// Subscribe sends a SubscribeRequest to the given client.
func Subscribe(ctx context.Context, client pb.GNMIClient, paths [][]string,
	respChan chan<- *pb.SubscribeResponse, errChan chan<- error) {
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()
	stream, err := client.Subscribe(ctx)
	if err != nil {
		errChan <- err
		return
	}
	req, err := NewSubscribeRequest(paths)
	if err != nil {
		errChan <- err
		return
	}
	if err := stream.Send(req); err != nil {
		errChan <- err
		return
	}

	for {
		resp, err := stream.Recv()
		if err != nil {
			if err == io.EOF {
				return
			}
			errChan <- err
			return
		}
		respChan <- resp
	}
}

// LogSubscribeResponse logs update responses to stderr.
func LogSubscribeResponse(response *pb.SubscribeResponse) error {
	switch resp := response.Response.(type) {
	case *pb.SubscribeResponse_Error:
		return errors.New(resp.Error.Message)
	case *pb.SubscribeResponse_SyncResponse:
		if !resp.SyncResponse {
			return errors.New("initial sync failed")
		}
	case *pb.SubscribeResponse_Update:
		prefix := StrPath(resp.Update.Prefix)
		for _, update := range resp.Update.Update {
			fmt.Printf("%s = %s\n", path.Join(prefix, StrPath(update.Path)),
				strUpdateVal(update))
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package plugin

import (
	"regexp"
	"strings"

	"github.com/j6n/noye/noye"
)

// Command is a type that makes up a DSL.
// This DSL allows an irc-bot command, via chat to be matched
// in a simple, programmatic fashion.
type Command struct {
	Command  string
	Options  Options
	Matchers []Matcher

	results []string
}

type Options struct {
	Respond bool
	Strict  bool
	Each    bool
}

// Hear is a command that isn't directed toward the bot
// It takes a command string and a matcher and returns a Command
func Hear(cmd string, opt Options, matchers ...Matcher) *Command {
	return &Command{Command: cmd, Matchers: matchers}
}

// Respond is a command that is directed toward the bot
// It takes a command string and a matcher and returns a Command
func Respond(cmd string, opt Options, matchers ...Matcher) *Command {
	opt.Respond = true
	return &Command{Command: cmd, Options: opt, Matchers: matchers}
}

// Match matches the command to the noye.Message
// returning whether it matched or not
func (c *Command) Match(msg noye.Message) bool {
	// reset the results
	c.results = make([]string, 0)

	// split text in parts so we can drop nick/cmd if needed
	parts := strings.Fields(msg.Text)

	// check to see if a nick was prefixed
	if c.Options.Respond {
		nick := "noye" // TODO get current nick
		ok, err := regexp.MatchString(`(?:`+nick+`[:,]?\s*)`, parts[0])
		if err != nil || !ok {
			return false
		}
	}

	// less typing for later
	hasCommand := c.Command != ""

	// if we expect a nick prefix and a command, but only have 1 part
	if (len(parts) == 1 && c.Options.Respond) && hasCommand {
		return false
	}

	index := 0
	// skip first element if we've matched against `respond`
	if c.Options.Respond {
		index++
	}

	// if we have a command, check to see if it matches the next part
	if hasCommand && !strings.EqualFold(c.Command, parts[index]) {
		return false
	}

	// skip next element if we've matched against `respond`
	if c.Options.Respond || hasCommand {
		index++
	}

	// if no default matcher was provided, give them one that always returns true
	if len(c.Matchers) == 0 {
		c.Matchers = append(c.Matchers, func(string) (bool, string) { return true, "" })
	}

	matchEach := func(input string) ([]string, bool) {
		var result []string
		for _, matcher := range c.Matchers {
			if ok, s := matcher(input); ok {
				if s != "" {
					result = append(result, s)
				}
			} else if c.Options.Strict {
				return result, false
			}
		}

		return result, true
	}

	// if we're using the matcher against each part
	if c.Options.Each {
		// ...then match each remaining part
		for _, part := range parts[index:] {
			// ...to each matcher
			if res, ok := matchEach(part); ok {
				c.results = append(c.results, res...)
			} else {
				return false
			}
		}

		// nothing else to do, we've succeeded
		return true
	}

	// match against the parts rejoined as a string
	input := strings.Join(parts[index:], " ")
	if res, ok := matchEach(input); ok {
		c.results = append(c.results, res...)
	} else {
		return false
	}

	return true
}

// Results returns the command results
func (c *Command) Results() []string {
	return c.results
}
<commit_msg>added documentation for plugin.Options<commit_after>package plugin

import (
	"regexp"
	"strings"

	"github.com/j6n/noye/noye"
)

// Command is a type that makes up a DSL.
// This DSL allows an irc-bot command, via chat to be matched
// in a simple, programmatic fashion.
type Command struct {
	Command  string
	Options  Options
	Matchers []Matcher

	results []string
}

// Options are a set of booleans which configure how the processing of the command should be handled.
// Respond means the commands expects a prefix
// Strict means the match must be true
// Each means to match for each part
type Options struct {
	Respond bool
	Strict  bool
	Each    bool
}

// Hear is a command that isn't directed toward the bot
// It takes a command string and a matcher and returns a Command
func Hear(cmd string, opt Options, matchers ...Matcher) *Command {
	return &Command{Command: cmd, Matchers: matchers}
}

// Respond is a command that is directed toward the bot
// It takes a command string and a matcher and returns a Command
func Respond(cmd string, opt Options, matchers ...Matcher) *Command {
	opt.Respond = true
	return &Command{Command: cmd, Options: opt, Matchers: matchers}
}

// Match matches the command to the noye.Message
// returning whether it matched or not
func (c *Command) Match(msg noye.Message) bool {
	// reset the results
	c.results = make([]string, 0)

	// split text in parts so we can drop nick/cmd if needed
	parts := strings.Fields(msg.Text)

	// check to see if a nick was prefixed
	if c.Options.Respond {
		nick := "noye" // TODO get current nick
		ok, err := regexp.MatchString(`(?:`+nick+`[:,]?\s*)`, parts[0])
		if err != nil || !ok {
			return false
		}
	}

	// less typing for later
	hasCommand := c.Command != ""

	// if we expect a nick prefix and a command, but only have 1 part
	if (len(parts) == 1 && c.Options.Respond) && hasCommand {
		return false
	}

	index := 0
	// skip first element if we've matched against `respond`
	if c.Options.Respond {
		index++
	}

	// if we have a command, check to see if it matches the next part
	if hasCommand && !strings.EqualFold(c.Command, parts[index]) {
		return false
	}

	// skip next element if we've matched against `respond`
	if c.Options.Respond || hasCommand {
		index++
	}

	// if no default matcher was provided, give them one that always returns true
	if len(c.Matchers) == 0 {
		c.Matchers = append(c.Matchers, func(string) (bool, string) { return true, "" })
	}

	matchEach := func(input string) ([]string, bool) {
		var result []string
		for _, matcher := range c.Matchers {
			if ok, s := matcher(input); ok {
				if s != "" {
					result = append(result, s)
				}
			} else if c.Options.Strict {
				return result, false
			}
		}

		return result, true
	}

	// if we're using the matcher against each part
	if c.Options.Each {
		// ...then match each remaining part
		for _, part := range parts[index:] {
			// ...to each matcher
			if res, ok := matchEach(part); ok {
				c.results = append(c.results, res...)
			} else {
				return false
			}
		}

		// nothing else to do, we've succeeded
		return true
	}

	// match against the parts rejoined as a string
	input := strings.Join(parts[index:], " ")
	if res, ok := matchEach(input); ok {
		c.results = append(c.results, res...)
	} else {
		return false
	}

	return true
}

// Results returns the command results
func (c *Command) Results() []string {
	return c.results
}
<|endoftext|>


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

// This file implements Sizes.

package types

// Sizes defines the sizing functions for package unsafe.
type Sizes interface {
	// Alignof returns the alignment of a variable of type T.
	// Alignof must implement the alignment guarantees required by the spec.
	Alignof(T Type) int64

	// Offsetsof returns the offsets of the given struct fields, in bytes.
	// Offsetsof must implement the offset guarantees required by the spec.
	Offsetsof(fields []*Var) []int64

	// Sizeof returns the size of a variable of type T.
	// Sizeof must implement the size guarantees required by the spec.
	Sizeof(T Type) int64
}

// StdSizes is a convenience type for creating commonly used Sizes.
// It makes the following simplifying assumptions:
//
//	- The size of explicitly sized basic types (int16, etc.) is the
//	  specified size.
//	- The size of strings and interfaces is 2*WordSize.
//	- The size of slices is 3*WordSize.
//	- All other types have size WordSize.
//	- Arrays and structs are aligned per spec definition; all other
//	  types are naturally aligned with a maximum alignment MaxAlign.
//
// *StdSizes implements Sizes.
//
type StdSizes struct {
	WordSize int64 // word size in bytes - must be >= 4 (32bits)
	MaxAlign int64 // maximum alignment in bytes - must be >= 1
}

func (s *StdSizes) Alignof(T Type) int64 {
	// For arrays and structs, alignment is defined in terms
	// of alignment of the elements and fields, respectively.
	switch t := T.Underlying().(type) {
	case *Array:
		// spec: "For a variable x of array type: unsafe.Alignof(x)
		// is the same as unsafe.Alignof(x[0]), but at least 1."
		return s.Alignof(t.elem)
	case *Struct:
		// spec: "For a variable x of struct type: unsafe.Alignof(x)
		// is the largest of the values unsafe.Alignof(x.f) for each
		// field f of x, but at least 1."
		max := int64(1)
		for _, f := range t.fields {
			if a := s.Alignof(f.typ); a > max {
				max = a
			}
		}
		return max
	}
	a := s.Sizeof(T) // may be 0
	// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
	if a < 1 {
		return 1
	}
	if a > s.MaxAlign {
		return s.MaxAlign
	}
	return a
}

func (s *StdSizes) Offsetsof(fields []*Var) []int64 {
	offsets := make([]int64, len(fields))
	var o int64
	for i, f := range fields {
		a := s.Alignof(f.typ)
		o = align(o, a)
		offsets[i] = o
		o += s.Sizeof(f.typ)
	}
	return offsets
}

var basicSizes = [...]byte{
	Bool:       1,
	Int8:       1,
	Int16:      2,
	Int32:      4,
	Int64:      8,
	Uint8:      1,
	Uint16:     2,
	Uint32:     4,
	Uint64:     8,
	Float32:    4,
	Float64:    8,
	Complex64:  8,
	Complex128: 16,
}

func (s *StdSizes) Sizeof(T Type) int64 {
	switch t := T.Underlying().(type) {
	case *Basic:
		assert(isTyped(T))
		k := t.kind
		if int(k) < len(basicSizes) {
			if s := basicSizes[k]; s > 0 {
				return int64(s)
			}
		}
		if k == String {
			return s.WordSize * 2
		}
	case *Array:
		a := s.Alignof(t.elem)
		z := s.Sizeof(t.elem)
		return align(z, a) * t.len // may be 0
	case *Slice:
		return s.WordSize * 3
	case *Struct:
		n := t.NumFields()
		if n == 0 {
			return 0
		}
		offsets := t.offsets
		if t.offsets == nil {
			// compute offsets on demand
			offsets = s.Offsetsof(t.fields)
			t.offsets = offsets
		}
		return offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
	case *Interface:
		return s.WordSize * 2
	}
	return s.WordSize // catch-all
}

// stdSizes is used if Config.Sizes == nil.
var stdSizes = StdSizes{8, 8}

func (conf *Config) alignof(T Type) int64 {
	if s := conf.Sizes; s != nil {
		if a := s.Alignof(T); a >= 1 {
			return a
		}
		panic("Config.Sizes.Alignof returned an alignment < 1")
	}
	return stdSizes.Alignof(T)
}

func (conf *Config) offsetsof(T *Struct) []int64 {
	offsets := T.offsets
	if offsets == nil && T.NumFields() > 0 {
		// compute offsets on demand
		if s := conf.Sizes; s != nil {
			offsets = s.Offsetsof(T.fields)
			// sanity checks
			if len(offsets) != T.NumFields() {
				panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
			}
			for _, o := range offsets {
				if o < 0 {
					panic("Config.Sizes.Offsetsof returned an offset < 0")
				}
			}
		} else {
			offsets = stdSizes.Offsetsof(T.fields)
		}
		T.offsets = offsets
	}
	return offsets
}

// offsetof returns the offset of the field specified via
// the index sequence relative to typ. All embedded fields
// must be structs (rather than pointer to structs).
func (conf *Config) offsetof(typ Type, index []int) int64 {
	var o int64
	for _, i := range index {
		s := typ.Underlying().(*Struct)
		o += conf.offsetsof(s)[i]
		typ = s.fields[i].typ
	}
	return o
}

func (conf *Config) sizeof(T Type) int64 {
	if s := conf.Sizes; s != nil {
		if z := s.Sizeof(T); z >= 0 {
			return z
		}
		panic("Config.Sizes.Sizeof returned a size < 0")
	}
	return stdSizes.Sizeof(T)
}

// align returns the smallest y >= x such that y % a == 0.
func align(x, a int64) int64 {
	y := x + a - 1
	return y - y%a
}
<commit_msg>go/types: document default unsafe.Sizeof computation better<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file implements Sizes.

package types

// Sizes defines the sizing functions for package unsafe.
type Sizes interface {
	// Alignof returns the alignment of a variable of type T.
	// Alignof must implement the alignment guarantees required by the spec.
	Alignof(T Type) int64

	// Offsetsof returns the offsets of the given struct fields, in bytes.
	// Offsetsof must implement the offset guarantees required by the spec.
	Offsetsof(fields []*Var) []int64

	// Sizeof returns the size of a variable of type T.
	// Sizeof must implement the size guarantees required by the spec.
	Sizeof(T Type) int64
}

// StdSizes is a convenience type for creating commonly used Sizes.
// It makes the following simplifying assumptions:
//
//	- The size of explicitly sized basic types (int16, etc.) is the
//	  specified size.
//	- The size of strings and interfaces is 2*WordSize.
//	- The size of slices is 3*WordSize.
//	- The size of arrays is the aligned size (see below) of an element
//        multiplied by the number of elements.
//      - The size of a struct is the offset of the last field plus that
//	  field's size. If the struct is used in an array its size must
//        first be aligned to a multiple of the struct's alignment.
//	- All other types have size WordSize.
//	- Arrays and structs are aligned per spec definition; all other
//	  types are naturally aligned with a maximum alignment MaxAlign.
//
// *StdSizes implements Sizes.
//
type StdSizes struct {
	WordSize int64 // word size in bytes - must be >= 4 (32bits)
	MaxAlign int64 // maximum alignment in bytes - must be >= 1
}

func (s *StdSizes) Alignof(T Type) int64 {
	// For arrays and structs, alignment is defined in terms
	// of alignment of the elements and fields, respectively.
	switch t := T.Underlying().(type) {
	case *Array:
		// spec: "For a variable x of array type: unsafe.Alignof(x)
		// is the same as unsafe.Alignof(x[0]), but at least 1."
		return s.Alignof(t.elem)
	case *Struct:
		// spec: "For a variable x of struct type: unsafe.Alignof(x)
		// is the largest of the values unsafe.Alignof(x.f) for each
		// field f of x, but at least 1."
		max := int64(1)
		for _, f := range t.fields {
			if a := s.Alignof(f.typ); a > max {
				max = a
			}
		}
		return max
	}
	a := s.Sizeof(T) // may be 0
	// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
	if a < 1 {
		return 1
	}
	if a > s.MaxAlign {
		return s.MaxAlign
	}
	return a
}

func (s *StdSizes) Offsetsof(fields []*Var) []int64 {
	offsets := make([]int64, len(fields))
	var o int64
	for i, f := range fields {
		a := s.Alignof(f.typ)
		o = align(o, a)
		offsets[i] = o
		o += s.Sizeof(f.typ)
	}
	return offsets
}

var basicSizes = [...]byte{
	Bool:       1,
	Int8:       1,
	Int16:      2,
	Int32:      4,
	Int64:      8,
	Uint8:      1,
	Uint16:     2,
	Uint32:     4,
	Uint64:     8,
	Float32:    4,
	Float64:    8,
	Complex64:  8,
	Complex128: 16,
}

func (s *StdSizes) Sizeof(T Type) int64 {
	switch t := T.Underlying().(type) {
	case *Basic:
		assert(isTyped(T))
		k := t.kind
		if int(k) < len(basicSizes) {
			if s := basicSizes[k]; s > 0 {
				return int64(s)
			}
		}
		if k == String {
			return s.WordSize * 2
		}
	case *Array:
		a := s.Alignof(t.elem)
		z := s.Sizeof(t.elem)
		return align(z, a) * t.len // may be 0
	case *Slice:
		return s.WordSize * 3
	case *Struct:
		n := t.NumFields()
		if n == 0 {
			return 0
		}
		offsets := t.offsets
		if t.offsets == nil {
			// compute offsets on demand
			offsets = s.Offsetsof(t.fields)
			t.offsets = offsets
		}
		return offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
	case *Interface:
		return s.WordSize * 2
	}
	return s.WordSize // catch-all
}

// stdSizes is used if Config.Sizes == nil.
var stdSizes = StdSizes{8, 8}

func (conf *Config) alignof(T Type) int64 {
	if s := conf.Sizes; s != nil {
		if a := s.Alignof(T); a >= 1 {
			return a
		}
		panic("Config.Sizes.Alignof returned an alignment < 1")
	}
	return stdSizes.Alignof(T)
}

func (conf *Config) offsetsof(T *Struct) []int64 {
	offsets := T.offsets
	if offsets == nil && T.NumFields() > 0 {
		// compute offsets on demand
		if s := conf.Sizes; s != nil {
			offsets = s.Offsetsof(T.fields)
			// sanity checks
			if len(offsets) != T.NumFields() {
				panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
			}
			for _, o := range offsets {
				if o < 0 {
					panic("Config.Sizes.Offsetsof returned an offset < 0")
				}
			}
		} else {
			offsets = stdSizes.Offsetsof(T.fields)
		}
		T.offsets = offsets
	}
	return offsets
}

// offsetof returns the offset of the field specified via
// the index sequence relative to typ. All embedded fields
// must be structs (rather than pointer to structs).
func (conf *Config) offsetof(typ Type, index []int) int64 {
	var o int64
	for _, i := range index {
		s := typ.Underlying().(*Struct)
		o += conf.offsetsof(s)[i]
		typ = s.fields[i].typ
	}
	return o
}

func (conf *Config) sizeof(T Type) int64 {
	if s := conf.Sizes; s != nil {
		if z := s.Sizeof(T); z >= 0 {
			return z
		}
		panic("Config.Sizes.Sizeof returned a size < 0")
	}
	return stdSizes.Sizeof(T)
}

// align returns the smallest y >= x such that y % a == 0.
func align(x, a int64) int64 {
	y := x + a - 1
	return y - y%a
}
<|endoftext|>


<commit_before>package plugin

import (
	"crypto/rand"
	"encoding/json"
	"fmt"

	"github.com/appc/cni/pkg/ipam"
	"github.com/appc/cni/pkg/skel"
	"github.com/appc/cni/pkg/types"
	"github.com/vishvananda/netlink"
	"github.com/vishvananda/netns"
	weaveapi "github.com/weaveworks/weave/api"
	"github.com/weaveworks/weave/common"
	ipamplugin "github.com/weaveworks/weave/plugin/ipam"
)

type CNIPlugin struct {
	weave *weaveapi.Client
}

func NewCNIPlugin(weave *weaveapi.Client) *CNIPlugin {
	return &CNIPlugin{weave: weave}
}

func loadNetConf(bytes []byte) (*NetConf, error) {
	n := &NetConf{
		BrName: "weave",
	}
	if err := json.Unmarshal(bytes, n); err != nil {
		return nil, errorf("failed to load netconf: %v", err)
	}
	return n, nil
}

func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error {
	conf, err := loadNetConf(args.StdinData)
	if err != nil {
		return err
	}

	if conf.IsGW {
		return errorf("Gateway functionality not supported")
	}
	if conf.IPMasq {
		return errorf("IP Masquerading functionality not supported")
	}

	ns, err := netns.GetFromPath(args.Netns)
	if err != nil {
		return err
	}
	defer ns.Close()

	id := args.ContainerID
	if len(id) < 5 {
		data := make([]byte, 5)
		_, err := rand.Reader.Read(data)
		if err != nil {
			return err
		}
		id = fmt.Sprintf("%x", data)
	}

	local, err := createAndAttach(id, conf.BrName, conf.MTU)
	if err != nil {
		return err
	}

	cleanup := func(err error) error {
		netlink.LinkDel(local)
		return err
	}
	guest, err := netlink.LinkByName(local.PeerName)
	if err != nil {
		return cleanup(err)
	}
	if err = netlink.LinkSetNsFd(guest, int(ns)); err != nil {
		return cleanup(errorf("failed to move veth to container netns: %s", err))
	}

	if err := netlink.LinkSetUp(local); err != nil {
		return cleanup(errorf("unable to bring veth up: %s", err))
	}

	var result *types.Result
	// Default IPAM is Weave's own
	if conf.IPAM.Type == "" {
		result, err = ipamplugin.NewIpam(c.weave).Allocate(args)
	} else {
		result, err = ipam.ExecAdd(conf.IPAM.Type, args.StdinData)
	}
	if err != nil {
		return cleanup(errorf("unable to allocate IP address: %s", err))
	}
	if result.IP4 == nil {
		return cleanup(errorf("IPAM plugin failed to allocate IP address"))
	}

	err = common.WithNetNS(ns, func() error {
		guest, err := netlink.LinkByName(local.PeerName)
		if err != nil {
			return cleanup(err)
		}
		if err = netlink.LinkSetName(guest, args.IfName); err != nil {
			return err
		}
		return ipam.ConfigureIface(args.IfName, result)
	})
	if err != nil {
		return cleanup(errorf("error setting up interface: %s", err))
	}

	result.DNS = conf.DNS
	return result.Print()
}

func (c *CNIPlugin) CmdDel(args *skel.CmdArgs) error {
	conf, err := loadNetConf(args.StdinData)
	if err != nil {
		return err
	}

	ns, err := netns.GetFromPath(args.Netns)
	if err != nil {
		return err
	}
	defer ns.Close()
	err = common.WithNetNS(ns, func() error {
		link, err := netlink.LinkByName(args.IfName)
		if err != nil {
			return err
		}
		return netlink.LinkDel(link)
	})
	if err != nil {
		return errorf("error removing interface: %s", err)
	}

	// Default IPAM is Weave's own
	if conf.IPAM.Type == "" {
		err = ipamplugin.NewIpam(c.weave).Release(args)
	} else {
		err = ipam.ExecDel(conf.IPAM.Type, args.StdinData)
	}
	if err != nil {
		return errorf("unable to release IP address: %s", err)
	}
	return nil
}

type NetConf struct {
	types.NetConf
	BrName string `json:"bridge"`
	IsGW   bool   `json:"isGateway"`
	IPMasq bool   `json:"ipMasq"`
	MTU    int    `json:"mtu"`
}
<commit_msg>Set a default route via bridge if config doesn't specify any<commit_after>package plugin

import (
	"crypto/rand"
	"encoding/json"
	"fmt"
	"net"
	"os"

	"github.com/appc/cni/pkg/ipam"
	"github.com/appc/cni/pkg/skel"
	"github.com/appc/cni/pkg/types"
	"github.com/vishvananda/netlink"
	"github.com/vishvananda/netns"
	weaveapi "github.com/weaveworks/weave/api"
	"github.com/weaveworks/weave/common"
	ipamplugin "github.com/weaveworks/weave/plugin/ipam"
)

var (
	zeroNetwork = net.IPNet{IP: net.IPv4zero, Mask: net.IPv4Mask(0, 0, 0, 0)}
	mask32      = net.IPv4Mask(0xff, 0xff, 0xff, 0xff)
)

type CNIPlugin struct {
	weave *weaveapi.Client
}

func NewCNIPlugin(weave *weaveapi.Client) *CNIPlugin {
	return &CNIPlugin{weave: weave}
}

func loadNetConf(bytes []byte) (*NetConf, error) {
	n := &NetConf{
		BrName: "weave",
	}
	if err := json.Unmarshal(bytes, n); err != nil {
		return nil, errorf("failed to load netconf: %v", err)
	}
	return n, nil
}

func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error {
	conf, err := loadNetConf(args.StdinData)
	if err != nil {
		return err
	}

	if conf.IsGW {
		return errorf("Gateway functionality not supported")
	}
	if conf.IPMasq {
		return errorf("IP Masquerading functionality not supported")
	}

	ns, err := netns.GetFromPath(args.Netns)
	if err != nil {
		return err
	}
	defer ns.Close()

	id := args.ContainerID
	if len(id) < 5 {
		data := make([]byte, 5)
		_, err := rand.Reader.Read(data)
		if err != nil {
			return err
		}
		id = fmt.Sprintf("%x", data)
	}

	local, err := createAndAttach(id, conf.BrName, conf.MTU)
	if err != nil {
		return err
	}

	cleanup := func(err error) error {
		netlink.LinkDel(local)
		return err
	}
	guest, err := netlink.LinkByName(local.PeerName)
	if err != nil {
		return cleanup(err)
	}
	if err = netlink.LinkSetNsFd(guest, int(ns)); err != nil {
		return cleanup(errorf("failed to move veth to container netns: %s", err))
	}

	if err := netlink.LinkSetUp(local); err != nil {
		return cleanup(errorf("unable to bring veth up: %s", err))
	}

	var result *types.Result
	// Default IPAM is Weave's own
	if conf.IPAM.Type == "" {
		result, err = ipamplugin.NewIpam(c.weave).Allocate(args)
	} else {
		result, err = ipam.ExecAdd(conf.IPAM.Type, args.StdinData)
	}
	if err != nil {
		return cleanup(errorf("unable to allocate IP address: %s", err))
	}
	if result.IP4 == nil {
		return cleanup(errorf("IPAM plugin failed to allocate IP address"))
	}

	// If config says nothing about routes or gateway, default one will be via the bridge
	if result.IP4.Routes == nil && result.IP4.Gateway == nil {
		bridgeIP, err := findBridgeIP(conf.BrName, result.IP4.IP)
		if err != nil {
			return cleanup(err)
		}
		result.IP4.Gateway = bridgeIP
	}

	err = common.WithNetNS(ns, func() error {
		return setupGuestIP4(local.PeerName, args.IfName, result.IP4.IP, result.IP4.Gateway, result.IP4.Routes)
	})
	if err != nil {
		return cleanup(errorf("error setting up interface: %s", err))
	}

	result.DNS = conf.DNS
	return result.Print()
}

func setupGuestIP4(origName, name string, ipnet net.IPNet, gw net.IP, routes []types.Route) error {
	guest, err := netlink.LinkByName(origName)
	if err != nil {
		return err
	}
	if err = netlink.LinkSetName(guest, name); err != nil {
		return err
	}
	if err = netlink.LinkSetUp(guest); err != nil {
		return err
	}
	if routes == nil { // If config says nothing about routes, add a default one
		if !ipnet.Contains(gw) {
			// The bridge IP is not on the same subnet; add a specific route to it
			gw32 := &net.IPNet{IP: gw, Mask: mask32}
			if err = addRoute(guest, netlink.SCOPE_LINK, gw32, nil); err != nil {
				return err
			}
		}
		routes = []types.Route{{Dst: zeroNetwork}}
	}
	if err = netlink.AddrAdd(guest, &netlink.Addr{IPNet: &ipnet}); err != nil {
		return fmt.Errorf("failed to add IP address to %q: %v", name, err)
	}
	for _, r := range routes {
		if r.GW != nil {
			err = addRoute(guest, netlink.SCOPE_UNIVERSE, &r.Dst, r.GW)
		} else {
			err = addRoute(guest, netlink.SCOPE_UNIVERSE, &r.Dst, gw)
		}
		if err != nil {
			return fmt.Errorf("failed to add route '%v via %v dev %v': %v", r.Dst, gw, name, err)
		}
	}
	return nil
}

func addRoute(link netlink.Link, scope netlink.Scope, dst *net.IPNet, gw net.IP) error {
	err := netlink.RouteAdd(&netlink.Route{
		LinkIndex: link.Attrs().Index,
		Scope:     scope,
		Dst:       dst,
		Gw:        gw,
	})
	if os.IsExist(err) { // squash duplicate route errors
		err = nil
	}
	return err
}

func findBridgeIP(bridgeName string, subnet net.IPNet) (net.IP, error) {
	netdevs, err := common.GetBridgeNetDev(bridgeName)
	if err != nil {
		return nil, fmt.Errorf("Failed to get netdev for %q bridge: %s", bridgeName, err)
	}
	if len(netdevs) == 0 {
		return nil, fmt.Errorf("Could not find %q bridge", bridgeName)
	}
	if len(netdevs[0].CIDRs) == 0 {
		return nil, fmt.Errorf("Bridge %q has no IP addresses", bridgeName)
	}
	for _, cidr := range netdevs[0].CIDRs {
		if subnet.Contains(cidr.IP) {
			return cidr.IP, nil
		}
	}
	// None in the required subnet; just return the first one
	return netdevs[0].CIDRs[0].IP, nil
}

func (c *CNIPlugin) CmdDel(args *skel.CmdArgs) error {
	conf, err := loadNetConf(args.StdinData)
	if err != nil {
		return err
	}

	ns, err := netns.GetFromPath(args.Netns)
	if err != nil {
		return err
	}
	defer ns.Close()
	err = common.WithNetNS(ns, func() error {
		link, err := netlink.LinkByName(args.IfName)
		if err != nil {
			return err
		}
		return netlink.LinkDel(link)
	})
	if err != nil {
		return errorf("error removing interface: %s", err)
	}

	// Default IPAM is Weave's own
	if conf.IPAM.Type == "" {
		err = ipamplugin.NewIpam(c.weave).Release(args)
	} else {
		err = ipam.ExecDel(conf.IPAM.Type, args.StdinData)
	}
	if err != nil {
		return errorf("unable to release IP address: %s", err)
	}
	return nil
}

type NetConf struct {
	types.NetConf
	BrName string `json:"bridge"`
	IsGW   bool   `json:"isGateway"`
	IPMasq bool   `json:"ipMasq"`
	MTU    int    `json:"mtu"`
}
<|endoftext|>