<commit_before>package fish

// see https://fishshell.com/docs/current/commands.html#complete
var fishTemplate = `#!/usr/bin/env fish
{{ $prog := .Name -}}
set PROG '{{ $prog }}'

function __fish_{{ $prog }}_needs_command
  set -l cmd (commandline -opc)
  if [ (count $cmd) -eq 1 -a $cmd[1] = $PROG ]
    return 0
  end
  return 1
end

function __fish_{{ $prog }}_uses_command
  set cmd (commandline -opc)
  if [ (count $cmd) -gt 1 ]
    if [ $argv[1] = $cmd[2] ]
      return 0
    end
  end
  return 1
end

function __fish_{{ $prog }}_print_gpg_keys
  gpg2 --list-keys | grep uid | sed 's/.*<\(.*\)>/\1/'
end

function __fish_{{ $prog }}_print_entries
  {{ $prog }} ls --flat
end

function __fish_{{ $prog }}__print_dirs
  for i in ({{ $prog }} ls --flat)
	  echo (dirname $i)
	end | sort -u
end

# erase any existing completions for {{ $prog }}
complete -c $PROG -e
complete -c $PROG -f -n '__fish_{{ $prog }}_needs_command' -a "(__fish_{{ $prog }}_print_entries)"
{{- $gflags := .Flags -}}
{{ range .Commands }}
complete -c $PROG -f -n '__fish_{{ $prog }}_needs_command' -a {{ .Name }} -d 'Command: {{ .Usage }}'
{{- $cmd := .Name -}}
{{- if or (eq $cmd "copy") (eq $cmd "move") (eq $cmd "delete") (eq $cmd "show") }}
complete -c $PROG -f -n '__fish_{{ $prog }}_uses_command {{ $cmd }}' -a "(__fish_{{ $prog }}_print_entries)"{{ end -}}
{{- if or (eq $cmd "insert") (eq $cmd "generate") (eq $cmd "list") }}
complete -c $PROG -f -n '__fish_{{ $prog }}_uses_command {{ $cmd }}' -a "(__fish_{{ $prog }}_print_dir)"{{ end -}}
{{- range .Subcommands }}
{{- $subcmd := .Name }}
complete -c $PROG -f -n '__fish_{{ $prog }}_uses_command {{ $cmd }}' -a {{ $subcmd }} -d 'Subcommand: {{ .Usage }}'
{{- range .Flags }}
complete -c $PROG -f -n '__fish_{{ $prog }}_uses_command {{ $cmd }} {{ $subcmd }} {{ if ne (. | formatShortFlag) "" }}-s {{ . | formatShortFlag }} {{ end }}-l {{ . | formatLongFlag }} -d "{{ . | formatFlagUsage }}"'
{{- end }}
{{- range $gflags }}
complete -c $PROG -f -n '__fish_{{ $prog }}_uses_command {{ $cmd }} {{ $subcmd }} {{ if ne (. | formatShortFlag) "" }}-s {{ . | formatShortFlag }} {{ end }}-l {{ . | formatLongFlag }} -d "{{ . | formatFlagUsage }}"'
{{- end }}
{{- end }}
{{- end }}`
<commit_msg>fix fish completion (#1049)<commit_after>package fish

// see https://fishshell.com/docs/current/commands.html#complete
var fishTemplate = `#!/usr/bin/env fish
{{ $prog := .Name -}}
set PROG '{{ $prog }}'

function __fish_{{ $prog }}_needs_command
  set -l cmd (commandline -opc)
  if [ (count $cmd) -eq 1 -a $cmd[1] = $PROG ]
    return 0
  end
  return 1
end

function __fish_{{ $prog }}_uses_command
  set cmd (commandline -opc)
  if [ (count $cmd) -gt 1 ]
    if [ $argv[1] = $cmd[2] ]
      return 0
    end
  end
  return 1
end

function __fish_{{ $prog }}_print_gpg_keys
  gpg2 --list-keys | grep uid | sed 's/.*<\(.*\)>/\1/'
end

function __fish_{{ $prog }}_print_entries
  {{ $prog }} ls --flat
end

function __fish_{{ $prog }}_print_dir
  for i in ({{ $prog }} ls --flat)
	  echo (dirname $i)
	end | sort -u
end

# erase any existing completions for {{ $prog }}
complete -c $PROG -e
complete -c $PROG -f -n '__fish_{{ $prog }}_needs_command' -a "(__fish_{{ $prog }}_print_entries)"
{{- $gflags := .Flags -}}
{{ range .Commands }}
complete -c $PROG -f -n '__fish_{{ $prog }}_needs_command' -a {{ .Name }} -d 'Command: {{ .Usage }}'
{{- $cmd := .Name -}}
{{- if or (eq $cmd "copy") (eq $cmd "move") (eq $cmd "delete") (eq $cmd "show") }}
complete -c $PROG -f -n '__fish_{{ $prog }}_uses_command {{ $cmd }}' -a "(__fish_{{ $prog }}_print_entries)"{{ end -}}
{{- if or (eq $cmd "insert") (eq $cmd "generate") (eq $cmd "list") }}
complete -c $PROG -f -n '__fish_{{ $prog }}_uses_command {{ $cmd }}' -a "(__fish_{{ $prog }}_print_dir)"{{ end -}}
{{- range .Subcommands }}
{{- $subcmd := .Name }}
complete -c $PROG -f -n '__fish_{{ $prog }}_uses_command {{ $cmd }}' -a {{ $subcmd }} -d 'Subcommand: {{ .Usage }}'
{{- range .Flags }}
complete -c $PROG -f -n '__fish_{{ $prog }}_uses_command {{ $cmd }} {{ $subcmd }} {{ if ne (. | formatShortFlag) "" }}-s {{ . | formatShortFlag }} {{ end }}-l {{ . | formatLongFlag }} -d "{{ . | formatFlagUsage }}"'
{{- end }}
{{- range $gflags }}
complete -c $PROG -f -n '__fish_{{ $prog }}_uses_command {{ $cmd }} {{ $subcmd }} {{ if ne (. | formatShortFlag) "" }}-s {{ . | formatShortFlag }} {{ end }}-l {{ . | formatLongFlag }} -d "{{ . | formatFlagUsage }}"'
{{- end }}
{{- end }}
{{- end }}`
<|endoftext|>


<commit_before>/*
Copyright 2018 Google Inc.

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

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

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

package config

const (
	natTable    = "nat"
	ipMasqChain = "IP-MASQ"
)

var MasqueradeConfigSet = Set{
	false,
	"Masquerade",
	nil,
}

func init() {
	MasqueradeConfigSet.Configs = []Config{

		IPTablesRuleConfig{
			IPTablesChainSpec{
				TableName:      natTable,
				ChainName:      postRoutingChain,
				IsDefaultChain: true,
				IPT:            ipt,
			},
			[]IPTablesRuleSpec{
				[]string{"-m", "addrtype", "!", "--dst-type", "LOCAL", "-j", "IP-MASQ"},
			},
			ipt,
		},
		IPTablesRuleConfig{
			IPTablesChainSpec{
				TableName:      natTable,
				ChainName:      ipMasqChain,
				IsDefaultChain: false,
				IPT:            ipt,
			},
			[]IPTablesRuleSpec{
				[]string{"-d", "169.254.0.0/16", "-j", "RETURN", "-m", "comment", "--comment", "ip-masq: local traffic is not subject to MASQUERADE"},
				[]string{"-d", "10.0.0.0/8", "-j", "RETURN", "-m", "comment", "--comment", "ip-masq: local traffic is not subject to MASQUERADE"},
				[]string{"-d", "172.16.0.0/12", "-j", "RETURN", "-m", "comment", "--comment", "ip-masq: local traffic is not subject to MASQUERADE"},
				[]string{"-d", "192.168.0.0/16", "-j", "RETURN", "-m", "comment", "--comment", "ip-masq: local traffic is not subject to MASQUERADE"},
				[]string{"-j", "MASQUERADE", "-m", "comment", "--comment", "ip-masq: outbound traffic is subject to MASQUERADE (must be last in chain)"},
			},
			ipt,
		},
	}
}
<commit_msg>fix ip-masq comments to match configure-helper.sh https://github.com/kubernetes/kubernetes/blob/master/cluster/gce/gci/configure-helper.sh#L74<commit_after>/*
Copyright 2018 Google Inc.

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

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

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

package config

const (
	natTable    = "nat"
	ipMasqChain = "IP-MASQ"
)

var MasqueradeConfigSet = Set{
	false,
	"Masquerade",
	nil,
}

func init() {
	MasqueradeConfigSet.Configs = []Config{

		IPTablesRuleConfig{
			IPTablesChainSpec{
				TableName:      natTable,
				ChainName:      postRoutingChain,
				IsDefaultChain: true,
				IPT:            ipt,
			},
			[]IPTablesRuleSpec{
				[]string{"-m", "comment", "--comment", "ip-masq: ensure nat POSTROUTING directs all non-LOCAL destination traffic to our custom IP-MASQ chain", "-m", "addrtype", "!", "--dst-type", "LOCAL", "-j", "IP-MASQ"},
			},
			ipt,
		},
		IPTablesRuleConfig{
			IPTablesChainSpec{
				TableName:      natTable,
				ChainName:      ipMasqChain,
				IsDefaultChain: false,
				IPT:            ipt,
			},
			[]IPTablesRuleSpec{
				[]string{"-d", "169.254.0.0/16", "-j", "RETURN", "-m", "comment", "--comment", "ip-masq: local traffic is not subject to MASQUERADE"},
				[]string{"-d", "10.0.0.0/8", "-j", "RETURN", "-m", "comment", "--comment", "ip-masq: local traffic is not subject to MASQUERADE"},
				[]string{"-d", "172.16.0.0/12", "-j", "RETURN", "-m", "comment", "--comment", "ip-masq: local traffic is not subject to MASQUERADE"},
				[]string{"-d", "192.168.0.0/16", "-j", "RETURN", "-m", "comment", "--comment", "ip-masq: local traffic is not subject to MASQUERADE"},
				[]string{"-j", "MASQUERADE", "-m", "comment", "--comment", "ip-masq: outbound traffic is subject to MASQUERADE (must be last in chain)"},
			},
			ipt,
		},
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Skaffold 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 debug

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"

	appsv1 "k8s.io/api/apps/v1"
	batchv1 "k8s.io/api/batch/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"
)

// portAllocator is a function that takes a desired port and returns an available port
// Ports are normally uint16 but Kubernetes ContainerPort.containerPort is an integer
type portAllocator func(int32) int32

// configurationRetriever retrieves an container image configuration
type configurationRetriever func(string) (imageConfiguration, error)

// imageConfiguration captures information from a docker/oci image configuration
type imageConfiguration struct {
	labels     map[string]string
	env        map[string]string
	entrypoint []string
	arguments  []string
}

// containerTransformer transforms a container definition
type containerTransformer interface {
	// IsApplicable determines if this container is suitable to be transformed.
	IsApplicable(config imageConfiguration) bool

	// RuntimeSupportImage returns the associated duct-tape helper image required or empty string
	RuntimeSupportImage() string

	// Apply configures a container definition for debugging, returning a simple map describing the debug configuration details or `nil` if it could not be done
	Apply(container *v1.Container, config imageConfiguration, portAlloc portAllocator) map[string]interface{}
}

var containerTransforms []containerTransformer

// transformManifest attempts to configure a manifest for debugging.
// Returns true if changed, false otherwise.
func transformManifest(obj runtime.Object, retrieveImageConfiguration configurationRetriever) bool {
	one := int32(1)
	switch o := obj.(type) {
	case *v1.Pod:
		return transformPodSpec(&o.ObjectMeta, &o.Spec, retrieveImageConfiguration)
	case *v1.PodList:
		changed := false
		for i := range o.Items {
			if transformPodSpec(&o.Items[i].ObjectMeta, &o.Items[i].Spec, retrieveImageConfiguration) {
				changed = true
			}
		}
		return changed
	case *v1.ReplicationController:
		if o.Spec.Replicas != nil {
			o.Spec.Replicas = &one
		}
		return transformPodSpec(&o.Spec.Template.ObjectMeta, &o.Spec.Template.Spec, retrieveImageConfiguration)
	case *appsv1.Deployment:
		if o.Spec.Replicas != nil {
			o.Spec.Replicas = &one
		}
		return transformPodSpec(&o.Spec.Template.ObjectMeta, &o.Spec.Template.Spec, retrieveImageConfiguration)
	case *appsv1.DaemonSet:
		return transformPodSpec(&o.Spec.Template.ObjectMeta, &o.Spec.Template.Spec, retrieveImageConfiguration)
	case *appsv1.ReplicaSet:
		if o.Spec.Replicas != nil {
			o.Spec.Replicas = &one
		}
		return transformPodSpec(&o.Spec.Template.ObjectMeta, &o.Spec.Template.Spec, retrieveImageConfiguration)
	case *appsv1.StatefulSet:
		if o.Spec.Replicas != nil {
			o.Spec.Replicas = &one
		}
		return transformPodSpec(&o.Spec.Template.ObjectMeta, &o.Spec.Template.Spec, retrieveImageConfiguration)
	case *batchv1.Job:
		return transformPodSpec(&o.Spec.Template.ObjectMeta, &o.Spec.Template.Spec, retrieveImageConfiguration)

	default:
		group, version, _, description := describe(obj)
		if group == "apps" || group == "batch" {
			if version != "v1" {
				// treat deprecated objects as errors
				logrus.Errorf("deprecated versions not supported by debug: %s (%s)", description, version)
			} else {
				logrus.Warnf("no debug transformation for: %s", description)
			}
		} else {
			logrus.Debugf("no debug transformation for: %s", description)
		}
		return false
	}
}

// transformPodSpec attempts to configure a podspec for debugging.
// Returns true if changed, false otherwise.
func transformPodSpec(metadata *metav1.ObjectMeta, podSpec *v1.PodSpec, retrieveImageConfiguration configurationRetriever) bool {
	portAlloc := func(desiredPort int32) int32 {
		return allocatePort(podSpec, desiredPort)
	}
	// containers are required to have unique name within a pod
	configurations := make(map[string]map[string]interface{})
	requiredSupportImages := make(map[string]string)
	var supportFilesRequired []*v1.Container
	for i := range podSpec.Containers {
		container := &podSpec.Containers[i]
		// we only reconfigure build artifacts
		if configuration, requiredSupportImage, err := transformContainer(container, retrieveImageConfiguration, portAlloc); err == nil {
			configurations[container.Name] = configuration
			if len(requiredSupportImage) > 0 {
				logrus.Infof("%q requires debugging support image %s", container.Name, requiredSupportImage)
				supportFilesRequired = append(supportFilesRequired, container)
				requiredSupportImages[requiredSupportImage] = requiredSupportImage
			}
			// todo: add this artifact to the watch list?
		} else {
			logrus.Infof("Image %q not configured for debugging: %v", container.Name, err)
		}
	}
	if len(supportFilesRequired) > 0 {
		logrus.Infof("Configuring installation of debugging support files")
		supportVolume := v1.Volume{Name: "debugging-support-files", VolumeSource: v1.VolumeSource{EmptyDir: &v1.EmptyDirVolumeSource{}}}
		podSpec.Volumes = append(podSpec.Volumes, supportVolume)
		supportVolumeMount := v1.VolumeMount{Name: "debugging-support-files", MountPath: "/dbg"}
		for _, container := range supportFilesRequired {
			container.VolumeMounts = append(container.VolumeMounts, supportVolumeMount)
		}
		// TODO make this pluggable for airgapped clusters? or is making container `imagePullPolicy:IfNotPresent` sufficient?
		for imageId, _ := range requiredSupportImages {
			supportFilesInitContainer := v1.Container{
				Name:            fmt.Sprintf("install-%s-support", imageId),
				Image:           fmt.Sprintf("gcr.io/gcp-dev-tools/duct-tape/%s", imageId),
				VolumeMounts:    []v1.VolumeMount{supportVolumeMount},
			}
			podSpec.InitContainers = append(podSpec.InitContainers, supportFilesInitContainer)
		}
	}

	if len(configurations) > 0 {
		if metadata.Annotations == nil {
			metadata.Annotations = make(map[string]string)
		}
		metadata.Annotations["debug.cloud.google.com/config"] = encodeConfigurations(configurations)
		return true
	}
	return false
}

// allocatePort walks the podSpec's containers looking for an available port that is close to desiredPort.
// We deal with wrapping and avoid allocating ports < 1024
func allocatePort(podSpec *v1.PodSpec, desiredPort int32) int32 {
	var maxPort int32 = 65535 // ports are normally [1-65535]
	if desiredPort < 1024 || desiredPort > maxPort {
		desiredPort = 1024 // skip reserved ports
	}
	// We assume ports are rather sparsely allocated, so even if desiredPort
	// is allocated, desiredPort+1 or desiredPort+2 are likely to be free
	for port := desiredPort; port < maxPort; port++ {
		if isPortAvailable(podSpec, port) {
			return port
		}
	}
	for port := desiredPort; port > 1024; port-- {
		if isPortAvailable(podSpec, port) {
			return port
		}
	}
	panic("cannot find available port") // exceedingly unlikely
}

// isPortAvailable returns true if none of the pod's containers specify the given port.
func isPortAvailable(podSpec *v1.PodSpec, port int32) bool {
	for _, container := range podSpec.Containers {
		for _, portSpec := range container.Ports {
			if portSpec.ContainerPort == port {
				return false
			}
		}
	}
	return true
}

// transformContainer rewrites the container definition to enable debugging.
// Returns a debugging configuration description with associated language runtime support
// container image, or an error if the rewrite was unsuccessful.
func transformContainer(container *v1.Container, retrieveImageConfiguration configurationRetriever, portAlloc portAllocator) (map[string]interface{}, string, error) {
	var config imageConfiguration
	config, err := retrieveImageConfiguration(container.Image)
	if err != nil {
		return nil, "", err
	}

	// update image configuration values with those set in the k8s manifest
	for _, envVar := range container.Env {
		// FIXME handle ValueFrom?
		config.env[envVar.Name] = envVar.Value
	}

	if len(container.Command) > 0 {
		config.entrypoint = container.Command
	}
	if len(container.Args) > 0 {
		config.arguments = container.Args
	}

	for _, transform := range containerTransforms {
		if transform.IsApplicable(config) {
			return transform.Apply(container, config, portAlloc), transform.RuntimeSupportImage(), nil
		}
	}
	return nil, "", errors.Errorf("unable to determine runtime for %q", container.Name)
}

func encodeConfigurations(configurations map[string]map[string]interface{}) string {
	bytes, err := json.Marshal(configurations)
	if err != nil {
		return ""
	}
	return string(bytes)
}

func describe(obj runtime.Object) (group, version, kind, description string) {
	// get metadata/name; shamelessly stolen from from k8s.io/cli-runtime/pkg/printers/name.go
	name := "<unknown>"
	if acc, err := meta.Accessor(obj); err == nil {
		if n := acc.GetName(); len(n) > 0 {
			name = n
		}
	}

	gvk := obj.GetObjectKind().GroupVersionKind()
	group = gvk.Group
	version = gvk.Version
	kind = gvk.Kind
	if group == "" {
		description = fmt.Sprintf("%s/%s", strings.ToLower(kind), name)
	} else {
		description = fmt.Sprintf("%s.%s/%s", strings.ToLower(kind), group, name)
	}
	return
}
<commit_msg>make golint happy<commit_after>/*
Copyright 2019 The Skaffold 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 debug

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"

	appsv1 "k8s.io/api/apps/v1"
	batchv1 "k8s.io/api/batch/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"
)

// portAllocator is a function that takes a desired port and returns an available port
// Ports are normally uint16 but Kubernetes ContainerPort.containerPort is an integer
type portAllocator func(int32) int32

// configurationRetriever retrieves an container image configuration
type configurationRetriever func(string) (imageConfiguration, error)

// imageConfiguration captures information from a docker/oci image configuration
type imageConfiguration struct {
	labels     map[string]string
	env        map[string]string
	entrypoint []string
	arguments  []string
}

// containerTransformer transforms a container definition
type containerTransformer interface {
	// IsApplicable determines if this container is suitable to be transformed.
	IsApplicable(config imageConfiguration) bool

	// RuntimeSupportImage returns the associated duct-tape helper image required or empty string
	RuntimeSupportImage() string

	// Apply configures a container definition for debugging, returning a simple map describing the debug configuration details or `nil` if it could not be done
	Apply(container *v1.Container, config imageConfiguration, portAlloc portAllocator) map[string]interface{}
}

var containerTransforms []containerTransformer

// transformManifest attempts to configure a manifest for debugging.
// Returns true if changed, false otherwise.
func transformManifest(obj runtime.Object, retrieveImageConfiguration configurationRetriever) bool {
	one := int32(1)
	switch o := obj.(type) {
	case *v1.Pod:
		return transformPodSpec(&o.ObjectMeta, &o.Spec, retrieveImageConfiguration)
	case *v1.PodList:
		changed := false
		for i := range o.Items {
			if transformPodSpec(&o.Items[i].ObjectMeta, &o.Items[i].Spec, retrieveImageConfiguration) {
				changed = true
			}
		}
		return changed
	case *v1.ReplicationController:
		if o.Spec.Replicas != nil {
			o.Spec.Replicas = &one
		}
		return transformPodSpec(&o.Spec.Template.ObjectMeta, &o.Spec.Template.Spec, retrieveImageConfiguration)
	case *appsv1.Deployment:
		if o.Spec.Replicas != nil {
			o.Spec.Replicas = &one
		}
		return transformPodSpec(&o.Spec.Template.ObjectMeta, &o.Spec.Template.Spec, retrieveImageConfiguration)
	case *appsv1.DaemonSet:
		return transformPodSpec(&o.Spec.Template.ObjectMeta, &o.Spec.Template.Spec, retrieveImageConfiguration)
	case *appsv1.ReplicaSet:
		if o.Spec.Replicas != nil {
			o.Spec.Replicas = &one
		}
		return transformPodSpec(&o.Spec.Template.ObjectMeta, &o.Spec.Template.Spec, retrieveImageConfiguration)
	case *appsv1.StatefulSet:
		if o.Spec.Replicas != nil {
			o.Spec.Replicas = &one
		}
		return transformPodSpec(&o.Spec.Template.ObjectMeta, &o.Spec.Template.Spec, retrieveImageConfiguration)
	case *batchv1.Job:
		return transformPodSpec(&o.Spec.Template.ObjectMeta, &o.Spec.Template.Spec, retrieveImageConfiguration)

	default:
		group, version, _, description := describe(obj)
		if group == "apps" || group == "batch" {
			if version != "v1" {
				// treat deprecated objects as errors
				logrus.Errorf("deprecated versions not supported by debug: %s (%s)", description, version)
			} else {
				logrus.Warnf("no debug transformation for: %s", description)
			}
		} else {
			logrus.Debugf("no debug transformation for: %s", description)
		}
		return false
	}
}

// transformPodSpec attempts to configure a podspec for debugging.
// Returns true if changed, false otherwise.
func transformPodSpec(metadata *metav1.ObjectMeta, podSpec *v1.PodSpec, retrieveImageConfiguration configurationRetriever) bool {
	portAlloc := func(desiredPort int32) int32 {
		return allocatePort(podSpec, desiredPort)
	}
	// containers are required to have unique name within a pod
	configurations := make(map[string]map[string]interface{})
	requiredSupportImages := make(map[string]string)
	var supportFilesRequired []*v1.Container
	for i := range podSpec.Containers {
		container := &podSpec.Containers[i]
		// we only reconfigure build artifacts
		if configuration, requiredSupportImage, err := transformContainer(container, retrieveImageConfiguration, portAlloc); err == nil {
			configurations[container.Name] = configuration
			if len(requiredSupportImage) > 0 {
				logrus.Infof("%q requires debugging support image %s", container.Name, requiredSupportImage)
				supportFilesRequired = append(supportFilesRequired, container)
				requiredSupportImages[requiredSupportImage] = requiredSupportImage
			}
			// todo: add this artifact to the watch list?
		} else {
			logrus.Infof("Image %q not configured for debugging: %v", container.Name, err)
		}
	}
	if len(supportFilesRequired) > 0 {
		logrus.Infof("Configuring installation of debugging support files")
		supportVolume := v1.Volume{Name: "debugging-support-files", VolumeSource: v1.VolumeSource{EmptyDir: &v1.EmptyDirVolumeSource{}}}
		podSpec.Volumes = append(podSpec.Volumes, supportVolume)
		supportVolumeMount := v1.VolumeMount{Name: "debugging-support-files", MountPath: "/dbg"}
		for _, container := range supportFilesRequired {
			container.VolumeMounts = append(container.VolumeMounts, supportVolumeMount)
		}
		// TODO make this pluggable for airgapped clusters? or is making container `imagePullPolicy:IfNotPresent` sufficient?
		for imageID, _ := range requiredSupportImages {
			supportFilesInitContainer := v1.Container{
				Name:         fmt.Sprintf("install-%s-support", imageId),
				Image:        fmt.Sprintf("gcr.io/gcp-dev-tools/duct-tape/%s", imageId),
				VolumeMounts: []v1.VolumeMount{supportVolumeMount},
			}
			podSpec.InitContainers = append(podSpec.InitContainers, supportFilesInitContainer)
		}
	}

	if len(configurations) > 0 {
		if metadata.Annotations == nil {
			metadata.Annotations = make(map[string]string)
		}
		metadata.Annotations["debug.cloud.google.com/config"] = encodeConfigurations(configurations)
		return true
	}
	return false
}

// allocatePort walks the podSpec's containers looking for an available port that is close to desiredPort.
// We deal with wrapping and avoid allocating ports < 1024
func allocatePort(podSpec *v1.PodSpec, desiredPort int32) int32 {
	var maxPort int32 = 65535 // ports are normally [1-65535]
	if desiredPort < 1024 || desiredPort > maxPort {
		desiredPort = 1024 // skip reserved ports
	}
	// We assume ports are rather sparsely allocated, so even if desiredPort
	// is allocated, desiredPort+1 or desiredPort+2 are likely to be free
	for port := desiredPort; port < maxPort; port++ {
		if isPortAvailable(podSpec, port) {
			return port
		}
	}
	for port := desiredPort; port > 1024; port-- {
		if isPortAvailable(podSpec, port) {
			return port
		}
	}
	panic("cannot find available port") // exceedingly unlikely
}

// isPortAvailable returns true if none of the pod's containers specify the given port.
func isPortAvailable(podSpec *v1.PodSpec, port int32) bool {
	for _, container := range podSpec.Containers {
		for _, portSpec := range container.Ports {
			if portSpec.ContainerPort == port {
				return false
			}
		}
	}
	return true
}

// transformContainer rewrites the container definition to enable debugging.
// Returns a debugging configuration description with associated language runtime support
// container image, or an error if the rewrite was unsuccessful.
func transformContainer(container *v1.Container, retrieveImageConfiguration configurationRetriever, portAlloc portAllocator) (map[string]interface{}, string, error) {
	var config imageConfiguration
	config, err := retrieveImageConfiguration(container.Image)
	if err != nil {
		return nil, "", err
	}

	// update image configuration values with those set in the k8s manifest
	for _, envVar := range container.Env {
		// FIXME handle ValueFrom?
		config.env[envVar.Name] = envVar.Value
	}

	if len(container.Command) > 0 {
		config.entrypoint = container.Command
	}
	if len(container.Args) > 0 {
		config.arguments = container.Args
	}

	for _, transform := range containerTransforms {
		if transform.IsApplicable(config) {
			return transform.Apply(container, config, portAlloc), transform.RuntimeSupportImage(), nil
		}
	}
	return nil, "", errors.Errorf("unable to determine runtime for %q", container.Name)
}

func encodeConfigurations(configurations map[string]map[string]interface{}) string {
	bytes, err := json.Marshal(configurations)
	if err != nil {
		return ""
	}
	return string(bytes)
}

func describe(obj runtime.Object) (group, version, kind, description string) {
	// get metadata/name; shamelessly stolen from from k8s.io/cli-runtime/pkg/printers/name.go
	name := "<unknown>"
	if acc, err := meta.Accessor(obj); err == nil {
		if n := acc.GetName(); len(n) > 0 {
			name = n
		}
	}

	gvk := obj.GetObjectKind().GroupVersionKind()
	group = gvk.Group
	version = gvk.Version
	kind = gvk.Kind
	if group == "" {
		description = fmt.Sprintf("%s/%s", strings.ToLower(kind), name)
	} else {
		description = fmt.Sprintf("%s.%s/%s", strings.ToLower(kind), group, name)
	}
	return
}
<|endoftext|>


<commit_before>// This output package contains all the operations to render the metrics collected
// during the benchmark
package output

import (
	"fmt"
	"os"
	"time"

	"github.com/giantswarm/nomi/log"
	"github.com/giantswarm/nomi/output/gnuplot"
	"github.com/giantswarm/nomi/unit"
)

// Directory where the plots are stored by default
const plotsDIR = "/nomi_plots"

var processTypes = []string{"fleetd", "systemd"}

// GeneratePlots creates some initial plots from the collected metrics. Three
// are the initial plots: start operation completion time/delay, stop operation
// completion time/delay and cluster metrics for systemd and fleetd.
func GeneratePlots(stats unit.Stats, verbose bool) {
	fname := ""
	persist := true
	debug := verbose
	plotsDirectory := plotsDIR

	if os.Getenv("PLOTS_DIR") != "" {
		plotsDirectory = os.Getenv("PLOTS_DIR")
	}

	gnuplot.Initialize()

	generateDelayStartPlot(fname, persist, debug, plotsDirectory, stats)

	// Start delay
	if len(stats.Start) > 0 {
		generateUnitsStartPlot(fname, persist, debug, plotsDirectory, stats)
	}

	// Stop delay
	if len(stats.Stop) > 0 {
		generateUnitsStopPlot(fname, persist, debug, plotsDirectory, stats)
	}

	// Start units counting
	if len(stats.Start) > 0 {
		generateUnitsStartCountPlot(fname, persist, debug, plotsDirectory, stats)
	}

	// Stop units counting
	if len(stats.Start) > 0 {
		generateUnitsStopCountPlot(fname, persist, debug, plotsDirectory, stats)
	}

	// Start units multiple plot
	if len(stats.Start) > 0 {
		generateUnitsStartMultiPlot(fname, persist, debug, plotsDirectory, stats)
	}
}

func generateDelayStartPlot(fname string, persist bool, debug bool, plotsDirectory string, stats unit.Stats) {
	for _, process := range processTypes {
		p, err := gnuplot.NewPlotter(fname, persist, debug)
		if err != nil {
			err_string := fmt.Sprintf("** err: %v\n", err)
			panic(err_string)
		}
		defer p.Close()
		for hostname, metrics := range stats.MachineStats {
			valuesX := make([]float64, 0)
			valuesY := make([]float64, 0)
			for _, metric := range metrics {
				if metric.Process == process {
					valuesX = append(valuesX, metric.TimeStamp)
					valuesY = append(valuesY, metric.CPUUsage)
				}
			}
			if debug {
				log.Logger().Infof("Plotting data for %s", hostname)
			}
			p.PlotXY(valuesX, valuesY, fmt.Sprintf("%s - Time/CPU", hostname), "")
		}
		p.SetXLabel("Timestamp (secs)")
		p.SetYLabel("CPU usage (%)")
		p.CheckedCmd("set terminal pdf")

		if debug {
			log.Logger().Infof("Generating plot %s", process)
		}
		p.CheckedCmd(fmt.Sprintf("set output '%s/%s.pdf'", plotsDirectory, process))
		p.CheckedCmd("replot")

		time.Sleep(2)
		p.CheckedCmd("q")

	}
}

func generateUnitsStartPlot(fname string, persist bool, debug bool, plotsDirectory string, stats unit.Stats) {
	p, err := gnuplot.NewPlotter(fname, persist, debug)
	if err != nil {
		err_string := fmt.Sprintf("** err: %v\n", err)
		panic(err_string)
	}
	defer p.Close()

	valuesX := make([]float64, 0)
	valuesY := make([]float64, 0)
	p.CheckedCmd("set grid x")
	p.CheckedCmd("set grid y")
	p.SetStyle("impulses")
	for _, stats := range stats.Start {
		valuesX = append(valuesX, stats.CompletionTime)
		valuesY = append(valuesY, stats.Delay)
	}
	p.PlotXY(valuesX, valuesY, "Start operation Completion/Delay seconds", "")
	p.SetXLabel("Completion time (secs)")
	p.SetYLabel("Delay time (secs)")
	p.CheckedCmd("set terminal pdf")

	p.CheckedCmd(fmt.Sprintf("set output '%s/units_start.pdf'", plotsDirectory))
	p.CheckedCmd("replot")

	time.Sleep(2)
	p.CheckedCmd("q")
}

func generateUnitsStopPlot(fname string, persist bool, debug bool, plotsDirectory string, stats unit.Stats) {
	p, err := gnuplot.NewPlotter(fname, persist, debug)
	if err != nil {
		err_string := fmt.Sprintf("** err: %v\n", err)
		panic(err_string)
	}
	defer p.Close()

	valuesX := make([]float64, 0)
	valuesY := make([]float64, 0)
	p.CheckedCmd("set grid x")
	p.CheckedCmd("set grid y")
	p.SetStyle("impulses")
	p.SetYLabel("Delay time (secs)")
	p.SetXLabel("Completion time (secs)")
	p.CheckedCmd("set terminal pdf")
	p.CheckedCmd(fmt.Sprintf("set output '%s/units_stop.pdf'", plotsDirectory))

	for _, stats := range stats.Stop {
		valuesX = append(valuesX, stats.CompletionTime)
		valuesY = append(valuesY, stats.Delay)
	}
	p.PlotXY(valuesX, valuesY, "Stop operation Completion/Delay seconds", "")
	p.CheckedCmd("replot")

	time.Sleep(2)
	p.CheckedCmd("q")
}

func generateUnitsStartCountPlot(fname string, persist bool, debug bool, plotsDirectory string, stats unit.Stats) {
	p, err := gnuplot.NewPlotter(fname, persist, debug)
	if err != nil {
		err_string := fmt.Sprintf("** err: %v\n", err)
		panic(err_string)
	}
	defer p.Close()

	valuesX1 := make([]float64, 0)
	valuesY1 := make([]float64, 0)
	valuesX2 := make([]float64, 0)
	valuesY2 := make([]float64, 0)

	p.SetStyle("lines")
	for _, stats := range stats.Start {
		valuesX1 = append(valuesX1, stats.StartTime)
		valuesY1 = append(valuesY1, float64(stats.StartingCount))
		valuesX2 = append(valuesX2, stats.CompletionTime)
		valuesY2 = append(valuesY2, float64(stats.RunningCount))
	}

	p.SetStyle("boxes")
	p.PlotXY(valuesX1, valuesY1, "Starting", "")
	p.SetStyle("lines")
	p.PlotXY(valuesX2, valuesY2, "Running", "")

	p.SetXLabel("Timestamp (secs)")
	p.SetYLabel("Number of units")
	p.CheckedCmd("set terminal pdf")
	p.CheckedCmd(fmt.Sprintf("set output '%s/units_start_count.pdf'", plotsDirectory))
	p.CheckedCmd("replot")

	time.Sleep(2)
	p.CheckedCmd("q")
}

func generateUnitsStopCountPlot(fname string, persist bool, debug bool, plotsDirectory string, stats unit.Stats) {
	p, err := gnuplot.NewPlotter(fname, persist, debug)
	if err != nil {
		err_string := fmt.Sprintf("** err: %v\n", err)
		panic(err_string)
	}
	defer p.Close()

	valuesX1 := make([]float64, 0)
	valuesY1 := make([]float64, 0)
	valuesX2 := make([]float64, 0)
	valuesY2 := make([]float64, 0)

	p.SetStyle("lines")
	for _, stats := range stats.Stop {
		valuesX1 = append(valuesX1, stats.StartTime)
		valuesY1 = append(valuesY1, float64(stats.StoppingCount))
		valuesX2 = append(valuesX2, stats.CompletionTime)
		valuesY2 = append(valuesY2, float64(stats.StoppedCount))
	}

	p.PlotXY(valuesX1, valuesY1, "Stopping", "")
	p.PlotXY(valuesX2, valuesY2, "Stopped", "")

	p.SetXLabel("Timestamp (secs)")
	p.SetYLabel("Number of units")
	p.CheckedCmd("set terminal pdf")
	p.CheckedCmd(fmt.Sprintf("set output '%s/units_stop_count.pdf'", plotsDirectory))
	p.CheckedCmd("replot")

	time.Sleep(2)
	p.CheckedCmd("q")
}

func generateUnitsStartMultiPlot(fname string, persist bool, debug bool, plotsDirectory string, stats unit.Stats) {
	p, err := gnuplot.NewPlotter(fname, persist, debug)
	if err != nil {
		err_string := fmt.Sprintf("** err: %v\n", err)
		panic(err_string)
	}
	defer p.Close()

	valuesX := make([]float64, 0)
	valuesY := make([]float64, 0)
	valuesY2 := make([]float64, 0)
	p.CheckedCmd("set yrange [y1min:y1max]")
	p.CheckedCmd("set y2range [y2min:y2max]")
	p.SetXLabel("Completion time (secs)")
	p.SetYLabel("Delay time (secs)")
	p.CheckedCmd("set y2label 'Number of units'")
	p.SetStyle("dots")
	for _, stats := range stats.Start {
		valuesX = append(valuesX, stats.CompletionTime)
		valuesY = append(valuesY, stats.Delay)
		valuesY2 = append(valuesY2, float64(stats.RunningCount))
	}
	p.PlotXY(valuesX, valuesY, "Start Completion/Delay secs/Units", "axes x1y1")
	p.SetStyle("lines")
	p.PlotXY(valuesX, valuesY2, "Running units", "axes x1y2")

	p.CheckedCmd("set terminal pdf")
	p.CheckedCmd(fmt.Sprintf("set output '%s/units_start_multi.pdf'", plotsDirectory))
	p.CheckedCmd("replot")

	time.Sleep(2)
	p.CheckedCmd("q")
}
<commit_msg>Add metrics to y2 axes<commit_after>// This output package contains all the operations to render the metrics collected
// during the benchmark
package output

import (
	"fmt"
	"os"
	"time"

	"github.com/giantswarm/nomi/log"
	"github.com/giantswarm/nomi/output/gnuplot"
	"github.com/giantswarm/nomi/unit"
)

// Directory where the plots are stored by default
const plotsDIR = "/nomi_plots"

var processTypes = []string{"fleetd", "systemd"}

// GeneratePlots creates some initial plots from the collected metrics. Three
// are the initial plots: start operation completion time/delay, stop operation
// completion time/delay and cluster metrics for systemd and fleetd.
func GeneratePlots(stats unit.Stats, verbose bool) {
	fname := ""
	persist := true
	debug := verbose
	plotsDirectory := plotsDIR

	if os.Getenv("PLOTS_DIR") != "" {
		plotsDirectory = os.Getenv("PLOTS_DIR")
	}

	gnuplot.Initialize()

	generateDelayStartPlot(fname, persist, debug, plotsDirectory, stats)

	// Start delay
	if len(stats.Start) > 0 {
		generateUnitsStartPlot(fname, persist, debug, plotsDirectory, stats)
	}

	// Stop delay
	if len(stats.Stop) > 0 {
		generateUnitsStopPlot(fname, persist, debug, plotsDirectory, stats)
	}

	// Start units counting
	if len(stats.Start) > 0 {
		generateUnitsStartCountPlot(fname, persist, debug, plotsDirectory, stats)
	}

	// Stop units counting
	if len(stats.Start) > 0 {
		generateUnitsStopCountPlot(fname, persist, debug, plotsDirectory, stats)
	}

	// Start units multiple plot
	if len(stats.Start) > 0 {
		generateUnitsStartMultiPlot(fname, persist, debug, plotsDirectory, stats)
	}
}

func generateDelayStartPlot(fname string, persist bool, debug bool, plotsDirectory string, stats unit.Stats) {
	for _, process := range processTypes {
		p, err := gnuplot.NewPlotter(fname, persist, debug)
		if err != nil {
			err_string := fmt.Sprintf("** err: %v\n", err)
			panic(err_string)
		}
		defer p.Close()
		for hostname, metrics := range stats.MachineStats {
			valuesX := make([]float64, 0)
			valuesY := make([]float64, 0)
			for _, metric := range metrics {
				if metric.Process == process {
					valuesX = append(valuesX, metric.TimeStamp)
					valuesY = append(valuesY, metric.CPUUsage)
				}
			}
			if debug {
				log.Logger().Infof("Plotting data for %s", hostname)
			}
			p.PlotXY(valuesX, valuesY, fmt.Sprintf("%s - Time/CPU", hostname), "")
		}
		p.SetXLabel("Timestamp (secs)")
		p.SetYLabel("CPU usage (%)")
		p.CheckedCmd("set terminal pdf")

		if debug {
			log.Logger().Infof("Generating plot %s", process)
		}
		p.CheckedCmd(fmt.Sprintf("set output '%s/%s.pdf'", plotsDirectory, process))
		p.CheckedCmd("replot")

		time.Sleep(2)
		p.CheckedCmd("q")

	}
}

func generateUnitsStartPlot(fname string, persist bool, debug bool, plotsDirectory string, stats unit.Stats) {
	p, err := gnuplot.NewPlotter(fname, persist, debug)
	if err != nil {
		err_string := fmt.Sprintf("** err: %v\n", err)
		panic(err_string)
	}
	defer p.Close()

	valuesX := make([]float64, 0)
	valuesY := make([]float64, 0)
	p.CheckedCmd("set grid x")
	p.CheckedCmd("set grid y")
	p.SetStyle("impulses")
	for _, stats := range stats.Start {
		valuesX = append(valuesX, stats.CompletionTime)
		valuesY = append(valuesY, stats.Delay)
	}
	p.PlotXY(valuesX, valuesY, "Start operation Completion/Delay seconds", "")
	p.SetXLabel("Completion time (secs)")
	p.SetYLabel("Delay time (secs)")
	p.CheckedCmd("set terminal pdf")

	p.CheckedCmd(fmt.Sprintf("set output '%s/units_start.pdf'", plotsDirectory))
	p.CheckedCmd("replot")

	time.Sleep(2)
	p.CheckedCmd("q")
}

func generateUnitsStopPlot(fname string, persist bool, debug bool, plotsDirectory string, stats unit.Stats) {
	p, err := gnuplot.NewPlotter(fname, persist, debug)
	if err != nil {
		err_string := fmt.Sprintf("** err: %v\n", err)
		panic(err_string)
	}
	defer p.Close()

	valuesX := make([]float64, 0)
	valuesY := make([]float64, 0)
	p.CheckedCmd("set grid x")
	p.CheckedCmd("set grid y")
	p.SetStyle("impulses")
	p.SetYLabel("Delay time (secs)")
	p.SetXLabel("Completion time (secs)")
	p.CheckedCmd("set terminal pdf")
	p.CheckedCmd(fmt.Sprintf("set output '%s/units_stop.pdf'", plotsDirectory))

	for _, stats := range stats.Stop {
		valuesX = append(valuesX, stats.CompletionTime)
		valuesY = append(valuesY, stats.Delay)
	}
	p.PlotXY(valuesX, valuesY, "Stop operation Completion/Delay seconds", "")
	p.CheckedCmd("replot")

	time.Sleep(2)
	p.CheckedCmd("q")
}

func generateUnitsStartCountPlot(fname string, persist bool, debug bool, plotsDirectory string, stats unit.Stats) {
	p, err := gnuplot.NewPlotter(fname, persist, debug)
	if err != nil {
		err_string := fmt.Sprintf("** err: %v\n", err)
		panic(err_string)
	}
	defer p.Close()

	valuesX1 := make([]float64, 0)
	valuesY1 := make([]float64, 0)
	valuesX2 := make([]float64, 0)
	valuesY2 := make([]float64, 0)

	p.SetStyle("lines")
	for _, stats := range stats.Start {
		valuesX1 = append(valuesX1, stats.StartTime)
		valuesY1 = append(valuesY1, float64(stats.StartingCount))
		valuesX2 = append(valuesX2, stats.CompletionTime)
		valuesY2 = append(valuesY2, float64(stats.RunningCount))
	}

	p.SetStyle("boxes")
	p.PlotXY(valuesX1, valuesY1, "Starting", "")
	p.SetStyle("lines")
	p.PlotXY(valuesX2, valuesY2, "Running", "")

	p.SetXLabel("Timestamp (secs)")
	p.SetYLabel("Number of units")
	p.CheckedCmd("set terminal pdf")
	p.CheckedCmd(fmt.Sprintf("set output '%s/units_start_count.pdf'", plotsDirectory))
	p.CheckedCmd("replot")

	time.Sleep(2)
	p.CheckedCmd("q")
}

func generateUnitsStopCountPlot(fname string, persist bool, debug bool, plotsDirectory string, stats unit.Stats) {
	p, err := gnuplot.NewPlotter(fname, persist, debug)
	if err != nil {
		err_string := fmt.Sprintf("** err: %v\n", err)
		panic(err_string)
	}
	defer p.Close()

	valuesX1 := make([]float64, 0)
	valuesY1 := make([]float64, 0)
	valuesX2 := make([]float64, 0)
	valuesY2 := make([]float64, 0)

	p.SetStyle("lines")
	for _, stats := range stats.Stop {
		valuesX1 = append(valuesX1, stats.StartTime)
		valuesY1 = append(valuesY1, float64(stats.StoppingCount))
		valuesX2 = append(valuesX2, stats.CompletionTime)
		valuesY2 = append(valuesY2, float64(stats.StoppedCount))
	}

	p.PlotXY(valuesX1, valuesY1, "Stopping", "")
	p.PlotXY(valuesX2, valuesY2, "Stopped", "")

	p.SetXLabel("Timestamp (secs)")
	p.SetYLabel("Number of units")
	p.CheckedCmd("set terminal pdf")
	p.CheckedCmd(fmt.Sprintf("set output '%s/units_stop_count.pdf'", plotsDirectory))
	p.CheckedCmd("replot")

	time.Sleep(2)
	p.CheckedCmd("q")
}

func generateUnitsStartMultiPlot(fname string, persist bool, debug bool, plotsDirectory string, stats unit.Stats) {
	p, err := gnuplot.NewPlotter(fname, persist, debug)
	if err != nil {
		err_string := fmt.Sprintf("** err: %v\n", err)
		panic(err_string)
	}
	defer p.Close()

	valuesX := make([]float64, 0)
	valuesY := make([]float64, 0)
	valuesY2 := make([]float64, 0)
	p.CheckedCmd("set yrange [y1min:y1max]")
	p.CheckedCmd("set y2range [y2min:y2max]")
	p.SetXLabel("Completion time (secs)")
	p.SetYLabel("Delay time (secs)")
	p.CheckedCmd("set y2label 'Number of units'")
	p.CheckedCmd("set ytics nomirror")
	p.CheckedCmd("set y2tics")
	p.SetStyle("dots")
	for _, stats := range stats.Start {
		valuesX = append(valuesX, stats.CompletionTime)
		valuesY = append(valuesY, stats.Delay)
		valuesY2 = append(valuesY2, float64(stats.RunningCount))
	}
	p.PlotXY(valuesX, valuesY, "Start Completion/Delay secs/Units", "axes x1y1")
	p.SetStyle("lines")
	p.PlotXY(valuesX, valuesY2, "Running units", "axes x1y2")

	p.CheckedCmd("set terminal pdf")
	p.CheckedCmd(fmt.Sprintf("set output '%s/units_start_multi.pdf'", plotsDirectory))
	p.CheckedCmd("replot")

	time.Sleep(2)
	p.CheckedCmd("q")
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"os/exec"
	"testing"

	. "gopkg.in/bluesuncorp/assert.v1"
)

// NOTES:
// - Run "go test" to run tests
// - Run "gocov test | gocov report" to report on test converage by file
// - Run "gocov test | gocov annotate -" to report on all code and functions, those ,marked with "MISS" were never called
//
// or
//
// -- may be a good idea to change to output path to somewherelike /tmp
// go test -coverprofile cover.out && go tool cover -html=cover.out -o cover.html
//

func TestOveralls(t *testing.T) {

	args := []string{"-project=github.com/joeybloggs/overalls/test-files", "-covermode=count", "-debug"}

	cmd := exec.Command("overalls", args...)
	err := cmd.Run()
	Equal(t, err, nil)

	fileBytes, err := ioutil.ReadFile(srcPath + "github.com/joeybloggs/overalls/test-files/overalls.coverprofile")
	Equal(t, err, nil)
	Equal(t, len(fileBytes), 149)
}
<commit_msg>update for repo change<commit_after>package main

import (
	"io/ioutil"
	"testing"

	. "gopkg.in/bluesuncorp/assert.v1"
)

// NOTES:
// - Run "go test" to run tests
// - Run "gocov test | gocov report" to report on test converage by file
// - Run "gocov test | gocov annotate -" to report on all code and functions, those ,marked with "MISS" were never called
//
// or
//
// -- may be a good idea to change to output path to somewherelike /tmp
// go test -coverprofile cover.out && go tool cover -html=cover.out -o cover.html
//

func TestOveralls(t *testing.T) {

	// args := []string{"-project=github.com/joeybloggs/overalls/test-files", "-covermode=count", "-debug"}

	// cmd := exec.Command("overalls", args...)
	// err := cmd.Run()
	// Equal(t, err, nil)

	fileBytes, err := ioutil.ReadFile(srcPath + "github.com/joeybloggs/overalls/test-files/overalls.coverprofile")
	Equal(t, err, nil)
	Equal(t, len(fileBytes), 151)
}
<|endoftext|>


<commit_before>// package peer implements an object used to represent peers in the ipfs network.
package peer

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"strings"

	ic "github.com/ipfs/go-libp2p/p2p/crypto"
	b58 "gx/ipfs/QmT8rehPR3F6bmwL6zjUN8XpiDBFFpMP2myPdC6ApsWfJf/go-base58"
	mh "gx/ipfs/QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku/go-multihash"
	u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
	logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" // ID represents the identity of a peer.
	ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
)

var log = logging.Logger("peer")

type ID string

// Pretty returns a b58-encoded string of the ID
func (id ID) Pretty() string {
	return IDB58Encode(id)
}

func (id ID) Loggable() map[string]interface{} {
	return map[string]interface{}{
		"peerID": id.Pretty(),
	}
}

// String prints out the peer.
//
// TODO(brian): ensure correctness at ID generation and
// enforce this by only exposing functions that generate
// IDs safely. Then any peer.ID type found in the
// codebase is known to be correct.
func (id ID) String() string {
	pid := id.Pretty()

	//All sha256 nodes start with Qm
	//We can skip the Qm to make the peer.ID more useful
	if strings.HasPrefix(pid, "gx/Qm") {
		pid = pid[2:]
	}

	maxRunes := 6
	if len(pid) < maxRunes {
		maxRunes = len(pid)
	}
	return fmt.Sprintf("<peer.ID %s>", pid[:maxRunes])
}

// MatchesPrivateKey tests whether this ID was derived from sk
func (id ID) MatchesPrivateKey(sk ic.PrivKey) bool {
	return id.MatchesPublicKey(sk.GetPublic())
}

// MatchesPublicKey tests whether this ID was derived from pk
func (id ID) MatchesPublicKey(pk ic.PubKey) bool {
	oid, err := IDFromPublicKey(pk)
	if err != nil {
		return false
	}
	return oid == id
}

// IDFromString cast a string to ID type, and validate
// the id to make sure it is a multihash.
func IDFromString(s string) (ID, error) {
	if _, err := mh.Cast([]byte(s)); err != nil {
		return ID(""), err
	}
	return ID(s), nil
}

// IDFromBytes cast a string to ID type, and validate
// the id to make sure it is a multihash.
func IDFromBytes(b []byte) (ID, error) {
	if _, err := mh.Cast(b); err != nil {
		return ID(""), err
	}
	return ID(b), nil
}

// IDB58Decode returns a b58-decoded Peer
func IDB58Decode(s string) (ID, error) {
	m, err := mh.FromB58String(s)
	if err != nil {
		return "", err
	}
	return ID(m), err
}

// IDB58Encode returns b58-encoded string
func IDB58Encode(id ID) string {
	return b58.Encode([]byte(id))
}

// IDHexDecode returns a b58-decoded Peer
func IDHexDecode(s string) (ID, error) {
	m, err := mh.FromHexString(s)
	if err != nil {
		return "", err
	}
	return ID(m), err
}

// IDHexEncode returns b58-encoded string
func IDHexEncode(id ID) string {
	return hex.EncodeToString([]byte(id))
}

// IDFromPublicKey returns the Peer ID corresponding to pk
func IDFromPublicKey(pk ic.PubKey) (ID, error) {
	b, err := pk.Bytes()
	if err != nil {
		return "", err
	}
	hash := u.Hash(b)
	return ID(hash), nil
}

// IDFromPrivateKey returns the Peer ID corresponding to sk
func IDFromPrivateKey(sk ic.PrivKey) (ID, error) {
	return IDFromPublicKey(sk.GetPublic())
}

// Map maps a Peer ID to a struct.
type Set map[ID]struct{}

// PeerInfo is a small struct used to pass around a peer with
// a set of addresses (and later, keys?). This is not meant to be
// a complete view of the system, but rather to model updates to
// the peerstore. It is used by things like the routing system.
type PeerInfo struct {
	ID    ID
	Addrs []ma.Multiaddr
}

func (pi *PeerInfo) Loggable() map[string]interface{} {
	return map[string]interface{}{
		"peerID": pi.ID.Pretty(),
		"addrs":  pi.Addrs,
	}
}

func (pi *PeerInfo) MarshalJSON() ([]byte, error) {
	out := make(map[string]interface{})
	out["ID"] = IDB58Encode(pi.ID)
	var addrs []string
	for _, a := range pi.Addrs {
		addrs = append(addrs, a.String())
	}
	out["Addrs"] = addrs
	return json.Marshal(out)
}

func (pi *PeerInfo) UnmarshalJSON(b []byte) error {
	var data map[string]interface{}
	err := json.Unmarshal(b, &data)
	if err != nil {
		return err
	}
	pid, err := IDB58Decode(data["ID"].(string))
	if err != nil {
		return err
	}
	pi.ID = pid
	addrs, ok := data["Addrs"].([]interface{})
	if ok {
		for _, a := range addrs {
			pi.Addrs = append(pi.Addrs, ma.StringCast(a.(string)))
		}
	}
	return nil
}

// IDSlice for sorting peers
type IDSlice []ID

func (es IDSlice) Len() int           { return len(es) }
func (es IDSlice) Swap(i, j int)      { es[i], es[j] = es[j], es[i] }
func (es IDSlice) Less(i, j int) bool { return string(es[i]) < string(es[j]) }
<commit_msg>fix accidental find and replace fail<commit_after>// package peer implements an object used to represent peers in the ipfs network.
package peer

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"strings"

	ic "github.com/ipfs/go-libp2p/p2p/crypto"
	b58 "gx/ipfs/QmT8rehPR3F6bmwL6zjUN8XpiDBFFpMP2myPdC6ApsWfJf/go-base58"
	mh "gx/ipfs/QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku/go-multihash"
	u "gx/ipfs/QmZNVWh8LLjAavuQ2JXuFmuYH3C11xo988vSgp7UQrTRj1/go-ipfs-util"
	logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" // ID represents the identity of a peer.
	ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
)

var log = logging.Logger("peer")

type ID string

// Pretty returns a b58-encoded string of the ID
func (id ID) Pretty() string {
	return IDB58Encode(id)
}

func (id ID) Loggable() map[string]interface{} {
	return map[string]interface{}{
		"peerID": id.Pretty(),
	}
}

// String prints out the peer.
//
// TODO(brian): ensure correctness at ID generation and
// enforce this by only exposing functions that generate
// IDs safely. Then any peer.ID type found in the
// codebase is known to be correct.
func (id ID) String() string {
	pid := id.Pretty()

	//All sha256 nodes start with Qm
	//We can skip the Qm to make the peer.ID more useful
	if strings.HasPrefix(pid, "Qm") {
		pid = pid[2:]
	}

	maxRunes := 6
	if len(pid) < maxRunes {
		maxRunes = len(pid)
	}
	return fmt.Sprintf("<peer.ID %s>", pid[:maxRunes])
}

// MatchesPrivateKey tests whether this ID was derived from sk
func (id ID) MatchesPrivateKey(sk ic.PrivKey) bool {
	return id.MatchesPublicKey(sk.GetPublic())
}

// MatchesPublicKey tests whether this ID was derived from pk
func (id ID) MatchesPublicKey(pk ic.PubKey) bool {
	oid, err := IDFromPublicKey(pk)
	if err != nil {
		return false
	}
	return oid == id
}

// IDFromString cast a string to ID type, and validate
// the id to make sure it is a multihash.
func IDFromString(s string) (ID, error) {
	if _, err := mh.Cast([]byte(s)); err != nil {
		return ID(""), err
	}
	return ID(s), nil
}

// IDFromBytes cast a string to ID type, and validate
// the id to make sure it is a multihash.
func IDFromBytes(b []byte) (ID, error) {
	if _, err := mh.Cast(b); err != nil {
		return ID(""), err
	}
	return ID(b), nil
}

// IDB58Decode returns a b58-decoded Peer
func IDB58Decode(s string) (ID, error) {
	m, err := mh.FromB58String(s)
	if err != nil {
		return "", err
	}
	return ID(m), err
}

// IDB58Encode returns b58-encoded string
func IDB58Encode(id ID) string {
	return b58.Encode([]byte(id))
}

// IDHexDecode returns a b58-decoded Peer
func IDHexDecode(s string) (ID, error) {
	m, err := mh.FromHexString(s)
	if err != nil {
		return "", err
	}
	return ID(m), err
}

// IDHexEncode returns b58-encoded string
func IDHexEncode(id ID) string {
	return hex.EncodeToString([]byte(id))
}

// IDFromPublicKey returns the Peer ID corresponding to pk
func IDFromPublicKey(pk ic.PubKey) (ID, error) {
	b, err := pk.Bytes()
	if err != nil {
		return "", err
	}
	hash := u.Hash(b)
	return ID(hash), nil
}

// IDFromPrivateKey returns the Peer ID corresponding to sk
func IDFromPrivateKey(sk ic.PrivKey) (ID, error) {
	return IDFromPublicKey(sk.GetPublic())
}

// Map maps a Peer ID to a struct.
type Set map[ID]struct{}

// PeerInfo is a small struct used to pass around a peer with
// a set of addresses (and later, keys?). This is not meant to be
// a complete view of the system, but rather to model updates to
// the peerstore. It is used by things like the routing system.
type PeerInfo struct {
	ID    ID
	Addrs []ma.Multiaddr
}

func (pi *PeerInfo) Loggable() map[string]interface{} {
	return map[string]interface{}{
		"peerID": pi.ID.Pretty(),
		"addrs":  pi.Addrs,
	}
}

func (pi *PeerInfo) MarshalJSON() ([]byte, error) {
	out := make(map[string]interface{})
	out["ID"] = IDB58Encode(pi.ID)
	var addrs []string
	for _, a := range pi.Addrs {
		addrs = append(addrs, a.String())
	}
	out["Addrs"] = addrs
	return json.Marshal(out)
}

func (pi *PeerInfo) UnmarshalJSON(b []byte) error {
	var data map[string]interface{}
	err := json.Unmarshal(b, &data)
	if err != nil {
		return err
	}
	pid, err := IDB58Decode(data["ID"].(string))
	if err != nil {
		return err
	}
	pi.ID = pid
	addrs, ok := data["Addrs"].([]interface{})
	if ok {
		for _, a := range addrs {
			pi.Addrs = append(pi.Addrs, ma.StringCast(a.(string)))
		}
	}
	return nil
}

// IDSlice for sorting peers
type IDSlice []ID

func (es IDSlice) Len() int           { return len(es) }
func (es IDSlice) Swap(i, j int)      { es[i], es[j] = es[j], es[i] }
func (es IDSlice) Less(i, j int) bool { return string(es[i]) < string(es[j]) }
<|endoftext|>


<commit_before>package k8s_test

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"strconv"
	"testing"
	"time"

	"github.com/caarlos0/env"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"

	. "github.com/concourse/concourse/topgun"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

func TestK8s(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "K8s Suite")
}

type environment struct {
	ChartsDir            string `env:"CHARTS_DIR,required"`
	ConcourseChartDir    string `env:"CONCOURSE_CHART_DIR"`
	ConcourseImageDigest string `env:"CONCOURSE_IMAGE_DIGEST"`
	ConcourseImageName   string `env:"CONCOURSE_IMAGE_NAME,required"`
	ConcourseImageTag    string `env:"CONCOURSE_IMAGE_TAG"`
	FlyPath              string `env:"FLY_PATH"`
	K8sEngine            string `env:"K8S_ENGINE" envDefault:"GKE"`
}

var (
	Environment environment
	fly         Fly
	namespace   string
	releaseName string
)

var _ = SynchronizedBeforeSuite(func() []byte {
	var parsedEnv environment

	err := env.Parse(&parsedEnv)
	Expect(err).ToNot(HaveOccurred())

	if parsedEnv.FlyPath == "" {
		parsedEnv.FlyPath = BuildBinary()
	}

	if parsedEnv.ConcourseChartDir == "" {
		parsedEnv.ConcourseChartDir = path.Join(parsedEnv.ChartsDir, "stable/concourse")
	}

	By("Checking if kubectl has a context set")
	Wait(Start(nil, "kubectl", "config", "current-context"))

	By("Initializing the client side of helm")
	Wait(Start(nil, "helm", "init", "--client-only"))

	By("Updating the dependencies of the Concourse chart locally")
	Wait(Start(nil, "helm", "dependency", "update", parsedEnv.ConcourseChartDir))

	envBytes, err := json.Marshal(parsedEnv)
	Expect(err).ToNot(HaveOccurred())

	return envBytes
}, func(data []byte) {
	err := json.Unmarshal(data, &Environment)
	Expect(err).ToNot(HaveOccurred())
})

var _ = BeforeEach(func() {
	SetDefaultEventuallyTimeout(30 * time.Second)
	SetDefaultConsistentlyDuration(30 * time.Second)

	tmp, err := ioutil.TempDir("", "topgun-tmp")
	Expect(err).ToNot(HaveOccurred())

	fly = Fly{
		Bin:    Environment.FlyPath,
		Target: "concourse-topgun-k8s-" + strconv.Itoa(GinkgoParallelNode()),
		Home:   filepath.Join(tmp, "fly-home-"+strconv.Itoa(GinkgoParallelNode())),
	}

	err = os.Mkdir(fly.Home, 0755)
	Expect(err).ToNot(HaveOccurred())
})

func setReleaseNameAndNamespace(description string) {
	rand.Seed(time.Now().UTC().UnixNano())
	releaseName = fmt.Sprintf("topgun-"+description+"-%d", rand.Int63n(100000000))
	namespace = releaseName
}

type pod struct {
	Status struct {
		ContainerStatuses []struct {
			Name  string `json:"name"`
			Ready bool   `json:"ready"`
		} `json:"containerStatuses"`
		Phase  string `json:"phase"`
		HostIp string `json:"hostIP"`
		Ip     string `json:"podIP"`
	} `json:"status"`
	Metadata struct {
		Name string `json:"name"`
	} `json:"metadata"`
}

type podListResponse struct {
	Items []pod `json:"items"`
}

func helmDeploy(releaseName, namespace, chartDir string, args ...string) *gexec.Session {
	helmArgs := []string{
		"upgrade",
		"--install",
		"--force",
		"--wait",
		"--namespace", namespace,
	}

	helmArgs = append(helmArgs, args...)
	helmArgs = append(helmArgs, releaseName, chartDir)

	sess := Start(nil, "helm", helmArgs...)
	<-sess.Exited
	return sess
}

func helmInstallArgs(args ...string) []string {
	helmArgs := []string{
		"--set=web.livenessProbe.failureThreshold=3",
		"--set=web.livenessProbe.initialDelaySeconds=3",
		"--set=web.livenessProbe.periodSeconds=3",
		"--set=web.livenessProbe.timeoutSeconds=3",
		"--set=concourse.web.kubernetes.keepNamespaces=false",
		"--set=postgresql.persistence.enabled=false",
		"--set=image=" + Environment.ConcourseImageName}

	if Environment.ConcourseImageTag != "" {
		helmArgs = append(helmArgs, "--set=imageTag="+Environment.ConcourseImageTag)
	}

	if Environment.ConcourseImageDigest != "" {
		helmArgs = append(helmArgs, "--set=imageDigest="+Environment.ConcourseImageDigest)
	}

	return append(helmArgs, args...)
}

func deployFailingConcourseChart(releaseName string, expectedErr string, args ...string) {
	helmArgs := helmInstallArgs(args...)
	sess := helmDeploy(releaseName, releaseName, Environment.ConcourseChartDir, helmArgs...)
	Expect(sess.ExitCode()).ToNot(Equal(0))
	Expect(sess.Err).To(gbytes.Say(expectedErr))
}

func deployConcourseChart(releaseName string, args ...string) {
	helmArgs := helmInstallArgs(args...)
	sess := helmDeploy(releaseName, releaseName, Environment.ConcourseChartDir, helmArgs...)
	Expect(sess.ExitCode()).To(Equal(0))
}

func helmDestroy(releaseName string) {
	helmArgs := []string{
		"delete",
		"--purge",
		releaseName,
	}

	Wait(Start(nil, "helm", helmArgs...))
}

func getPods(namespace string, flags ...string) []pod {
	var (
		pods podListResponse
		args = append([]string{"get", "pods",
			"--namespace=" + namespace,
			"--output=json",
			"--no-headers"}, flags...)
		session = Start(nil, "kubectl", args...)
	)

	Wait(session)

	err := json.Unmarshal(session.Out.Contents(), &pods)
	Expect(err).ToNot(HaveOccurred())

	return pods.Items
}

func isPodReady(p pod) bool {
	total := len(p.Status.ContainerStatuses)
	actual := 0

	for _, containerStatus := range p.Status.ContainerStatuses {
		if containerStatus.Ready {
			actual++
		}
	}

	return total == actual
}

func waitAllPodsInNamespaceToBeReady(namespace string) {
	Eventually(func() bool {
		expectedPods := getPods(namespace)
		actualPods := getPods(namespace, "--field-selector=status.phase=Running")

		if len(expectedPods) != len(actualPods) {
			return false
		}

		podsReady := 0
		for _, pod := range actualPods {
			if isPodReady(pod) {
				podsReady++
			}
		}

		return podsReady == len(expectedPods)
	}, 5*time.Minute, 10*time.Second).Should(BeTrue(), "expected all pods to be running")
}

func deletePods(namespace string, flags ...string) []string {
	var (
		podNames []string
		args     = append([]string{"delete", "pod",
			"--namespace=" + namespace,
		}, flags...)
		session = Start(nil, "kubectl", args...)
	)

	Wait(session)

	scanner := bufio.NewScanner(bytes.NewBuffer(session.Out.Contents()))
	for scanner.Scan() {
		podNames = append(podNames, scanner.Text())
	}

	return podNames
}

func startPortForwardingWithProtocol(namespace, resource, port, protocol string) (*gexec.Session, string) {
	session := Start(nil, "kubectl", "port-forward", "--namespace="+namespace, resource, ":"+port)
	Eventually(session.Out).Should(gbytes.Say("Forwarding"))

	address := regexp.MustCompile(`127\.0\.0\.1:[0-9]+`).
		FindStringSubmatch(string(session.Out.Contents()))

	Expect(address).NotTo(BeEmpty())

	return session, protocol + "://" + address[0]
}

func startPortForwarding(namespace, resource, port string) (*gexec.Session, string) {
	return startPortForwardingWithProtocol(namespace, resource, port, "http")
}

func getRunningWorkers(workers []Worker) (running []Worker) {
	for _, w := range workers {
		if w.State == "running" {
			running = append(running, w)
		}
	}
	return
}

func cleanup(releaseName, namespace string, proxySession *gexec.Session) {
	helmDestroy(releaseName)
	Run(nil, "kubectl", "delete", "namespace", namespace, "--wait=false")

	if proxySession != nil {
		Wait(proxySession.Interrupt())
	}
}

func onPks(f func()) {
	Context("PKS", func() {

		BeforeEach(func() {
			if Environment.K8sEngine != "PKS" {
				Skip("not running on PKS")
			}
		})

		f()
	})
}

func onGke(f func()) {
	Context("GKE", func() {

		BeforeEach(func() {
			if Environment.K8sEngine != "GKE" {
				Skip("not running on GKE")
			}
		})

		f()
	})
}
<commit_msg>k8s topgun refers to new FlyCli type<commit_after>package k8s_test

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"strconv"
	"testing"
	"time"

	"github.com/caarlos0/env"
	"github.com/onsi/gomega/gbytes"
	"github.com/onsi/gomega/gexec"

	. "github.com/concourse/concourse/topgun"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

func TestK8s(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "K8s Suite")
}

type environment struct {
	ChartsDir            string `env:"CHARTS_DIR,required"`
	ConcourseChartDir    string `env:"CONCOURSE_CHART_DIR"`
	ConcourseImageDigest string `env:"CONCOURSE_IMAGE_DIGEST"`
	ConcourseImageName   string `env:"CONCOURSE_IMAGE_NAME,required"`
	ConcourseImageTag    string `env:"CONCOURSE_IMAGE_TAG"`
	FlyPath              string `env:"FLY_PATH"`
	K8sEngine            string `env:"K8S_ENGINE" envDefault:"GKE"`
}

var (
	Environment environment
	fly         FlyCli
	namespace   string
	releaseName string
)

var _ = SynchronizedBeforeSuite(func() []byte {
	var parsedEnv environment

	err := env.Parse(&parsedEnv)
	Expect(err).ToNot(HaveOccurred())

	if parsedEnv.FlyPath == "" {
		parsedEnv.FlyPath = BuildBinary()
	}

	if parsedEnv.ConcourseChartDir == "" {
		parsedEnv.ConcourseChartDir = path.Join(parsedEnv.ChartsDir, "stable/concourse")
	}

	By("Checking if kubectl has a context set")
	Wait(Start(nil, "kubectl", "config", "current-context"))

	By("Initializing the client side of helm")
	Wait(Start(nil, "helm", "init", "--client-only"))

	By("Updating the dependencies of the Concourse chart locally")
	Wait(Start(nil, "helm", "dependency", "update", parsedEnv.ConcourseChartDir))

	envBytes, err := json.Marshal(parsedEnv)
	Expect(err).ToNot(HaveOccurred())

	return envBytes
}, func(data []byte) {
	err := json.Unmarshal(data, &Environment)
	Expect(err).ToNot(HaveOccurred())
})

var _ = BeforeEach(func() {
	SetDefaultEventuallyTimeout(30 * time.Second)
	SetDefaultConsistentlyDuration(30 * time.Second)

	tmp, err := ioutil.TempDir("", "topgun-tmp")
	Expect(err).ToNot(HaveOccurred())

	fly = FlyCli{
		Bin:    Environment.FlyPath,
		Target: "concourse-topgun-k8s-" + strconv.Itoa(GinkgoParallelNode()),
		Home:   filepath.Join(tmp, "fly-home-"+strconv.Itoa(GinkgoParallelNode())),
	}

	err = os.Mkdir(fly.Home, 0755)
	Expect(err).ToNot(HaveOccurred())
})

func setReleaseNameAndNamespace(description string) {
	rand.Seed(time.Now().UTC().UnixNano())
	releaseName = fmt.Sprintf("topgun-"+description+"-%d", rand.Int63n(100000000))
	namespace = releaseName
}

type pod struct {
	Status struct {
		ContainerStatuses []struct {
			Name  string `json:"name"`
			Ready bool   `json:"ready"`
		} `json:"containerStatuses"`
		Phase  string `json:"phase"`
		HostIp string `json:"hostIP"`
		Ip     string `json:"podIP"`
	} `json:"status"`
	Metadata struct {
		Name string `json:"name"`
	} `json:"metadata"`
}

type podListResponse struct {
	Items []pod `json:"items"`
}

func helmDeploy(releaseName, namespace, chartDir string, args ...string) *gexec.Session {
	helmArgs := []string{
		"upgrade",
		"--install",
		"--force",
		"--wait",
		"--namespace", namespace,
	}

	helmArgs = append(helmArgs, args...)
	helmArgs = append(helmArgs, releaseName, chartDir)

	sess := Start(nil, "helm", helmArgs...)
	<-sess.Exited
	return sess
}

func helmInstallArgs(args ...string) []string {
	helmArgs := []string{
		"--set=web.livenessProbe.failureThreshold=3",
		"--set=web.livenessProbe.initialDelaySeconds=3",
		"--set=web.livenessProbe.periodSeconds=3",
		"--set=web.livenessProbe.timeoutSeconds=3",
		"--set=concourse.web.kubernetes.keepNamespaces=false",
		"--set=postgresql.persistence.enabled=false",
		"--set=image=" + Environment.ConcourseImageName}

	if Environment.ConcourseImageTag != "" {
		helmArgs = append(helmArgs, "--set=imageTag="+Environment.ConcourseImageTag)
	}

	if Environment.ConcourseImageDigest != "" {
		helmArgs = append(helmArgs, "--set=imageDigest="+Environment.ConcourseImageDigest)
	}

	return append(helmArgs, args...)
}

func deployFailingConcourseChart(releaseName string, expectedErr string, args ...string) {
	helmArgs := helmInstallArgs(args...)
	sess := helmDeploy(releaseName, releaseName, Environment.ConcourseChartDir, helmArgs...)
	Expect(sess.ExitCode()).ToNot(Equal(0))
	Expect(sess.Err).To(gbytes.Say(expectedErr))
}

func deployConcourseChart(releaseName string, args ...string) {
	helmArgs := helmInstallArgs(args...)
	sess := helmDeploy(releaseName, releaseName, Environment.ConcourseChartDir, helmArgs...)
	Expect(sess.ExitCode()).To(Equal(0))
}

func helmDestroy(releaseName string) {
	helmArgs := []string{
		"delete",
		"--purge",
		releaseName,
	}

	Wait(Start(nil, "helm", helmArgs...))
}

func getPods(namespace string, flags ...string) []pod {
	var (
		pods podListResponse
		args = append([]string{"get", "pods",
			"--namespace=" + namespace,
			"--output=json",
			"--no-headers"}, flags...)
		session = Start(nil, "kubectl", args...)
	)

	Wait(session)

	err := json.Unmarshal(session.Out.Contents(), &pods)
	Expect(err).ToNot(HaveOccurred())

	return pods.Items
}

func isPodReady(p pod) bool {
	total := len(p.Status.ContainerStatuses)
	actual := 0

	for _, containerStatus := range p.Status.ContainerStatuses {
		if containerStatus.Ready {
			actual++
		}
	}

	return total == actual
}

func waitAllPodsInNamespaceToBeReady(namespace string) {
	Eventually(func() bool {
		expectedPods := getPods(namespace)
		actualPods := getPods(namespace, "--field-selector=status.phase=Running")

		if len(expectedPods) != len(actualPods) {
			return false
		}

		podsReady := 0
		for _, pod := range actualPods {
			if isPodReady(pod) {
				podsReady++
			}
		}

		return podsReady == len(expectedPods)
	}, 5*time.Minute, 10*time.Second).Should(BeTrue(), "expected all pods to be running")
}

func deletePods(namespace string, flags ...string) []string {
	var (
		podNames []string
		args     = append([]string{"delete", "pod",
			"--namespace=" + namespace,
		}, flags...)
		session = Start(nil, "kubectl", args...)
	)

	Wait(session)

	scanner := bufio.NewScanner(bytes.NewBuffer(session.Out.Contents()))
	for scanner.Scan() {
		podNames = append(podNames, scanner.Text())
	}

	return podNames
}

func startPortForwardingWithProtocol(namespace, resource, port, protocol string) (*gexec.Session, string) {
	session := Start(nil, "kubectl", "port-forward", "--namespace="+namespace, resource, ":"+port)
	Eventually(session.Out).Should(gbytes.Say("Forwarding"))

	address := regexp.MustCompile(`127\.0\.0\.1:[0-9]+`).
		FindStringSubmatch(string(session.Out.Contents()))

	Expect(address).NotTo(BeEmpty())

	return session, protocol + "://" + address[0]
}

func startPortForwarding(namespace, resource, port string) (*gexec.Session, string) {
	return startPortForwardingWithProtocol(namespace, resource, port, "http")
}

func getRunningWorkers(workers []Worker) (running []Worker) {
	for _, w := range workers {
		if w.State == "running" {
			running = append(running, w)
		}
	}
	return
}

func cleanup(releaseName, namespace string, proxySession *gexec.Session) {
	helmDestroy(releaseName)
	Run(nil, "kubectl", "delete", "namespace", namespace, "--wait=false")

	if proxySession != nil {
		Wait(proxySession.Interrupt())
	}
}

func onPks(f func()) {
	Context("PKS", func() {

		BeforeEach(func() {
			if Environment.K8sEngine != "PKS" {
				Skip("not running on PKS")
			}
		})

		f()
	})
}

func onGke(f func()) {
	Context("GKE", func() {

		BeforeEach(func() {
			if Environment.K8sEngine != "GKE" {
				Skip("not running on GKE")
			}
		})

		f()
	})
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"strings"

	log "github.com/sirupsen/logrus"
	"github.com/spf13/cobra"

	"github.com/authelia/authelia/internal/utils"
)

func buildAutheliaBinary(xflags []string) {
	cmd := utils.CommandWithStdout("go", "build", "-o", "../../"+OutputDir+"/authelia", "-ldflags", strings.Join(xflags, " "))
	cmd.Dir = "cmd/authelia"

	cmd.Env = append(os.Environ(),
		"GOOS=linux", "GOARCH=amd64", "CGO_ENABLED=0")

	err := cmd.Run()
	if err != nil {
		log.Fatal(err)
	}
}

func buildFrontend() {
	cmd := utils.CommandWithStdout("yarn", "install")
	cmd.Dir = webDirectory

	err := cmd.Run()
	if err != nil {
		log.Fatal(err)
	}

	cmd = utils.CommandWithStdout("yarn", "build")
	cmd.Dir = webDirectory

	cmd.Env = append(os.Environ(), "INLINE_RUNTIME_CHUNK=false")

	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}

	cmd = utils.CommandWithStdout("rm", "-rf", "internal/server/public_html")

	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}

	err = os.Rename("web/build", "internal/server/public_html")
	if err != nil {
		log.Fatal(err)
	}
}

func buildSwagger() {
	swaggerVer := "3.50.0"
	cmd := utils.CommandWithStdout("bash", "-c", "wget -q https://github.com/swagger-api/swagger-ui/archive/v"+swaggerVer+".tar.gz -O ./v"+swaggerVer+".tar.gz")

	err := cmd.Run()
	if err != nil {
		log.Fatal(err)
	}

	cmd = utils.CommandWithStdout("cp", "-r", "api", "internal/server/public_html")

	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}

	cmd = utils.CommandWithStdout("tar", "-C", "internal/server/public_html/api", "--exclude=index.html", "--strip-components=2", "-xf", "v"+swaggerVer+".tar.gz", "swagger-ui-"+swaggerVer+"/dist")

	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}

	cmd = utils.CommandWithStdout("rm", "./v"+swaggerVer+".tar.gz")

	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}
}

func cleanAssets() {
	if err := os.Rename("internal/server/public_html", OutputDir+"/public_html"); err != nil {
		log.Fatal(err)
	}

	cmd := utils.CommandWithStdout("mkdir", "-p", "internal/server/public_html/api")

	if err := cmd.Run(); err != nil {
		log.Fatal(err)
	}

	cmd = utils.CommandWithStdout("bash", "-c", "touch internal/server/public_html/{index.html,api/index.html,api/openapi.yml}")

	if err := cmd.Run(); err != nil {
		log.Fatal(err)
	}
}

// Build build Authelia.
func Build(cobraCmd *cobra.Command, args []string) {
	log.Info("Building Authelia...")

	Clean(cobraCmd, args)

	xflags, err := getXFlags("", "0", "")
	if err != nil {
		log.Fatal(err)
	}

	log.Debug("Creating `" + OutputDir + "` directory")
	err = os.MkdirAll(OutputDir, os.ModePerm)

	if err != nil {
		log.Fatal(err)
	}

	log.Debug("Building Authelia frontend...")
	buildFrontend()

	log.Debug("Building swagger-ui frontend...")
	buildSwagger()

	log.Debug("Building Authelia Go binary...")
	buildAutheliaBinary(xflags)
	cleanAssets()
}
<commit_msg>build(deps): update swagger-ui to v3.51.0 (#2118)<commit_after>package main

import (
	"os"
	"strings"

	log "github.com/sirupsen/logrus"
	"github.com/spf13/cobra"

	"github.com/authelia/authelia/internal/utils"
)

func buildAutheliaBinary(xflags []string) {
	cmd := utils.CommandWithStdout("go", "build", "-o", "../../"+OutputDir+"/authelia", "-ldflags", strings.Join(xflags, " "))
	cmd.Dir = "cmd/authelia"

	cmd.Env = append(os.Environ(),
		"GOOS=linux", "GOARCH=amd64", "CGO_ENABLED=0")

	err := cmd.Run()
	if err != nil {
		log.Fatal(err)
	}
}

func buildFrontend() {
	cmd := utils.CommandWithStdout("yarn", "install")
	cmd.Dir = webDirectory

	err := cmd.Run()
	if err != nil {
		log.Fatal(err)
	}

	cmd = utils.CommandWithStdout("yarn", "build")
	cmd.Dir = webDirectory

	cmd.Env = append(os.Environ(), "INLINE_RUNTIME_CHUNK=false")

	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}

	cmd = utils.CommandWithStdout("rm", "-rf", "internal/server/public_html")

	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}

	err = os.Rename("web/build", "internal/server/public_html")
	if err != nil {
		log.Fatal(err)
	}
}

func buildSwagger() {
	swaggerVer := "3.51.0"
	cmd := utils.CommandWithStdout("bash", "-c", "wget -q https://github.com/swagger-api/swagger-ui/archive/v"+swaggerVer+".tar.gz -O ./v"+swaggerVer+".tar.gz")

	err := cmd.Run()
	if err != nil {
		log.Fatal(err)
	}

	cmd = utils.CommandWithStdout("cp", "-r", "api", "internal/server/public_html")

	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}

	cmd = utils.CommandWithStdout("tar", "-C", "internal/server/public_html/api", "--exclude=index.html", "--strip-components=2", "-xf", "v"+swaggerVer+".tar.gz", "swagger-ui-"+swaggerVer+"/dist")

	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}

	cmd = utils.CommandWithStdout("rm", "./v"+swaggerVer+".tar.gz")

	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}
}

func cleanAssets() {
	if err := os.Rename("internal/server/public_html", OutputDir+"/public_html"); err != nil {
		log.Fatal(err)
	}

	cmd := utils.CommandWithStdout("mkdir", "-p", "internal/server/public_html/api")

	if err := cmd.Run(); err != nil {
		log.Fatal(err)
	}

	cmd = utils.CommandWithStdout("bash", "-c", "touch internal/server/public_html/{index.html,api/index.html,api/openapi.yml}")

	if err := cmd.Run(); err != nil {
		log.Fatal(err)
	}
}

// Build build Authelia.
func Build(cobraCmd *cobra.Command, args []string) {
	log.Info("Building Authelia...")

	Clean(cobraCmd, args)

	xflags, err := getXFlags("", "0", "")
	if err != nil {
		log.Fatal(err)
	}

	log.Debug("Creating `" + OutputDir + "` directory")
	err = os.MkdirAll(OutputDir, os.ModePerm)

	if err != nil {
		log.Fatal(err)
	}

	log.Debug("Building Authelia frontend...")
	buildFrontend()

	log.Debug("Building swagger-ui frontend...")
	buildSwagger()

	log.Debug("Building Authelia Go binary...")
	buildAutheliaBinary(xflags)
	cleanAssets()
}
<|endoftext|>


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

package router_test

import (
	"net/url"

	"github.com/tsuru/config"
	"github.com/tsuru/tsuru/db"
	"github.com/tsuru/tsuru/db/dbtest"
	"github.com/tsuru/tsuru/router"
	_ "github.com/tsuru/tsuru/router/hipache"
	_ "github.com/tsuru/tsuru/router/routertest"
	"gopkg.in/check.v1"
)

type ExternalSuite struct {
	conn *db.Storage
}

var _ = check.Suite(&ExternalSuite{})

func (s *ExternalSuite) SetUpSuite(c *check.C) {
	config.Set("hipache:domain", "swaptest.org")
	config.Set("database:url", "127.0.0.1:27017")
	config.Set("database:name", "router_swap_tests")
	config.Set("routers:fake:type", "fake")
}

func (s *ExternalSuite) SetUpTest(c *check.C) {
	var err error
	s.conn, err = db.Conn()
	c.Assert(err, check.IsNil)
	dbtest.ClearAllCollections(s.conn.Collection("router").Database)
}

func (s *ExternalSuite) TearDownTest(c *check.C) {
	s.conn.Close()
}

func (s *ExternalSuite) TearDownSuite(c *check.C) {
	conn, err := db.Conn()
	c.Assert(err, check.IsNil)
	defer conn.Close()
	conn.Apps().Database.DropDatabase()
}

func (s *ExternalSuite) TestSwap(c *check.C) {
	backend1 := "b1"
	backend2 := "b2"
	r, err := router.Get("fake")
	c.Assert(err, check.IsNil)
	r.AddBackend(backend1)
	addr1, _ := url.Parse("http://127.0.0.1")
	r.AddRoute(backend1, addr1)
	r.AddBackend(backend2)
	addr2, _ := url.Parse("http://10.10.10.10")
	r.AddRoute(backend2, addr2)
	err = router.Swap(r, backend1, backend2)
	c.Assert(err, check.IsNil)
	routes1, err := r.Routes(backend1)
	c.Assert(err, check.IsNil)
	c.Assert(routes1, check.DeepEquals, []*url.URL{addr1})
	routes2, err := r.Routes(backend2)
	c.Assert(err, check.IsNil)
	c.Assert(routes2, check.DeepEquals, []*url.URL{addr2})
	name1, err := router.Retrieve(backend1)
	c.Assert(err, check.IsNil)
	c.Assert(name1, check.Equals, backend2)
	name2, err := router.Retrieve(backend2)
	c.Assert(err, check.IsNil)
	c.Assert(name2, check.Equals, backend1)
}

func (s *ExternalSuite) TestSwapWithDifferentRouterKinds(c *check.C) {
	config.Set("hipache:redis-server", "127.0.0.1:6379")
	config.Set("hipache:redis-db", 5)
	backend1 := "bb1"
	backend2 := "bb2"
	r1, err := router.Get("fake")
	c.Assert(err, check.IsNil)
	r2, err := router.Get("hipache")
	c.Assert(err, check.IsNil)
	err = r1.AddBackend(backend1)
	c.Assert(err, check.IsNil)
	addr1, _ := url.Parse("http://127.0.0.1")
	err = r1.AddRoute(backend1, addr1)
	c.Assert(err, check.IsNil)
	err = r2.AddBackend(backend2)
	c.Assert(err, check.IsNil)
	addr2, _ := url.Parse("http://10.10.10.10")
	err = r2.AddRoute(backend2, addr2)
	c.Assert(err, check.IsNil)
	err = router.Swap(r1, backend1, backend2)
	c.Assert(err, check.ErrorMatches, `swap is only allowed between routers of the same kind. "bb1" uses "fake", "bb2" uses "hipache"`)
	err = router.Swap(r2, backend1, backend2)
	c.Assert(err, check.ErrorMatches, `swap is only allowed between routers of the same kind. "bb1" uses "fake", "bb2" uses "hipache"`)
}
<commit_msg>router: add cleanup in test<commit_after>// Copyright 2016 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package router_test

import (
	"net/url"

	"github.com/tsuru/config"
	"github.com/tsuru/tsuru/db"
	"github.com/tsuru/tsuru/db/dbtest"
	"github.com/tsuru/tsuru/router"
	_ "github.com/tsuru/tsuru/router/hipache"
	_ "github.com/tsuru/tsuru/router/routertest"
	"gopkg.in/check.v1"
)

type ExternalSuite struct {
	conn *db.Storage
}

var _ = check.Suite(&ExternalSuite{})

func (s *ExternalSuite) SetUpSuite(c *check.C) {
	config.Set("hipache:domain", "swaptest.org")
	config.Set("database:url", "127.0.0.1:27017")
	config.Set("database:name", "router_swap_tests")
	config.Set("routers:fake:type", "fake")
}

func (s *ExternalSuite) SetUpTest(c *check.C) {
	var err error
	s.conn, err = db.Conn()
	c.Assert(err, check.IsNil)
	dbtest.ClearAllCollections(s.conn.Collection("router").Database)
}

func (s *ExternalSuite) TearDownTest(c *check.C) {
	s.conn.Close()
}

func (s *ExternalSuite) TearDownSuite(c *check.C) {
	conn, err := db.Conn()
	c.Assert(err, check.IsNil)
	defer conn.Close()
	conn.Apps().Database.DropDatabase()
}

func (s *ExternalSuite) TestSwap(c *check.C) {
	backend1 := "b1"
	backend2 := "b2"
	r, err := router.Get("fake")
	c.Assert(err, check.IsNil)
	r.AddBackend(backend1)
	addr1, _ := url.Parse("http://127.0.0.1")
	r.AddRoute(backend1, addr1)
	r.AddBackend(backend2)
	addr2, _ := url.Parse("http://10.10.10.10")
	r.AddRoute(backend2, addr2)
	err = router.Swap(r, backend1, backend2)
	c.Assert(err, check.IsNil)
	routes1, err := r.Routes(backend1)
	c.Assert(err, check.IsNil)
	c.Assert(routes1, check.DeepEquals, []*url.URL{addr1})
	routes2, err := r.Routes(backend2)
	c.Assert(err, check.IsNil)
	c.Assert(routes2, check.DeepEquals, []*url.URL{addr2})
	name1, err := router.Retrieve(backend1)
	c.Assert(err, check.IsNil)
	c.Assert(name1, check.Equals, backend2)
	name2, err := router.Retrieve(backend2)
	c.Assert(err, check.IsNil)
	c.Assert(name2, check.Equals, backend1)
}

func (s *ExternalSuite) TestSwapWithDifferentRouterKinds(c *check.C) {
	config.Set("hipache:redis-server", "127.0.0.1:6379")
	config.Set("hipache:redis-db", 5)
	backend1 := "bb1"
	backend2 := "bb2"
	r1, err := router.Get("fake")
	c.Assert(err, check.IsNil)
	r2, err := router.Get("hipache")
	c.Assert(err, check.IsNil)
	err = r1.AddBackend(backend1)
	c.Assert(err, check.IsNil)
	defer r1.RemoveBackend(backend1)
	addr1, _ := url.Parse("http://127.0.0.1")
	err = r1.AddRoute(backend1, addr1)
	c.Assert(err, check.IsNil)
	defer r1.RemoveRoute(backend1, addr1)
	err = r2.AddBackend(backend2)
	c.Assert(err, check.IsNil)
	defer r2.RemoveBackend(backend2)
	addr2, _ := url.Parse("http://10.10.10.10")
	err = r2.AddRoute(backend2, addr2)
	c.Assert(err, check.IsNil)
	defer r2.RemoveRoute(backend2, addr2)
	err = router.Swap(r1, backend1, backend2)
	c.Assert(err, check.ErrorMatches, `swap is only allowed between routers of the same kind. "bb1" uses "fake", "bb2" uses "hipache"`)
	err = router.Swap(r2, backend1, backend2)
	c.Assert(err, check.ErrorMatches, `swap is only allowed between routers of the same kind. "bb1" uses "fake", "bb2" uses "hipache"`)
}
<|endoftext|>


<commit_before>// Package packet implements the iSCSI PDU packet format as specified in
// rfc7143 section 11.
package packet

import (
	"fmt"
	"io"
	"strings"
)

type opCode int

const (
	// Defined on the initiator.
	opNoopOut     opCode = 0x00
	opSCSICmd            = 0x01
	opSCSITaskReq        = 0x02
	opLoginReq           = 0x03
	opTextReq            = 0x04
	opSCSIOut            = 0x05
	opLogoutReq          = 0x06
	opSNACKReq           = 0x10
	// Defined on the target.
	opNoopIn       opCode = 0x20
	opSCSIResp            = 0x21
	opSCSITaskResp        = 0x22
	opLoginResp           = 0x23
	opTextResp            = 0x24
	opSCSIIn              = 0x25
	opLogoutResp          = 0x26
	opReady               = 0x31
	opAsync               = 0x32
	opReject              = 0x3f
)

var opCodeMap = map[opCode]string{
	opNoopOut:      "NOP-Out",
	opSCSICmd:      "SCSI Command",
	opSCSITaskReq:  "SCSI Task Management FunctionRequest",
	opLoginReq:     "Login Request",
	opTextReq:      "Text Request",
	opSCSIOut:      "SCSI Data-Out (write)",
	opLogoutReq:    "Logout Request",
	opSNACKReq:     "SNACK Request",
	opNoopIn:       "NOP-In",
	opSCSIResp:     "SCSI Response",
	opSCSITaskResp: "SCSI Task Management Function Response",
	opLoginResp:    "Login Response",
	opTextResp:     "Text Response",
	opSCSIIn:       "SCSI Data-In (read)",
	opLogoutResp:   "Logout Response",
	opReady:        "Ready To Transfer (R2T)",
	opAsync:        "Asynchronous Message",
	opReject:       "Reject",
}

func (c opCode) String() string {
	s := opCodeMap[c]
	if s == "" {
		s = fmt.Sprintf("Unknown Code: %x", int(c))
	}
	return s
}

type Message struct {
	opCode    opCode
	header    []byte
	final     bool
	immediate bool
	dataLen   int
	data      []byte
	taskTag   uint32
	ahsLen    int

	connID    uint16
	cmdSN     uint32
	expStatSN uint32

	// valid when opCode == opSCSICmd
	read, write bool
	lun         int

	// valid for opLoginReq
	transit  bool
	cont     bool
	csg, nsg int
	isid     uint64
	tsih     uint16
}

func (m *Message) String() string {
	var s []string
	s = append(s, fmt.Sprintf("Op: %v", m.opCode))
	s = append(s, fmt.Sprintf("Final = %v", m.final))
	s = append(s, fmt.Sprintf("Immediate = %v", m.immediate))
	s = append(s, fmt.Sprintf("Total AHS Length = %d", m.ahsLen))
	s = append(s, fmt.Sprintf("Data Segment Length = %d", m.dataLen))
	s = append(s, fmt.Sprintf("Task Tag = %x", m.taskTag))
	switch m.opCode {
	case opSCSICmd:
		s = append(s, fmt.Sprintf("LUN = %d", m.lun))
	case opLoginReq:
		s = append(s, fmt.Sprintf("Transit = %v", m.transit))
		s = append(s, fmt.Sprintf("Continue = %v", m.cont))
		s = append(s, fmt.Sprintf("Connection ID = %x", m.connID))
	}
	return strings.Join(s, "\n")
}

func Next(r io.Reader) (*Message, error) {
	buf := make([]byte, 48) // sync.Pool
	if _, err := io.ReadFull(r, buf); err != nil {
		return nil, err
	}
	m, err := parseHeader(buf)
	if err != nil {
		return nil, err
	}
	m.header = buf
	if m.dataLen > 0 {
		dl := m.dataLen
		for dl%4 > 0 {
			dl++
		}
		data := make([]byte, dl)
		if _, err := io.ReadFull(r, data); err != nil {
			return nil, err
		}
		m.data = data
	}
	return m, nil
}

// parseUint parses the given slice as a network-byte-ordered integer.  If
// there are more than 8 bytes in data, it overflows.
func parseUint(data []byte) uint64 {
	var out uint64
	for i := 0; i < len(data); i++ {
		out += uint64(data[len(data)-i-1]) << uint(8*i)
	}
	return out
}

func parseHeader(data []byte) (*Message, error) {
	if len(data) < 48 {
		return nil, fmt.Errorf("garbled header")
	}
	// TODO: sync.Pool
	m := &Message{}
	m.immediate = 0x40&data[0] == 0x40
	m.opCode = opCode(data[0] & 0x3f)
	m.final = 0x80&data[1] == 0x80
	m.ahsLen = int(data[4]) * 4
	m.dataLen = int(parseUint(data[5:8]))
	m.taskTag = uint32(parseUint(data[16:20]))
	switch m.opCode {
	case opSCSICmd:
		m.lun = int(parseUint(data[8:16]))
	case opLoginReq:
		m.transit = m.final
		m.cont = data[1]&0x40 == 0x40
		if m.cont && m.transit {
			// rfc7143 11.12.2
			return nil, fmt.Errorf("transit and continue bits set in same login request")
		}
		m.csg = int(data[1]&0xc) >> 2
		m.nsg = int(data[1] & 0x3)
		m.connID = uint16(parseUint(data[20:22]))
		m.cmdSN = uint32(parseUint(data[24:28]))
		m.expStatSN = uint32(parseUint(data[28:32]))
	}
	return m, nil
}
<commit_msg>Convenience functions for message handling.<commit_after>// Package packet implements the iSCSI PDU packet format as specified in
// rfc7143 section 11.
package packet

import (
	"fmt"
	"io"
	"strings"
)

type opCode int

const (
	// Defined on the initiator.
	opNoopOut     opCode = 0x00
	opSCSICmd            = 0x01
	opSCSITaskReq        = 0x02
	opLoginReq           = 0x03
	opTextReq            = 0x04
	opSCSIOut            = 0x05
	opLogoutReq          = 0x06
	opSNACKReq           = 0x10
	// Defined on the target.
	opNoopIn       opCode = 0x20
	opSCSIResp            = 0x21
	opSCSITaskResp        = 0x22
	opLoginResp           = 0x23
	opTextResp            = 0x24
	opSCSIIn              = 0x25
	opLogoutResp          = 0x26
	opReady               = 0x31
	opAsync               = 0x32
	opReject              = 0x3f
)

var opCodeMap = map[opCode]string{
	opNoopOut:      "NOP-Out",
	opSCSICmd:      "SCSI Command",
	opSCSITaskReq:  "SCSI Task Management FunctionRequest",
	opLoginReq:     "Login Request",
	opTextReq:      "Text Request",
	opSCSIOut:      "SCSI Data-Out (write)",
	opLogoutReq:    "Logout Request",
	opSNACKReq:     "SNACK Request",
	opNoopIn:       "NOP-In",
	opSCSIResp:     "SCSI Response",
	opSCSITaskResp: "SCSI Task Management Function Response",
	opLoginResp:    "Login Response",
	opTextResp:     "Text Response",
	opSCSIIn:       "SCSI Data-In (read)",
	opLogoutResp:   "Logout Response",
	opReady:        "Ready To Transfer (R2T)",
	opAsync:        "Asynchronous Message",
	opReject:       "Reject",
}

func (c opCode) String() string {
	s := opCodeMap[c]
	if s == "" {
		s = fmt.Sprintf("Unknown Code: %x", int(c))
	}
	return s
}

type Message struct {
	opCode    opCode
	header    []byte
	final     bool
	immediate bool
	dataLen   int
	data      []byte
	taskTag   uint32
	ahsLen    int

	connID    uint16
	cmdSN     uint32
	expStatSN uint32

	// valid when opCode == opSCSICmd
	read, write bool
	lun         int

	// valid for opLoginReq
	transit  bool
	cont     bool
	csg, nsg int
	isid     uint64
	tsih     uint16
}

func (m *Message) Data() []byte {
	return m.data[:m.dataLen]
}

func (m *Message) String() string {
	var s []string
	s = append(s, fmt.Sprintf("Op: %v", m.opCode))
	s = append(s, fmt.Sprintf("Final = %v", m.final))
	s = append(s, fmt.Sprintf("Immediate = %v", m.immediate))
	s = append(s, fmt.Sprintf("Total AHS Length = %d", m.ahsLen))
	s = append(s, fmt.Sprintf("Data Segment Length = %d", m.dataLen))
	s = append(s, fmt.Sprintf("Task Tag = %x", m.taskTag))
	switch m.opCode {
	case opSCSICmd:
		s = append(s, fmt.Sprintf("LUN = %d", m.lun))
	case opLoginReq:
		s = append(s, fmt.Sprintf("Transit = %v", m.transit))
		s = append(s, fmt.Sprintf("Continue = %v", m.cont))
		s = append(s, fmt.Sprintf("Connection ID = %x", m.connID))
	}
	return strings.Join(s, "\n")
}

func Next(r io.Reader) (*Message, error) {
	buf := make([]byte, 48) // sync.Pool
	if _, err := io.ReadFull(r, buf); err != nil {
		return nil, err
	}
	m, err := parseHeader(buf)
	if err != nil {
		return nil, err
	}
	m.header = buf
	if m.dataLen > 0 {
		dl := m.dataLen
		for dl%4 > 0 {
			dl++
		}
		data := make([]byte, dl)
		if _, err := io.ReadFull(r, data); err != nil {
			return nil, err
		}
		m.data = data
	}
	return m, nil
}

// parseUint parses the given slice as a network-byte-ordered integer.  If
// there are more than 8 bytes in data, it overflows.
func parseUint(data []byte) uint64 {
	var out uint64
	for i := 0; i < len(data); i++ {
		out += uint64(data[len(data)-i-1]) << uint(8*i)
	}
	return out
}

func parseHeader(data []byte) (*Message, error) {
	if len(data) < 48 {
		return nil, fmt.Errorf("garbled header")
	}
	// TODO: sync.Pool
	m := &Message{}
	m.immediate = 0x40&data[0] == 0x40
	m.opCode = opCode(data[0] & 0x3f)
	m.final = 0x80&data[1] == 0x80
	m.ahsLen = int(data[4]) * 4
	m.dataLen = int(parseUint(data[5:8]))
	m.taskTag = uint32(parseUint(data[16:20]))
	switch m.opCode {
	case opSCSICmd:
		m.lun = int(parseUint(data[8:16]))
	case opLoginReq:
		m.transit = m.final
		m.cont = data[1]&0x40 == 0x40
		if m.cont && m.transit {
			// rfc7143 11.12.2
			return nil, fmt.Errorf("transit and continue bits set in same login request")
		}
		m.csg = int(data[1]&0xc) >> 2
		m.nsg = int(data[1] & 0x3)
		m.connID = uint16(parseUint(data[20:22]))
		m.cmdSN = uint32(parseUint(data[24:28]))
		m.expStatSN = uint32(parseUint(data[28:32]))
	}
	return m, nil
}

func (m *Message) IsLogon() bool {
	return m.opCode == opLoginReq
}

func (m *Message) IsTerminal() bool {
	return m.final
}
<|endoftext|>


<commit_before>package js

import (
	// "github.com/robertkrimen/otto"
	"io"
	"net/http"
	"strings"
)

type HTTPResponse struct {
	Status int
}

func (a JSAPI) HTTPRequest(method, url, body string, params map[string]interface{}) map[string]interface{} {
	bodyReader := io.Reader(nil)
	if body != "" {
		bodyReader = strings.NewReader(body)
	}
	req, err := http.NewRequest(method, url, bodyReader)
	if err != nil {
		throw(a.vu.vm, err)
	}

	res, err := a.vu.HTTPClient.Do(req)
	if err != nil {
		throw(a.vu.vm, err)
	}

	return map[string]interface{}{
		"status": res.StatusCode,
	}
}
<commit_msg>[feat] Response bodies<commit_after>package js

import (
	// "github.com/robertkrimen/otto"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
)

type HTTPResponse struct {
	Status int
}

func (a JSAPI) HTTPRequest(method, url, body string, params map[string]interface{}) map[string]interface{} {
	bodyReader := io.Reader(nil)
	if body != "" {
		bodyReader = strings.NewReader(body)
	}
	req, err := http.NewRequest(method, url, bodyReader)
	if err != nil {
		throw(a.vu.vm, err)
	}

	res, err := a.vu.HTTPClient.Do(req)
	if err != nil {
		throw(a.vu.vm, err)
	}

	resBody, err := ioutil.ReadAll(res.Body)
	if err != nil {
		throw(a.vu.vm, err)
	}
	res.Body.Close()

	return map[string]interface{}{
		"status": res.StatusCode,
		"body":   string(resBody),
	}
}
<|endoftext|>