<commit_before>////////////////////////////////////////////////////////////////////////////
// Porgram: FfCvt
// Purpose: ffmpeg convert wrapper tool
// Authors: Tong Sun (c) 2015, All rights reserved
////////////////////////////////////////////////////////////////////////////

/*

Transcodes all episodes in the given directory and all of it's subdirectories
using ffmpeg.

Forked from Michael Murphy (mmstick)'s
https://gist.github.com/mmstick/3182c1c8596c1f830c7e

*/

////////////////////////////////////////////////////////////////////////////
// Program start

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"strings"
	"time"
)

////////////////////////////////////////////////////////////////////////////
// Constant and data type/structure definitions

// Contains information about each episode
type Episode struct {
	name           string
	directory      string
	originalSize   int64
	transcodedSize int64
	sizeDifference int64
	time           time.Duration
	stat           error
}

////////////////////////////////////////////////////////////////////////////
// Global variables definitions

var (
	sprintf = fmt.Sprintf
)

////////////////////////////////////////////////////////////////////////////
// Main

func main() {
	flag.Usage = Usage
	flag.Parse()

	// One mandatory arguments, either -d or -f
	if len(Opts.Directory)+len(Opts.File) < 1 {
		Usage()
	}
	getDefault()

	startTime := time.Now()
	if Opts.Directory != "" {
		transcodeEpisodes(scanEpisodes(scanDirectory(Opts.Directory), Opts.Directory))
	} else if Opts.File != "" {
		outputName := getOutputName(Opts.File)
		fmt.Printf("\n== Transcoding: %s\n", Opts.File)
		transcodeFile(Opts.File, outputName)
	}
	fmt.Printf("Transcoding completed in %s\n", time.Since(startTime))
}

////////////////////////////////////////////////////////////////////////////
// Function definitions

//==========================================================================
// Directory & Episodes handling

// Transcodes all episodes in the episode list
func transcodeEpisodes(episodeList *[]Episode) {
	files := len(*episodeList)
	for index, ep := range *episodeList {
		ep.transcodeEpisode(index+1, files)
		ep.status()
	}
}

// Print the status of the transcoded episode
func (episode Episode) status() {
	if episode.stat != nil {
		fmt.Println("Failed to transcode", episode.name)
	} else {
		fmt.Println("Transcoded", episode.name)
		fmt.Println("Original Size:", episode.originalSize, "MB")
		fmt.Println("New Size:", episode.transcodedSize, "MB")
		fmt.Println("Difference:", episode.sizeDifference, "MB")
		fmt.Println("Time:", episode.time)
	}
}

// Recurse through each subdirectory and adds each episode to the episode list
func scanEpisodes(directoryList []os.FileInfo, directory string) *[]Episode {
	list := []Episode{}
	for _, file := range directoryList {
		if file.IsDir() {
			recurseDirectory(&directory, file.Name())
		} else {
			appendEpisode(&list, file, &directory)
		}
	}
	return &list
}

// Returns a list of files in the current directory
func scanDirectory(path string) []os.FileInfo {
	directory, _ := ioutil.ReadDir(path)
	return directory
}

// If the file is a directory, recurse through the directory.
func recurseDirectory(directory *string, filename string) {
	subdirectory := sprintf("%s/%s", *directory, filename)
	scanEpisodes(scanDirectory(subdirectory), subdirectory)
}

// Append the current episode to the episode list, unless it's encoded already
func appendEpisode(list *[]Episode, file os.FileInfo, directory *string) {
	fname := file.Name()
	if fname[len(fname)-5:] == "_.mkv" {
		return
	}

	*list = append(*list, Episode{
		name:         fname,
		directory:    *directory,
		originalSize: file.Size() / 1000000,
	})
}

//==========================================================================
// Transcode handling

// Transcode the current episode
func (ep Episode) transcodeEpisode(index, files int) {
	inputName := sprintf("%s/%s", ep.directory, ep.name)
	outputName := getOutputName(inputName)
	fmt.Printf("\n== Transcoding [%d/%d]: %s\n", index, files, ep.name)
	ep.time, ep.stat = transcodeFile(inputName, outputName)
	ep.transcodedSize = transcodeSize(outputName)
	ep.sizeDifference = ep.originalSize - ep.transcodedSize
}

func transcodeFile(inputName, outputName string) (time.Duration, error) {
	startTime := time.Now()

	args := encodeParametersV(encodeParametersA(
		[]string{"-i", inputName}))
	if Opts.Force {
		args = append(args, "-y")
	}
	args = append(args, strings.Fields(Opts.OptExtra)...)
	args = append(args, flag.Args()...)
	args = append(args, outputName)
	debug(Opts.FFMpeg, 2)
	debug(strings.Join(args, " "), 1)

	cmd := exec.Command(Opts.FFMpeg, args...)
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		log.Printf("%s: Exec error - %s", progname, err.Error())
	}
	fmt.Printf("%s\n", out.String())
	time := time.Since(startTime)
	return time, err
}

// Returns the encode parameters for Audio
func encodeParametersA(args []string) []string {
	if Opts.AC {
		args = append(args, "-c:a", "copy")
		return args
	}
	if Opts.AN {
		args = append(args, "-an")
		return args
	}
	if Opts.A2Opus {
		Opts.AES = "libopus"
	}
	if Opts.AES != "" {
		args = append(args, "-c:a", Opts.AES)
	}
	if Opts.ABR != "" {
		args = append(args, "-b:a", Opts.ABR)
	}
	if Opts.AEA != "" {
		args = append(args, strings.Fields(Opts.AEA)...)
	}
	return args
}

// Returns the encode parameters for Video
func encodeParametersV(args []string) []string {
	if Opts.VC {
		args = append(args, "-c:v", "copy")
		return args
	}
	if Opts.VN {
		args = append(args, "-vn")
		return args
	}
	if Opts.V2X265 {
		Opts.VES = "libx265"
	}
	if Opts.VES != "" {
		args = append(args, "-c:v", Opts.VES)
	}
	if Opts.CRF != "" {
		if Opts.VES[:6] == "libx26" {
			args = append(args, "-"+Opts.VES[3:]+"-params", "crf="+Opts.CRF)
		}
	}
	if Opts.VEA != "" {
		args = append(args, strings.Fields(Opts.VEA)...)
	}
	return args
}

// Returns the size of the newly transcoded episode, if it exists.
func transcodeSize(transcodedEpisode string) int64 {
	file, err := os.Open(transcodedEpisode)
	if err == nil {
		stat, _ := file.Stat()
		return stat.Size() / 1000000
	} else {
		log.Printf("%s: Open error - %s", progname, err.Error())
		return 0
	}
}

// Replaces the file extension from the input string with _.mkv
func getOutputName(input string) string {
	for index := len(input) - 1; index >= 0; index-- {
		if input[index] == '.' {
			input = input[:index]
		}
	}
	return input + Opts.Suffix + "_.mkv"
}

func debug(input string, threshold int) {
	if !(Opts.Debug >= threshold) {
		return
	}
	print("] ")
	print(input)
	print("\n")
}
<commit_msg>- [!] bug fix, file extension detection was wrong -- ended with the first period instead of last<commit_after>////////////////////////////////////////////////////////////////////////////
// Porgram: FfCvt
// Purpose: ffmpeg convert wrapper tool
// Authors: Tong Sun (c) 2015, All rights reserved
////////////////////////////////////////////////////////////////////////////

/*

Transcodes all episodes in the given directory and all of it's subdirectories
using ffmpeg.

Forked from Michael Murphy (mmstick)'s
https://gist.github.com/mmstick/3182c1c8596c1f830c7e

*/

////////////////////////////////////////////////////////////////////////////
// Program start

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"strings"
	"time"
)

////////////////////////////////////////////////////////////////////////////
// Constant and data type/structure definitions

// Contains information about each episode
type Episode struct {
	name           string
	directory      string
	originalSize   int64
	transcodedSize int64
	sizeDifference int64
	time           time.Duration
	stat           error
}

////////////////////////////////////////////////////////////////////////////
// Global variables definitions

var (
	sprintf = fmt.Sprintf
)

////////////////////////////////////////////////////////////////////////////
// Main

func main() {
	flag.Usage = Usage
	flag.Parse()

	// One mandatory arguments, either -d or -f
	if len(Opts.Directory)+len(Opts.File) < 1 {
		Usage()
	}
	getDefault()

	startTime := time.Now()
	if Opts.Directory != "" {
		transcodeEpisodes(scanEpisodes(scanDirectory(Opts.Directory), Opts.Directory))
	} else if Opts.File != "" {
		outputName := getOutputName(Opts.File)
		fmt.Printf("\n== Transcoding: %s\n", Opts.File)
		transcodeFile(Opts.File, outputName)
	}
	fmt.Printf("Transcoding completed in %s\n", time.Since(startTime))
}

////////////////////////////////////////////////////////////////////////////
// Function definitions

//==========================================================================
// Directory & Episodes handling

// Transcodes all episodes in the episode list
func transcodeEpisodes(episodeList *[]Episode) {
	files := len(*episodeList)
	for index, ep := range *episodeList {
		ep.transcodeEpisode(index+1, files)
		ep.status()
	}
}

// Print the status of the transcoded episode
func (episode Episode) status() {
	if episode.stat != nil {
		fmt.Println("Failed to transcode", episode.name)
	} else {
		fmt.Println("Transcoded", episode.name)
		fmt.Println("Original Size:", episode.originalSize, "MB")
		fmt.Println("New Size:", episode.transcodedSize, "MB")
		fmt.Println("Difference:", episode.sizeDifference, "MB")
		fmt.Println("Time:", episode.time)
	}
}

// Recurse through each subdirectory and adds each episode to the episode list
func scanEpisodes(directoryList []os.FileInfo, directory string) *[]Episode {
	list := []Episode{}
	for _, file := range directoryList {
		if file.IsDir() {
			recurseDirectory(&directory, file.Name())
		} else {
			appendEpisode(&list, file, &directory)
		}
	}
	return &list
}

// Returns a list of files in the current directory
func scanDirectory(path string) []os.FileInfo {
	directory, _ := ioutil.ReadDir(path)
	return directory
}

// If the file is a directory, recurse through the directory.
func recurseDirectory(directory *string, filename string) {
	subdirectory := sprintf("%s/%s", *directory, filename)
	scanEpisodes(scanDirectory(subdirectory), subdirectory)
}

// Append the current episode to the episode list, unless it's encoded already
func appendEpisode(list *[]Episode, file os.FileInfo, directory *string) {
	fname := file.Name()
	if fname[len(fname)-5:] == "_.mkv" {
		return
	}

	*list = append(*list, Episode{
		name:         fname,
		directory:    *directory,
		originalSize: file.Size() / 1000000,
	})
}

//==========================================================================
// Transcode handling

// Transcode the current episode
func (ep Episode) transcodeEpisode(index, files int) {
	inputName := sprintf("%s/%s", ep.directory, ep.name)
	outputName := getOutputName(inputName)
	fmt.Printf("\n== Transcoding [%d/%d]: %s\n", index, files, ep.name)
	ep.time, ep.stat = transcodeFile(inputName, outputName)
	ep.transcodedSize = transcodeSize(outputName)
	ep.sizeDifference = ep.originalSize - ep.transcodedSize
}

func transcodeFile(inputName, outputName string) (time.Duration, error) {
	startTime := time.Now()

	args := encodeParametersV(encodeParametersA(
		[]string{"-i", inputName}))
	if Opts.Force {
		args = append(args, "-y")
	}
	args = append(args, strings.Fields(Opts.OptExtra)...)
	args = append(args, flag.Args()...)
	args = append(args, outputName)
	debug(Opts.FFMpeg, 2)
	debug(strings.Join(args, " "), 1)

	cmd := exec.Command(Opts.FFMpeg, args...)
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		log.Printf("%s: Exec error - %s", progname, err.Error())
	}
	fmt.Printf("%s\n", out.String())
	time := time.Since(startTime)
	return time, err
}

// Returns the encode parameters for Audio
func encodeParametersA(args []string) []string {
	if Opts.AC {
		args = append(args, "-c:a", "copy")
		return args
	}
	if Opts.AN {
		args = append(args, "-an")
		return args
	}
	if Opts.A2Opus {
		Opts.AES = "libopus"
	}
	if Opts.AES != "" {
		args = append(args, "-c:a", Opts.AES)
	}
	if Opts.ABR != "" {
		args = append(args, "-b:a", Opts.ABR)
	}
	if Opts.AEA != "" {
		args = append(args, strings.Fields(Opts.AEA)...)
	}
	return args
}

// Returns the encode parameters for Video
func encodeParametersV(args []string) []string {
	if Opts.VC {
		args = append(args, "-c:v", "copy")
		return args
	}
	if Opts.VN {
		args = append(args, "-vn")
		return args
	}
	if Opts.V2X265 {
		Opts.VES = "libx265"
	}
	if Opts.VES != "" {
		args = append(args, "-c:v", Opts.VES)
	}
	if Opts.CRF != "" {
		if Opts.VES[:6] == "libx26" {
			args = append(args, "-"+Opts.VES[3:]+"-params", "crf="+Opts.CRF)
		}
	}
	if Opts.VEA != "" {
		args = append(args, strings.Fields(Opts.VEA)...)
	}
	return args
}

// Returns the size of the newly transcoded episode, if it exists.
func transcodeSize(transcodedEpisode string) int64 {
	file, err := os.Open(transcodedEpisode)
	if err == nil {
		stat, _ := file.Stat()
		return stat.Size() / 1000000
	} else {
		log.Printf("%s: Open error - %s", progname, err.Error())
		return 0
	}
}

// Replaces the file extension from the input string with _.mkv
func getOutputName(input string) string {
	for index := len(input) - 1; index >= 0; index-- {
		if input[index] == '.' {
			input = input[:index]
			break
		}
	}
	return input + Opts.Suffix + "_.mkv"
}

func debug(input string, threshold int) {
	if !(Opts.Debug >= threshold) {
		return
	}
	print("] ")
	print(input)
	print("\n")
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package connection

import (
	"context"
	"fmt"
	"net"
	"strings"
	"time"

	"github.com/container-storage-interface/spec/lib/go/csi"
	"github.com/golang/glog"
	"google.golang.org/grpc"
	"google.golang.org/grpc/connectivity"
)

// CSIConnection is gRPC connection to a remote CSI driver and abstracts all
// CSI calls.
type CSIConnection interface {
	// GetDriverName returns driver name as discovered by GetPluginInfo()
	// gRPC call.
	GetDriverName(ctx context.Context) (string, error)

	// SupportsControllerPublish returns true if the CSI driver reports
	// PUBLISH_UNPUBLISH_VOLUME in ControllerGetCapabilities() gRPC call.
	SupportsControllerPublish(ctx context.Context) (bool, error)

	// Attach given volume to given node. Returns PublishVolumeInfo
	Attach(ctx context.Context, volumeID string, readOnly bool, nodeID string, caps *csi.VolumeCapability) (map[string]string, error)

	// Detach given volume from given node.
	Detach(ctx context.Context, volumeID string, nodeID string) error

	// Close the connection
	Close() error
}

type csiConnection struct {
	conn *grpc.ClientConn
}

var (
	_ CSIConnection = &csiConnection{}

	// Version of CSI this client implements
	csiVersion = csi.Version{
		Major: 0,
		Minor: 1,
		Patch: 0,
	}
)

func New(address string, timeout time.Duration) (CSIConnection, error) {
	conn, err := connect(address, timeout)
	if err != nil {
		return nil, err
	}
	return &csiConnection{
		conn: conn,
	}, nil
}

func connect(address string, timeout time.Duration) (*grpc.ClientConn, error) {
	glog.V(2).Infof("Connecting to %s", address)
	dialOptions := []grpc.DialOption{
		grpc.WithInsecure(),
		grpc.WithBackoffMaxDelay(time.Second),
	}
	if strings.HasPrefix(address, "/") {
		dialOptions = append(dialOptions, grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
			return net.DialTimeout("unix", addr, timeout)
		}))
	}
	conn, err := grpc.Dial(address, dialOptions...)

	if err != nil {
		return nil, err
	}
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()
	for {
		if !conn.WaitForStateChange(ctx, conn.GetState()) {
			glog.V(4).Infof("Connection timed out")
			return conn, nil // return nil, subsequent GetPluginInfo will show the real connection error
		}
		if conn.GetState() == connectivity.Ready {
			glog.V(3).Infof("Connected")
			return conn, nil
		}
		glog.V(4).Infof("Still trying, connection is %s", conn.GetState())
	}
}

func (c *csiConnection) GetDriverName(ctx context.Context) (string, error) {
	client := csi.NewIdentityClient(c.conn)

	req := csi.GetPluginInfoRequest{
		Version: &csiVersion,
	}

	rsp, err := client.GetPluginInfo(ctx, &req)
	if err != nil {
		return "", err
	}
	e := rsp.GetError()
	if e != nil {
		// TODO: report the right error
		return "", fmt.Errorf("Error calling GetPluginInfo: %+v", e)
	}

	result := rsp.GetResult()
	if result == nil {
		return "", fmt.Errorf("result is empty")
	}
	name := result.GetName()
	if name == "" {
		return "", fmt.Errorf("name is empty")
	}
	return result.GetName(), nil
}

func (c *csiConnection) SupportsControllerPublish(ctx context.Context) (bool, error) {
	client := csi.NewControllerClient(c.conn)
	req := csi.ControllerGetCapabilitiesRequest{
		Version: &csiVersion,
	}

	rsp, err := client.ControllerGetCapabilities(ctx, &req)
	if err != nil {
		return false, err
	}
	e := rsp.GetError()
	if e != nil {
		// TODO: report the right error
		return false, fmt.Errorf("error calling ControllerGetCapabilities: %+v", e)
	}

	result := rsp.GetResult()
	if result == nil {
		return false, fmt.Errorf("result is empty")
	}

	caps := result.GetCapabilities()
	for _, cap := range caps {
		if cap == nil {
			continue
		}
		rpc := cap.GetRpc()
		if rpc == nil {
			continue
		}
		if rpc.GetType() == csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME {
			return true, nil
		}
	}
	return false, nil
}

func (c *csiConnection) Attach(ctx context.Context, volumeID string, readOnly bool, nodeID string, caps *csi.VolumeCapability) (map[string]string, error) {
	client := csi.NewControllerClient(c.conn)

	req := csi.ControllerPublishVolumeRequest{
		Version:          &csiVersion,
		VolumeId:         volumeID,
		NodeId:           nodeID,
		VolumeCapability: caps,
		Readonly:         readOnly,
		UserCredentials:  nil,
	}

	rsp, err := client.ControllerPublishVolume(ctx, &req)
	if err != nil {
		return nil, err
	}
	e := rsp.GetError()
	if e != nil {
		// TODO: report the right error
		return nil, fmt.Errorf("error calling ControllerPublishVolume: %+v", e)
	}

	result := rsp.GetResult()
	if result == nil {
		return nil, fmt.Errorf("result is empty")
	}

	return result.PublishVolumeInfo, nil
}

func (c *csiConnection) Detach(ctx context.Context, volumeID string, nodeID string) error {
	client := csi.NewControllerClient(c.conn)

	req := csi.ControllerUnpublishVolumeRequest{
		Version:         &csiVersion,
		VolumeId:        volumeID,
		NodeId:          nodeID,
		UserCredentials: nil,
	}

	rsp, err := client.ControllerUnpublishVolume(ctx, &req)
	if err != nil {
		return err
	}
	e := rsp.GetError()
	if e != nil {
		// TODO: report the right error
		return fmt.Errorf("error calling ControllerUnpublishVolume: %+v", e)
	}

	result := rsp.GetResult()
	if result == nil {
		return fmt.Errorf("result is empty")
	}

	return nil
}

func (c *csiConnection) Close() error {
	return c.conn.Close()
}
<commit_msg>Add gRPC logging<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package connection

import (
	"context"
	"fmt"
	"net"
	"strings"
	"time"

	"github.com/container-storage-interface/spec/lib/go/csi"
	"github.com/golang/glog"
	"google.golang.org/grpc"
	"google.golang.org/grpc/connectivity"
)

// CSIConnection is gRPC connection to a remote CSI driver and abstracts all
// CSI calls.
type CSIConnection interface {
	// GetDriverName returns driver name as discovered by GetPluginInfo()
	// gRPC call.
	GetDriverName(ctx context.Context) (string, error)

	// SupportsControllerPublish returns true if the CSI driver reports
	// PUBLISH_UNPUBLISH_VOLUME in ControllerGetCapabilities() gRPC call.
	SupportsControllerPublish(ctx context.Context) (bool, error)

	// Attach given volume to given node. Returns PublishVolumeInfo
	Attach(ctx context.Context, volumeID string, readOnly bool, nodeID string, caps *csi.VolumeCapability) (map[string]string, error)

	// Detach given volume from given node.
	Detach(ctx context.Context, volumeID string, nodeID string) error

	// Close the connection
	Close() error
}

type csiConnection struct {
	conn *grpc.ClientConn
}

var (
	_ CSIConnection = &csiConnection{}

	// Version of CSI this client implements
	csiVersion = csi.Version{
		Major: 0,
		Minor: 1,
		Patch: 0,
	}
)

func New(address string, timeout time.Duration) (CSIConnection, error) {
	conn, err := connect(address, timeout)
	if err != nil {
		return nil, err
	}
	return &csiConnection{
		conn: conn,
	}, nil
}

func connect(address string, timeout time.Duration) (*grpc.ClientConn, error) {
	glog.V(2).Infof("Connecting to %s", address)
	dialOptions := []grpc.DialOption{
		grpc.WithInsecure(),
		grpc.WithBackoffMaxDelay(time.Second),
		grpc.WithUnaryInterceptor(logGRPC),
	}
	if strings.HasPrefix(address, "/") {
		dialOptions = append(dialOptions, grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
			return net.DialTimeout("unix", addr, timeout)
		}))
	}
	conn, err := grpc.Dial(address, dialOptions...)

	if err != nil {
		return nil, err
	}
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()
	for {
		if !conn.WaitForStateChange(ctx, conn.GetState()) {
			glog.V(4).Infof("Connection timed out")
			return conn, nil // return nil, subsequent GetPluginInfo will show the real connection error
		}
		if conn.GetState() == connectivity.Ready {
			glog.V(3).Infof("Connected")
			return conn, nil
		}
		glog.V(4).Infof("Still trying, connection is %s", conn.GetState())
	}
}

func (c *csiConnection) GetDriverName(ctx context.Context) (string, error) {
	client := csi.NewIdentityClient(c.conn)

	req := csi.GetPluginInfoRequest{
		Version: &csiVersion,
	}

	rsp, err := client.GetPluginInfo(ctx, &req)
	if err != nil {
		return "", err
	}
	e := rsp.GetError()
	if e != nil {
		// TODO: report the right error
		return "", fmt.Errorf("Error calling GetPluginInfo: %+v", e)
	}

	result := rsp.GetResult()
	if result == nil {
		return "", fmt.Errorf("result is empty")
	}
	name := result.GetName()
	if name == "" {
		return "", fmt.Errorf("name is empty")
	}
	return result.GetName(), nil
}

func (c *csiConnection) SupportsControllerPublish(ctx context.Context) (bool, error) {
	client := csi.NewControllerClient(c.conn)
	req := csi.ControllerGetCapabilitiesRequest{
		Version: &csiVersion,
	}

	rsp, err := client.ControllerGetCapabilities(ctx, &req)
	if err != nil {
		return false, err
	}
	e := rsp.GetError()
	if e != nil {
		// TODO: report the right error
		return false, fmt.Errorf("error calling ControllerGetCapabilities: %+v", e)
	}

	result := rsp.GetResult()
	if result == nil {
		return false, fmt.Errorf("result is empty")
	}

	caps := result.GetCapabilities()
	for _, cap := range caps {
		if cap == nil {
			continue
		}
		rpc := cap.GetRpc()
		if rpc == nil {
			continue
		}
		if rpc.GetType() == csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME {
			return true, nil
		}
	}
	return false, nil
}

func (c *csiConnection) Attach(ctx context.Context, volumeID string, readOnly bool, nodeID string, caps *csi.VolumeCapability) (map[string]string, error) {
	client := csi.NewControllerClient(c.conn)

	req := csi.ControllerPublishVolumeRequest{
		Version:          &csiVersion,
		VolumeId:         volumeID,
		NodeId:           nodeID,
		VolumeCapability: caps,
		Readonly:         readOnly,
		UserCredentials:  nil,
	}

	rsp, err := client.ControllerPublishVolume(ctx, &req)
	if err != nil {
		return nil, err
	}
	e := rsp.GetError()
	if e != nil {
		// TODO: report the right error
		return nil, fmt.Errorf("error calling ControllerPublishVolume: %+v", e)
	}

	result := rsp.GetResult()
	if result == nil {
		return nil, fmt.Errorf("result is empty")
	}

	return result.PublishVolumeInfo, nil
}

func (c *csiConnection) Detach(ctx context.Context, volumeID string, nodeID string) error {
	client := csi.NewControllerClient(c.conn)

	req := csi.ControllerUnpublishVolumeRequest{
		Version:         &csiVersion,
		VolumeId:        volumeID,
		NodeId:          nodeID,
		UserCredentials: nil,
	}

	rsp, err := client.ControllerUnpublishVolume(ctx, &req)
	if err != nil {
		return err
	}
	e := rsp.GetError()
	if e != nil {
		// TODO: report the right error
		return fmt.Errorf("error calling ControllerUnpublishVolume: %+v", e)
	}

	result := rsp.GetResult()
	if result == nil {
		return fmt.Errorf("result is empty")
	}

	return nil
}

func (c *csiConnection) Close() error {
	return c.conn.Close()
}

func logGRPC(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
	glog.V(5).Infof("GRPC call: %s", method)
	glog.V(5).Infof("GRPC request: %+v", req)
	err := invoker(ctx, method, req, reply, cc, opts...)
	glog.V(5).Infof("GRPC response: %+v", reply)
	glog.V(5).Infof("GRPC error: %v", err)
	return err
}
<|endoftext|>


<commit_before>package experiment

import (
	"errors"
	log "github.com/Sirupsen/logrus"
	"os"
	"path"
	"strconv"
	"time"
)

// Experiment captures the internal data for the Experiment Driver.
type Experiment struct {
	session             session
	name                string
	workingDirectory    string
	measurements        []Measurement
	startingDirectory   string
	experimentDirectory string

	logFile *os.File
	logLvl  log.Level
	Log     *log.Logger
}

// NewExperiment creates a new Experiment instance,
// initialize experiment working directory and initialize logs.
// Caller have to provide slice of Measurement interfaces which are going to be executed.
func NewExperiment(name string, measurements []Measurement,
	directory string, logLevel log.Level) (*Experiment, error) {
	if len(measurements) == 0 {
		return nil, errors.New("invalid argument: no measurements provided")
	}

	// TODO(mpatelcz): Check if measurements names are unique!
	e := &Experiment{
		name:             name,
		session:          newSession(),
		workingDirectory: directory,
		measurements:     measurements,
		logLvl:           logLevel,
	}

	err := e.createExperimentDir()
	if err != nil {
		return nil, err
	}

	err = e.logInitialize()
	if err != nil {
		os.Chdir(e.startingDirectory)
		return nil, err
	}

	return e, nil
}

// Run runs experiment.
// It runs in a sequence defined measurements with given repetition count.
func (e *Experiment) Run() error {
	experimentStartingTime := time.Now()

	e.Log.Info("Starting Experiment ", e.name, " with uuid ", e.session.Name)
	var err error
	for _, measurement := range e.measurements {
		for i := 0; i < measurement.Repetitions(); i++ {
			measurementStartingTime := time.Now()

			e.Log.Info("Starting ", measurement.Name(), " repetition ", i)
			err = e.createMeasurementDir(measurement, i)
			if err != nil {
				return err
			}

			err := measurement.Run(e.Log)
			if err != nil {
				// When measurement return error we stop the whole experiment.
				e.Log.Error(measurement.Name(), " returned error ", err)
				return err
			}

			e.Log.Info("Ended ", measurement.Name(), " repetition ", i,
				" in ", time.Since(measurementStartingTime))
		}

		// Give a chance for measurement to finalize.
		// E.g to check statistical confidence of a result based on repetitions results.
		e.Log.Info("Finalizing ", measurement.Name(),
			" after ", measurement.Repetitions(), " repetitions")
		err := measurement.Finalize()
		if err != nil {
			// When measurement return error we stop the whole experiment.
			e.Log.Error(measurement.Name(), " returned error ", err,
				" while finalizing.")
			return err
		}
	}
	e.Log.Info("Ended experiment ", e.name, " with uuid ", e.session.Name,
		" in ", time.Since(experimentStartingTime))
	return err
}

// createExperimentDir creates unique directory for experiment logs and results.
func (e *Experiment) createExperimentDir() error {
	e.startingDirectory, _ = os.Getwd()

	if len(e.workingDirectory) > 0 {
		e.experimentDirectory = path.Join(e.workingDirectory, e.name, e.session.Name)
	} else {
		e.experimentDirectory = path.Join(e.startingDirectory, e.name, e.session.Name)
	}

	err := os.MkdirAll(e.experimentDirectory, 0777)
	if err != nil {
		return err
	}

	err = os.Chdir(e.experimentDirectory)
	return err
}

func (e *Experiment) Finalize() {
	e.logClose()

	// Exit experiment directory
	os.Chdir(e.startingDirectory)
}

func (e *Experiment) createMeasurementDir(measurement Measurement, iteration int) error {
	measurementDir := path.Join(e.experimentDirectory,
		measurement.Name(), strconv.FormatInt(int64(iteration), 10))

	err := os.MkdirAll(measurementDir, 0777)
	if err != nil {
		return err
	}

	err = os.Chdir(measurementDir)
	if err != nil {
		return err
	}

	return err
}

func (e *Experiment) logInitialize() error {
	var err error

	// Create master log file "master.log".
	e.logFile, err = os.OpenFile(e.experimentDirectory+"/master.log", os.O_WRONLY|os.O_CREATE, 0755)
	if err != nil {
		return err
	}

	// Create new logger.
	e.Log = &log.Logger{
		Out:       e.logFile,
		Formatter: new(log.TextFormatter),
		Hooks:     make(log.LevelHooks),
		Level:     e.logLvl,
	}

	return err
}

func (e *Experiment) logClose() {
	e.logFile.Close()
}
<commit_msg>Fixed lint issue.<commit_after>package experiment

import (
	"errors"
	log "github.com/Sirupsen/logrus"
	"os"
	"path"
	"strconv"
	"time"
)

// Experiment captures the internal data for the Experiment Driver.
type Experiment struct {
	session             session
	name                string
	workingDirectory    string
	measurements        []Measurement
	startingDirectory   string
	experimentDirectory string

	logFile *os.File
	logLvl  log.Level
	Log     *log.Logger
}

// NewExperiment creates a new Experiment instance,
// initialize experiment working directory and initialize logs.
// Caller have to provide slice of Measurement interfaces which are going to be executed.
func NewExperiment(name string, measurements []Measurement,
	directory string, logLevel log.Level) (*Experiment, error) {
	if len(measurements) == 0 {
		return nil, errors.New("invalid argument: no measurements provided")
	}

	// TODO(mpatelcz): Check if measurements names are unique!
	e := &Experiment{
		name:             name,
		session:          newSession(),
		workingDirectory: directory,
		measurements:     measurements,
		logLvl:           logLevel,
	}

	err := e.createExperimentDir()
	if err != nil {
		return nil, err
	}

	err = e.logInitialize()
	if err != nil {
		os.Chdir(e.startingDirectory)
		return nil, err
	}

	return e, nil
}

// Run runs experiment.
// It runs in a sequence defined measurements with given repetition count.
func (e *Experiment) Run() error {
	experimentStartingTime := time.Now()

	e.Log.Info("Starting Experiment ", e.name, " with uuid ", e.session.Name)
	var err error
	for _, measurement := range e.measurements {
		for i := 0; i < measurement.Repetitions(); i++ {
			measurementStartingTime := time.Now()

			e.Log.Info("Starting ", measurement.Name(), " repetition ", i)
			err = e.createMeasurementDir(measurement, i)
			if err != nil {
				return err
			}

			err := measurement.Run(e.Log)
			if err != nil {
				// When measurement return error we stop the whole experiment.
				e.Log.Error(measurement.Name(), " returned error ", err)
				return err
			}

			e.Log.Info("Ended ", measurement.Name(), " repetition ", i,
				" in ", time.Since(measurementStartingTime))
		}

		// Give a chance for measurement to finalize.
		// E.g to check statistical confidence of a result based on repetitions results.
		e.Log.Info("Finalizing ", measurement.Name(),
			" after ", measurement.Repetitions(), " repetitions")
		err := measurement.Finalize()
		if err != nil {
			// When measurement return error we stop the whole experiment.
			e.Log.Error(measurement.Name(), " returned error ", err,
				" while finalizing.")
			return err
		}
	}
	e.Log.Info("Ended experiment ", e.name, " with uuid ", e.session.Name,
		" in ", time.Since(experimentStartingTime))
	return err
}

// createExperimentDir creates unique directory for experiment logs and results.
func (e *Experiment) createExperimentDir() error {
	e.startingDirectory, _ = os.Getwd()

	if len(e.workingDirectory) > 0 {
		e.experimentDirectory = path.Join(e.workingDirectory, e.name, e.session.Name)
	} else {
		e.experimentDirectory = path.Join(e.startingDirectory, e.name, e.session.Name)
	}

	err := os.MkdirAll(e.experimentDirectory, 0777)
	if err != nil {
		return err
	}

	err = os.Chdir(e.experimentDirectory)
	return err
}

// Finalize closes log file and returns to the previous working directory.
func (e *Experiment) Finalize() {
	e.logClose()

	// Exit experiment directory
	os.Chdir(e.startingDirectory)
}

func (e *Experiment) createMeasurementDir(measurement Measurement, iteration int) error {
	measurementDir := path.Join(e.experimentDirectory,
		measurement.Name(), strconv.FormatInt(int64(iteration), 10))

	err := os.MkdirAll(measurementDir, 0777)
	if err != nil {
		return err
	}

	err = os.Chdir(measurementDir)
	if err != nil {
		return err
	}

	return err
}

func (e *Experiment) logInitialize() error {
	var err error

	// Create master log file "master.log".
	e.logFile, err = os.OpenFile(e.experimentDirectory+"/master.log", os.O_WRONLY|os.O_CREATE, 0755)
	if err != nil {
		return err
	}

	// Create new logger.
	e.Log = &log.Logger{
		Out:       e.logFile,
		Formatter: new(log.TextFormatter),
		Hooks:     make(log.LevelHooks),
		Level:     e.logLvl,
	}

	return err
}

func (e *Experiment) logClose() {
	e.logFile.Close()
}
<|endoftext|>


<commit_before>// +build freebsd
// tun_freebsd.go -- tun interface with cgo for linux / bsd
//

package samtun

/*

#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <net/if.h>
#include <net/if_tun.h>
#include <stdio.h>

int tundev_open(char * ifname) {
  if (strlen(ifname) > IFNAMSIZ) {
    return -1;
  }
  char name[IFNAMSIZ];
  sprintf(name, "/dev/%s", ifname);
  int fd = open(name, O_RDWR);
  if (fd > 0) {
    int i = 0;
    ioctl(fd, TUNSLMODE, &i);
    ioctl(fd, TUNSIFHEAD, &i);
  }
  return fd;
}

int tundev_up(char * ifname, char * addr, char * netmask, int mtu) {

  struct ifreq ifr;
  memset(&ifr, 0, sizeof(struct ifreq));
  strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
  int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
  if ( fd > 0 ) {
    ifr.ifr_mtu = mtu;
    if ( ioctl(fd, SIOCSIFMTU, (void*) &ifr) < 0) {
      close(fd);
      perror("SIOCSIFMTU");
      return -1;
    }

    struct sockaddr_in src;
    memset(&src, 0, sizeof(struct sockaddr_in));
    src.sin_family = AF_INET;
    if ( ! inet_aton(addr, &src.sin_addr) ) {
      printf("invalid srcaddr %s\n", addr);
      close(fd);
      return -1;
    }

    memcpy(&ifr.ifr_addr, &src, sizeof(struct sockaddr_in));
    if ( ioctl(fd, SIOCSIFADDR, (void*)&ifr) < 0 ) {
      close(fd);
      perror("SIOCSIFADDR");
     return -1;
    }

    struct sockaddr_in mask;
    memset(&mask, 0, sizeof(struct sockaddr_in));
    mask.sin_family = AF_INET;
    if ( ! inet_aton(netmask, &mask.sin_addr) ) {
      close(fd);
      printf("invalid netmask %s\n", netmask);
      return -1;
    }

    memcpy(&ifr.ifr_netmask, &mask, sizeof(struct sockaddr_in));
    if ( ioctl(fd, SIOCSIFNETMASK, (void*) &ifr) < 0) {
      close(fd);
      perror("SIOCSIFNETMASK");
      return -1;
    }

    if ( ioctl(fd, SIOCGIFFLAGS, (void*)&ifr) < 0 ) {
      close(fd);
      perror("SIOCGIFFLAGS");
      return -1;
    }
    ifr.ifr_flags |= IFF_UP ;
    if ( ioctl(fd, SIOCSIFFLAGS, (void*)&ifr) < 0 ) {
      perror("SIOCSIFFLAGS");
      close(fd);
      return -1;
    }

    close(fd);
    return 0;
  }
  return -1;
}

void tundev_close(int fd) {
  close(fd);
}

*/
import "C"

import (
  "errors"
)

type tunDev struct {
  fd C.int
}

func newTun(ifname, addr, dstaddr string, mtu int) (t tunDev, err error) {
  fd := C.tundev_open(C.CString(ifname))

  if fd == -1 {
    err = errors.New("cannot open tun interface")
  } else {
    if C.tundev_up(C.CString(ifname), C.CString(addr), C.CString(dstaddr), C.int(mtu)) < C.int(0) {
      err = errors.New("cannot put up interface")
    } else {
      t = tunDev{fd}
    }
  }
  return
}

// read from the tun device
func (t *tunDev) Read(d []byte) (n int, err error) {
  return fdRead(C.int(t.fd), d)
}

func (t *tunDev) Write(d []byte) (n int, err error) {
  return fdWrite(C.int(t.fd), d)
}

func (t *tunDev) Close() {
  C.tundev_close(C.int(t.fd))
}
<commit_msg>try fixing freebsd<commit_after>// +build freebsd
// tun_freebsd.go -- tun interface with cgo for linux / bsd
//

package samtun

/*

#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <net/if.h>
#include <net/if_tun.h>
#include <stdio.h>

int tundev_open(char * ifname) {
  if (strlen(ifname) > IFNAMSIZ) {
    return -1;
  }
  char name[IFNAMSIZ];
  sprintf(name, "/dev/%s", ifname);
  int fd = open(name, O_RDWR);
  if (fd > 0) {
    int i = 0;
    ioctl(fd, TUNSLMODE, &i);
    ioctl(fd, TUNSIFHEAD, &i);
  }
  return fd;
}

int tundev_up(char * ifname, char * addr, char * netmask, int mtu) {

  struct ifreq ifr;
  memset(&ifr, 0, sizeof(struct ifreq));
  strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
  int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
  if ( fd > 0 ) {
    ifr.ifr_mtu = mtu;
    if ( ioctl(fd, SIOCSIFMTU, (void*) &ifr) < 0) {
      close(fd);
      perror("SIOCSIFMTU");
      return -1;
    }

    struct sockaddr_in src;
    memset(&src, 0, sizeof(struct sockaddr_in));
    src.sin_family = AF_INET;
    if ( ! inet_aton(addr, &src.sin_addr) ) {
      printf("invalid srcaddr %s\n", addr);
      close(fd);
      return -1;
    }

    memcpy(&ifr.ifr_addr, &src, sizeof(struct sockaddr_in));
    if ( ioctl(fd, SIOCSIFADDR, (void*)&ifr) < 0 ) {
      close(fd);
      perror("SIOCSIFADDR");
     return -1;
    }

    struct sockaddr_in mask;
    memset(&mask, 0, sizeof(struct sockaddr_in));
    mask.sin_family = AF_INET;
    if ( ! inet_aton(netmask, &mask.sin_addr) ) {
      close(fd);
      printf("invalid netmask %s\n", netmask);
      return -1;
    }

    if ( ioctl(fd, SIOCGIFFLAGS, (void*)&ifr) < 0 ) {
      close(fd);
      perror("SIOCGIFFLAGS");
      return -1;
    }
    ifr.ifr_flags |= IFF_UP ;
    if ( ioctl(fd, SIOCSIFFLAGS, (void*)&ifr) < 0 ) {
      perror("SIOCSIFFLAGS");
      close(fd);
      return -1;
    }

    close(fd);
    return 0;
  }
  return -1;
}

void tundev_close(int fd) {
  close(fd);
}

*/
import "C"

import (
  "errors"
)

type tunDev struct {
  fd C.int
}

func newTun(ifname, addr, dstaddr string, mtu int) (t tunDev, err error) {
  fd := C.tundev_open(C.CString(ifname))

  if fd == -1 {
    err = errors.New("cannot open tun interface")
  } else {
    if C.tundev_up(C.CString(ifname), C.CString(addr), C.CString(dstaddr), C.int(mtu)) < C.int(0) {
      err = errors.New("cannot put up interface")
    } else {
      t = tunDev{fd}
    }
  }
  return
}

// read from the tun device
func (t *tunDev) Read(d []byte) (n int, err error) {
  return fdRead(C.int(t.fd), d)
}

func (t *tunDev) Write(d []byte) (n int, err error) {
  return fdWrite(C.int(t.fd), d)
}

func (t *tunDev) Close() {
  C.tundev_close(C.int(t.fd))
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import ()

const CENTER = 0x0000001818000000 // 4 central squares
const EXTENDED_CENTER = 0x00003C3C3C3C0000 // 12 central squares

type Score struct {
	middlegame int
	endgame    int
}

type Brain struct {
        player *Player
        color  int
}

func NewBrain(player *Player) *Brain {
        brain := new(Brain)

        brain.player = player
        brain.color = player.Color

        return brain
}

func (b *Brain) Evaluate(p *Position) (score int) {
        material := b.materialBalance(p)
        mobility := b.mobilityBalance(p)
        aggression := b.aggressionBalance(p)
        center := b.centerBoost(p)
        score = material + mobility + aggression + center
        Log("Score for %s is %d (mat: %d, mob: %d, agg: %d, ctr: %d)\n", C(b.color), score, material, mobility, aggression, center)
        return
}

func (b *Brain) materialBalance(p *Position) int {
        opposite := b.color^1

        score := 1000 * (p.count[King(b.color)] - p.count[King(opposite)]) +
                  900 * (p.count[Queen(b.color)] - p.count[Queen(opposite)]) +
                  500 * (p.count[Rook(b.color)] - p.count[Rook(opposite)]) +
                  305 * (p.count[Bishop(b.color)] - p.count[Bishop(opposite)]) +
                  300 * (p.count[Knight(b.color)] - p.count[Knight(opposite)]) +
                  100 * (p.count[Pawn(b.color)] - p.count[Pawn(opposite)])

        return score
}

func (b *Brain) mobilityBalance(p *Position) (score int) {
        score = b.movesAvailable(p, b.color) - b.movesAvailable(p, b.color^1)
        if score != 0 {
                score += 25 * (score / Abs(score))
        }
        return
}

func (b *Brain) aggressionBalance(p *Position) (score int) {
        score = b.attacksAvailable(p, b.color) - b.attacksAvailable(p, b.color^1)
        if score != 0 {
                score += 20 * (score / Abs(score))
        }
        return
}

// How many attacks for the central squares?
func (b *Brain) centerBoost(p *Position) (center int) {
        for i, piece := range p.pieces {
                if piece != 0 && piece.Color() == b.color {
                        targets := p.targets[i]
                        sq12 := targets.Intersect(EXTENDED_CENTER).Count()
                        sq04 := targets.Intersect(CENTER).Count()
                        center += 5 * (sq12 - sq04) + 3 * sq04
                }
        }
        return
}

// Number of moves available for all pieces of certain color.
func (b *Brain) movesAvailable(p *Position, color int) (moves int) {
        for i, piece := range p.pieces {
                if piece != 0 && piece.Color() == color {
                        moves += p.targets[i].Count()
                }
        }
        return
}

// How many times pieces of opposite color are being attacked?
func (b *Brain) attacksAvailable(p *Position, color int) (attacks int) {
        for i, piece := range p.pieces {
                if piece != 0 && piece.Color() == color {
                        targets := p.targets[i]
                        attacks += targets.Intersect(p.board[color^1]).Count()
                }
        }
        return
}
<commit_msg>Started with more sophisticated evaluation<commit_after>// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import ()

const CENTER = 0x0000001818000000 // 4 central squares
const EXTENDED_CENTER = 0x00003C3C3C3C0000 // 12 central squares

type Score struct {
	middlegame int
	endgame    int
}

type Brain struct {
        player      *Player
        color       int
        stage       int
        endgame     int
        middlegame  int
}

func NewBrain(player *Player) *Brain {
        brain := new(Brain)

        brain.player = player
        brain.color = player.Color

        return brain
}

func (b *Brain) EvaluateEx(p *Position) (score int) {
        b.determineGameStage(p)
        b.analyzePawnStructure(p)
        b.analyzeCoordination(p)
        b.analyzePassedPawns(p)
        b.analyzeKingSafety(p)

        score = (b.middlegame * b.stage + b.endgame * (256 - b.stage)) / 256
        if b.color == BLACK {
                score = -score
        }
        return
}

// Determine game stage by counting how many pieces are present on the board.
func (b *Brain) determineGameStage(p *Position) {
        b.stage  =  2 * (p.count[Pawn(WHITE)]   + p.count[Pawn(BLACK)])
        b.stage +=  6 * (p.count[Knight(WHITE)] + p.count[Knight(BLACK)])
        b.stage += 12 * (p.count[Bishop(WHITE)] + p.count[Bishop(BLACK)])
        b.stage += 16 * (p.count[Rook(WHITE)]   + p.count[Rook(BLACK)])
        b.stage += 32 * (p.count[Queen(WHITE)]  + p.count[Queen(BLACK)])
}

func (b *Brain) analyzePawnStructure(p *Position) {
}

func (b *Brain) analyzeCoordination(p *Position) {
}

func (b *Brain) analyzePassedPawns(p *Position) {
}

func (b *Brain) analyzeKingSafety(p *Position) {
}

func (b *Brain) Evaluate(p *Position) (score int) {
        material := b.materialBalance(p)
        mobility := b.mobilityBalance(p)
        aggression := b.aggressionBalance(p)
        center := b.centerBoost(p)
        score = material + mobility + aggression + center
        Log("Score for %s is %d (mat: %d, mob: %d, agg: %d, ctr: %d)\n", C(b.color), score, material, mobility, aggression, center)
        return
}

func (b *Brain) materialBalance(p *Position) int {
        opposite := b.color^1

        score := 1000 * (p.count[King(b.color)] - p.count[King(opposite)]) +
                  900 * (p.count[Queen(b.color)] - p.count[Queen(opposite)]) +
                  500 * (p.count[Rook(b.color)] - p.count[Rook(opposite)]) +
                  305 * (p.count[Bishop(b.color)] - p.count[Bishop(opposite)]) +
                  300 * (p.count[Knight(b.color)] - p.count[Knight(opposite)]) +
                  100 * (p.count[Pawn(b.color)] - p.count[Pawn(opposite)])

        return score
}

func (b *Brain) mobilityBalance(p *Position) (score int) {
        score = b.movesAvailable(p, b.color) - b.movesAvailable(p, b.color^1)
        if score != 0 {
                score += 25 * (score / Abs(score))
        }
        return
}

func (b *Brain) aggressionBalance(p *Position) (score int) {
        score = b.attacksAvailable(p, b.color) - b.attacksAvailable(p, b.color^1)
        if score != 0 {
                score += 20 * (score / Abs(score))
        }
        return
}

// How many attacks for the central squares?
func (b *Brain) centerBoost(p *Position) (center int) {
        for i, piece := range p.pieces {
                if piece != 0 && piece.Color() == b.color {
                        targets := p.targets[i]
                        sq12 := targets.Intersect(EXTENDED_CENTER).Count()
                        sq04 := targets.Intersect(CENTER).Count()
                        center += 5 * (sq12 - sq04) + 3 * sq04
                }
        }
        return
}

// Number of moves available for all pieces of certain color.
func (b *Brain) movesAvailable(p *Position, color int) (moves int) {
        for i, piece := range p.pieces {
                if piece != 0 && piece.Color() == color {
                        moves += p.targets[i].Count()
                }
        }
        return
}

// How many times pieces of opposite color are being attacked?
func (b *Brain) attacksAvailable(p *Position, color int) (attacks int) {
        for i, piece := range p.pieces {
                if piece != 0 && piece.Color() == color {
                        targets := p.targets[i]
                        attacks += targets.Intersect(p.board[color^1]).Count()
                }
        }
        return
}
<|endoftext|>


<commit_before>// +build e2e

/*
Copyright 2018 The Knative 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 conformance

import (
	"testing"

	"context"
	"fmt"
	"math"
	"net/http"
	"regexp"
	"strings"

	pkgTest "github.com/knative/pkg/test"
	"github.com/knative/pkg/test/spoof"
	"github.com/knative/serving/test"
	"github.com/pkg/errors"
	"golang.org/x/sync/errgroup"

	// Mysteriously required to support GCP auth (required by k8s libs). Apparently just importing it is enough. @_@ side effects @_@. https://github.com/kubernetes/client-go/issues/242
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
)

// Constants for test images located in test/test_images.
const (
	pizzaPlanet1        = "pizzaplanetv1"
	pizzaPlanet2        = "pizzaplanetv2"
	helloworld          = "helloworld"
	httpproxy           = "httpproxy"
	singleThreadedImage = "singlethreaded"
	timeout             = "timeout"
	printport           = "printport"
	runtime             = "runtime"
	protocols           = "protocols"

	concurrentRequests = 50
	// We expect to see 100% of requests succeed for traffic sent directly to revisions.
	// This might be a bad assumption.
	minDirectPercentage = 1
	// We expect to see at least 25% of either response since we're routing 50/50.
	// This might be a bad assumption.
	minSplitPercentage = 0.25
)

// Constants for test image output.
const (
	pizzaPlanetText1 = "What a spaceport!"
	pizzaPlanetText2 = "Re-energize yourself with a slice of pepperoni!"
	helloWorldText   = "Hello World! How about some tasty noodles?"
)

func setup(t *testing.T) *test.Clients {
	t.Helper()
	clients, err := test.NewClients(pkgTest.Flags.Kubeconfig, pkgTest.Flags.Cluster, test.ServingNamespace)
	if err != nil {
		t.Fatalf("Couldn't initialize clients: %v", err)
	}
	return clients
}

func waitForExpectedResponse(t *testing.T, clients *test.Clients, domain, expectedResponse string) error {
	client, err := pkgTest.NewSpoofingClient(clients.KubeClient, t.Logf, domain, test.ServingFlags.ResolvableDomain)
	if err != nil {
		return err
	}
	req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s", domain), nil)
	if err != nil {
		return err
	}
	_, err = client.Poll(req, pkgTest.MatchesAllOf(pkgTest.IsStatusOK(), pkgTest.EventuallyMatchesBody(expectedResponse)))
	return err
}

func validateDomains(
	t *testing.T, clients *test.Clients, baseDomain string,
	baseExpected, trafficTargets, targetsExpected []string) error {
	var subdomains []string
	for _, target := range trafficTargets {
		subdomains = append(subdomains, fmt.Sprintf("%s.%s", target, baseDomain))
	}

	g, _ := errgroup.WithContext(context.Background())
	// We don't have a good way to check if the route is updated so we will wait until a subdomain has
	// started returning at least one expected result to key that we should validate percentage splits.
	// In order for tests to succeed reliably, we need to make sure that all domains succeed.
	for i, s := range subdomains {
		i, s := i, s
		g.Go(func() error {
			t.Logf("Waiting for route to update domain: %s", s)
			return waitForExpectedResponse(t, clients, s, targetsExpected[i])
		})
	}
	if err := g.Wait(); err != nil {
		return errors.Wrap(err, "error with initial domain probing")
	}

	g.Go(func() error {
		minBasePercentage := minSplitPercentage
		if len(baseExpected) == 1 {
			minBasePercentage = minDirectPercentage
		}
		min := int(math.Floor(concurrentRequests * minBasePercentage))
		return checkDistribution(t, clients, baseDomain, concurrentRequests, min, baseExpected)
	})
	for i, subdomain := range subdomains {
		i, subdomain := i, subdomain
		g.Go(func() error {
			min := int(math.Floor(concurrentRequests * minDirectPercentage))
			return checkDistribution(t, clients, subdomain, concurrentRequests, min, []string{targetsExpected[i]})
		})
	}
	if err := g.Wait(); err != nil {
		return errors.Wrap(err, "error checking routing distribution")
	}
	return nil
}

func validateImageDigest(imageName string, imageDigest string) (bool, error) {
	imageDigestRegex := fmt.Sprintf("%s/%s@sha256:[0-9a-f]{64}", test.ServingFlags.DockerRepo, imageName)
	return regexp.MatchString(imageDigestRegex, imageDigest)
}

// sendRequests sends "num" requests to "domain", returning a string for each spoof.Response.Body.
func sendRequests(client spoof.Interface, domain string, num int) ([]string, error) {
	responses := make([]string, num)

	// Launch "num" requests, recording the responses we get in "responses".
	g, _ := errgroup.WithContext(context.Background())
	for i := 0; i < num; i++ {
		// We don't index into "responses" inside the goroutine to avoid a race, see #1545.
		result := &responses[i]
		g.Go(func() error {
			req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s", domain), nil)
			if err != nil {
				return err
			}

			resp, err := client.Do(req)
			if err != nil {
				return err
			}

			*result = string(resp.Body)
			return nil
		})
	}
	return responses, g.Wait()
}

// checkResponses verifies that each "expectedResponse" is present in "actualResponses" at least "min" times.
func checkResponses(t *testing.T, num int, min int, domain string, expectedResponses []string, actualResponses []string) error {
	// counts maps the expected response body to the number of matching requests we saw.
	counts := make(map[string]int)
	// badCounts maps the unexpected response body to the number of matching requests we saw.
	badCounts := make(map[string]int)

	// counts := eval(
	//   SELECT body, count(*) AS total
	//   FROM $actualResponses
	//   WHERE body IN $expectedResponses
	//   GROUP BY body
	// )
	for _, ar := range actualResponses {
		expected := false
		for _, er := range expectedResponses {
			if strings.Contains(ar, er) {
				counts[er]++
				expected = true
			}
		}
		if !expected {
			badCounts[ar]++
		}
	}

	// Verify that we saw each entry in "expectedResponses" at least "min" times.
	// check(SELECT body FROM $counts WHERE total < $min)
	totalMatches := 0
	for _, er := range expectedResponses {
		count := counts[er]
		if count < min {
			return fmt.Errorf("domain %s failed: want at least %d, got %d for response %q", domain, min, count, er)
		}

		t.Logf("For domain %s: wanted at least %d, got %d requests.", domain, min, count)
		totalMatches += count
	}
	// Verify that the total expected responses match the number of requests made.
	for badResponse, count := range badCounts {
		t.Logf("Saw unexpected response %q %d times.", badResponse, count)
	}
	if totalMatches < num {
		return fmt.Errorf("domain %s: saw expected responses %d times, wanted %d", domain, totalMatches, num)
	}
	// If we made it here, the implementation conforms. Congratulations!
	return nil
}

// checkDistribution sends "num" requests to "domain", then validates that
// we see each body in "expectedResponses" at least "min" times.
func checkDistribution(t *testing.T, clients *test.Clients, domain string, num, min int, expectedResponses []string) error {
	client, err := pkgTest.NewSpoofingClient(clients.KubeClient, t.Logf, domain, test.ServingFlags.ResolvableDomain)
	if err != nil {
		return err
	}

	t.Logf("Performing %d concurrent requests to %s", num, domain)
	actualResponses, err := sendRequests(client, domain, num)
	if err != nil {
		return err
	}

	return checkResponses(t, num, min, domain, expectedResponses, actualResponses)
}
<commit_msg>Add missing retry for conformance tests. (#3282)<commit_after>// +build e2e

/*
Copyright 2018 The Knative 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 conformance

import (
	"testing"

	"context"
	"fmt"
	"math"
	"net/http"
	"regexp"
	"strings"

	pkgTest "github.com/knative/pkg/test"
	"github.com/knative/pkg/test/spoof"
	"github.com/knative/serving/test"
	"github.com/pkg/errors"
	"golang.org/x/sync/errgroup"

	// Mysteriously required to support GCP auth (required by k8s libs). Apparently just importing it is enough. @_@ side effects @_@. https://github.com/kubernetes/client-go/issues/242
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
)

// Constants for test images located in test/test_images.
const (
	pizzaPlanet1        = "pizzaplanetv1"
	pizzaPlanet2        = "pizzaplanetv2"
	helloworld          = "helloworld"
	httpproxy           = "httpproxy"
	singleThreadedImage = "singlethreaded"
	timeout             = "timeout"
	printport           = "printport"
	runtime             = "runtime"
	protocols           = "protocols"

	concurrentRequests = 50
	// We expect to see 100% of requests succeed for traffic sent directly to revisions.
	// This might be a bad assumption.
	minDirectPercentage = 1
	// We expect to see at least 25% of either response since we're routing 50/50.
	// This might be a bad assumption.
	minSplitPercentage = 0.25
)

// Constants for test image output.
const (
	pizzaPlanetText1 = "What a spaceport!"
	pizzaPlanetText2 = "Re-energize yourself with a slice of pepperoni!"
	helloWorldText   = "Hello World! How about some tasty noodles?"
)

func setup(t *testing.T) *test.Clients {
	t.Helper()
	clients, err := test.NewClients(pkgTest.Flags.Kubeconfig, pkgTest.Flags.Cluster, test.ServingNamespace)
	if err != nil {
		t.Fatalf("Couldn't initialize clients: %v", err)
	}
	return clients
}

func waitForExpectedResponse(t *testing.T, clients *test.Clients, domain, expectedResponse string) error {
	client, err := pkgTest.NewSpoofingClient(clients.KubeClient, t.Logf, domain, test.ServingFlags.ResolvableDomain)
	if err != nil {
		return err
	}
	req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s", domain), nil)
	if err != nil {
		return err
	}
	_, err = client.Poll(req, test.RetryingRouteInconsistency(pkgTest.MatchesAllOf(pkgTest.IsStatusOK(), pkgTest.EventuallyMatchesBody(expectedResponse))))
	return err
}

func validateDomains(
	t *testing.T, clients *test.Clients, baseDomain string,
	baseExpected, trafficTargets, targetsExpected []string) error {
	var subdomains []string
	for _, target := range trafficTargets {
		subdomains = append(subdomains, fmt.Sprintf("%s.%s", target, baseDomain))
	}

	g, _ := errgroup.WithContext(context.Background())
	// We don't have a good way to check if the route is updated so we will wait until a subdomain has
	// started returning at least one expected result to key that we should validate percentage splits.
	// In order for tests to succeed reliably, we need to make sure that all domains succeed.
	for i, s := range subdomains {
		i, s := i, s
		g.Go(func() error {
			t.Logf("Waiting for route to update domain: %s", s)
			return waitForExpectedResponse(t, clients, s, targetsExpected[i])
		})
	}
	if err := g.Wait(); err != nil {
		return errors.Wrap(err, "error with initial domain probing")
	}

	g.Go(func() error {
		minBasePercentage := minSplitPercentage
		if len(baseExpected) == 1 {
			minBasePercentage = minDirectPercentage
		}
		min := int(math.Floor(concurrentRequests * minBasePercentage))
		return checkDistribution(t, clients, baseDomain, concurrentRequests, min, baseExpected)
	})
	for i, subdomain := range subdomains {
		i, subdomain := i, subdomain
		g.Go(func() error {
			min := int(math.Floor(concurrentRequests * minDirectPercentage))
			return checkDistribution(t, clients, subdomain, concurrentRequests, min, []string{targetsExpected[i]})
		})
	}
	if err := g.Wait(); err != nil {
		return errors.Wrap(err, "error checking routing distribution")
	}
	return nil
}

func validateImageDigest(imageName string, imageDigest string) (bool, error) {
	imageDigestRegex := fmt.Sprintf("%s/%s@sha256:[0-9a-f]{64}", test.ServingFlags.DockerRepo, imageName)
	return regexp.MatchString(imageDigestRegex, imageDigest)
}

// sendRequests sends "num" requests to "domain", returning a string for each spoof.Response.Body.
func sendRequests(client spoof.Interface, domain string, num int) ([]string, error) {
	responses := make([]string, num)

	// Launch "num" requests, recording the responses we get in "responses".
	g, _ := errgroup.WithContext(context.Background())
	for i := 0; i < num; i++ {
		// We don't index into "responses" inside the goroutine to avoid a race, see #1545.
		result := &responses[i]
		g.Go(func() error {
			req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s", domain), nil)
			if err != nil {
				return err
			}

			resp, err := client.Do(req)
			if err != nil {
				return err
			}

			*result = string(resp.Body)
			return nil
		})
	}
	return responses, g.Wait()
}

// checkResponses verifies that each "expectedResponse" is present in "actualResponses" at least "min" times.
func checkResponses(t *testing.T, num int, min int, domain string, expectedResponses []string, actualResponses []string) error {
	// counts maps the expected response body to the number of matching requests we saw.
	counts := make(map[string]int)
	// badCounts maps the unexpected response body to the number of matching requests we saw.
	badCounts := make(map[string]int)

	// counts := eval(
	//   SELECT body, count(*) AS total
	//   FROM $actualResponses
	//   WHERE body IN $expectedResponses
	//   GROUP BY body
	// )
	for _, ar := range actualResponses {
		expected := false
		for _, er := range expectedResponses {
			if strings.Contains(ar, er) {
				counts[er]++
				expected = true
			}
		}
		if !expected {
			badCounts[ar]++
		}
	}

	// Verify that we saw each entry in "expectedResponses" at least "min" times.
	// check(SELECT body FROM $counts WHERE total < $min)
	totalMatches := 0
	for _, er := range expectedResponses {
		count := counts[er]
		if count < min {
			return fmt.Errorf("domain %s failed: want at least %d, got %d for response %q", domain, min, count, er)
		}

		t.Logf("For domain %s: wanted at least %d, got %d requests.", domain, min, count)
		totalMatches += count
	}
	// Verify that the total expected responses match the number of requests made.
	for badResponse, count := range badCounts {
		t.Logf("Saw unexpected response %q %d times.", badResponse, count)
	}
	if totalMatches < num {
		return fmt.Errorf("domain %s: saw expected responses %d times, wanted %d", domain, totalMatches, num)
	}
	// If we made it here, the implementation conforms. Congratulations!
	return nil
}

// checkDistribution sends "num" requests to "domain", then validates that
// we see each body in "expectedResponses" at least "min" times.
func checkDistribution(t *testing.T, clients *test.Clients, domain string, num, min int, expectedResponses []string) error {
	client, err := pkgTest.NewSpoofingClient(clients.KubeClient, t.Logf, domain, test.ServingFlags.ResolvableDomain)
	if err != nil {
		return err
	}

	t.Logf("Performing %d concurrent requests to %s", num, domain)
	actualResponses, err := sendRequests(client, domain, num)
	if err != nil {
		return err
	}

	return checkResponses(t, num, min, domain, expectedResponses, actualResponses)
}
<|endoftext|>


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

package runtime

import "unsafe"

var sigset_all sigset = sigset{^uint32(0), ^uint32(0)}

// Linux futex.
//
//	futexsleep(uint32 *addr, uint32 val)
//	futexwakeup(uint32 *addr)
//
// Futexsleep atomically checks if *addr == val and if so, sleeps on addr.
// Futexwakeup wakes up threads sleeping on addr.
// Futexsleep is allowed to wake up spuriously.

const (
	_FUTEX_WAIT = 0
	_FUTEX_WAKE = 1
)

// Atomically,
//	if(*addr == val) sleep
// Might be woken up spuriously; that's allowed.
// Don't sleep longer than ns; ns < 0 means forever.
//go:nosplit
func futexsleep(addr *uint32, val uint32, ns int64) {
	var ts timespec

	// Some Linux kernels have a bug where futex of
	// FUTEX_WAIT returns an internal error code
	// as an errno.  Libpthread ignores the return value
	// here, and so can we: as it says a few lines up,
	// spurious wakeups are allowed.
	if ns < 0 {
		futex(unsafe.Pointer(addr), _FUTEX_WAIT, val, nil, nil, 0)
		return
	}

	// It's difficult to live within the no-split stack limits here.
	// On ARM and 386, a 64-bit divide invokes a general software routine
	// that needs more stack than we can afford. So we use timediv instead.
	// But on real 64-bit systems, where words are larger but the stack limit
	// is not, even timediv is too heavy, and we really need to use just an
	// ordinary machine instruction.
	if ptrSize == 8 {
		ts.set_sec(ns / 1000000000)
		ts.set_nsec(int32(ns % 1000000000))
	} else {
		ts.tv_nsec = 0
		ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec)))))
	}
	futex(unsafe.Pointer(addr), _FUTEX_WAIT, val, unsafe.Pointer(&ts), nil, 0)
}

// If any procs are sleeping on addr, wake up at most cnt.
//go:nosplit
func futexwakeup(addr *uint32, cnt uint32) {
	ret := futex(unsafe.Pointer(addr), _FUTEX_WAKE, cnt, nil, nil, 0)
	if ret >= 0 {
		return
	}

	// I don't know that futex wakeup can return
	// EAGAIN or EINTR, but if it does, it would be
	// safe to loop and call futex again.
	systemstack(func() {
		print("futexwakeup addr=", addr, " returned ", ret, "\n")
	})

	*(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006
}

func getproccount() int32 {
	// This buffer is huge (8 kB) but we are on the system stack
	// and there should be plenty of space (64 kB).
	// Also this is a leaf, so we're not holding up the memory for long.
	// See golang.org/issue/11823.
	// The suggested behavior here is to keep trying with ever-larger
	// buffers, but we don't have a dynamic memory allocator at the
	// moment, so that's a bit tricky and seems like overkill.
	const maxCPUs = 64 * 1024
	var buf [maxCPUs / (ptrSize * 8)]uintptr
	r := sched_getaffinity(0, unsafe.Sizeof(buf), &buf[0])
	n := int32(0)
	for _, v := range buf[:r/ptrSize] {
		for v != 0 {
			n += int32(v & 1)
			v >>= 1
		}
	}
	if n == 0 {
		n = 1
	}
	return n
}

// Clone, the Linux rfork.
const (
	_CLONE_VM             = 0x100
	_CLONE_FS             = 0x200
	_CLONE_FILES          = 0x400
	_CLONE_SIGHAND        = 0x800
	_CLONE_PTRACE         = 0x2000
	_CLONE_VFORK          = 0x4000
	_CLONE_PARENT         = 0x8000
	_CLONE_THREAD         = 0x10000
	_CLONE_NEWNS          = 0x20000
	_CLONE_SYSVSEM        = 0x40000
	_CLONE_SETTLS         = 0x80000
	_CLONE_PARENT_SETTID  = 0x100000
	_CLONE_CHILD_CLEARTID = 0x200000
	_CLONE_UNTRACED       = 0x800000
	_CLONE_CHILD_SETTID   = 0x1000000
	_CLONE_STOPPED        = 0x2000000
	_CLONE_NEWUTS         = 0x4000000
	_CLONE_NEWIPC         = 0x8000000

	cloneFlags = _CLONE_VM | /* share memory */
		_CLONE_FS | /* share cwd, etc */
		_CLONE_FILES | /* share fd table */
		_CLONE_SIGHAND | /* share sig handler table */
		_CLONE_THREAD /* revisit - okay for now */
)

// May run with m.p==nil, so write barriers are not allowed.
//go:nowritebarrier
func newosproc(mp *m, stk unsafe.Pointer) {
	/*
	 * note: strace gets confused if we use CLONE_PTRACE here.
	 */
	mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
	if false {
		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " clone=", funcPC(clone), " id=", mp.id, "/", mp.tls[0], " ostk=", &mp, "\n")
	}

	// Disable signals during clone, so that the new thread starts
	// with signals disabled.  It will enable them in minit.
	var oset sigset
	rtsigprocmask(_SIG_SETMASK, &sigset_all, &oset, int32(unsafe.Sizeof(oset)))
	ret := clone(cloneFlags, stk, unsafe.Pointer(mp), unsafe.Pointer(mp.g0), unsafe.Pointer(funcPC(mstart)))
	rtsigprocmask(_SIG_SETMASK, &oset, nil, int32(unsafe.Sizeof(oset)))

	if ret < 0 {
		print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", -ret, ")\n")
		throw("newosproc")
	}
}

// Version of newosproc that doesn't require a valid G.
//go:nosplit
func newosproc0(stacksize uintptr, fn unsafe.Pointer) {
	stack := sysAlloc(stacksize, &memstats.stacks_sys)
	if stack == nil {
		write(2, unsafe.Pointer(&failallocatestack[0]), int32(len(failallocatestack)))
		exit(1)
	}
	ret := clone(cloneFlags, unsafe.Pointer(uintptr(stack)+stacksize), nil, nil, fn)
	if ret < 0 {
		write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
		exit(1)
	}
}

var failallocatestack = []byte("runtime: failed to allocate stack for the new OS thread\n")
var failthreadcreate = []byte("runtime: failed to create new OS thread\n")

func osinit() {
	ncpu = getproccount()
}

var urandom_dev = []byte("/dev/urandom\x00")

func getRandomData(r []byte) {
	if startupRandomData != nil {
		n := copy(r, startupRandomData)
		extendRandom(r, n)
		return
	}
	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
	closefd(fd)
	extendRandom(r, int(n))
}

func goenvs() {
	goenvs_unix()
}

// Called to initialize a new m (including the bootstrap m).
// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
func mpreinit(mp *m) {
	mp.gsignal = malg(32 * 1024) // Linux wants >= 2K
	mp.gsignal.m = mp
}

func msigsave(mp *m) {
	smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
	if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
		throw("insufficient storage for signal mask")
	}
	rtsigprocmask(_SIG_SETMASK, nil, smask, int32(unsafe.Sizeof(*smask)))
}

func gettid() uint32

// Called to initialize a new m (including the bootstrap m).
// Called on the new thread, can not allocate memory.
func minit() {
	// Initialize signal handling.
	_g_ := getg()
	signalstack(&_g_.m.gsignal.stack)

	// for debuggers, in case cgo created the thread
	_g_.m.procid = uint64(gettid())

	// restore signal mask from m.sigmask and unblock essential signals
	nmask := *(*sigset)(unsafe.Pointer(&_g_.m.sigmask))
	for i := range sigtable {
		if sigtable[i].flags&_SigUnblock != 0 {
			nmask[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
		}
	}
	rtsigprocmask(_SIG_SETMASK, &nmask, nil, int32(unsafe.Sizeof(nmask)))
}

// Called from dropm to undo the effect of an minit.
func unminit() {
	_g_ := getg()
	smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
	rtsigprocmask(_SIG_SETMASK, smask, nil, int32(unsafe.Sizeof(*smask)))
	signalstack(nil)
}

func memlimit() uintptr {
	/*
		TODO: Convert to Go when something actually uses the result.

		Rlimit rl;
		extern byte runtime·text[], runtime·end[];
		uintptr used;

		if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
			return 0;
		if(rl.rlim_cur >= 0x7fffffff)
			return 0;

		// Estimate our VM footprint excluding the heap.
		// Not an exact science: use size of binary plus
		// some room for thread stacks.
		used = runtime·end - runtime·text + (64<<20);
		if(used >= rl.rlim_cur)
			return 0;

		// If there's not at least 16 MB left, we're probably
		// not going to be able to do much.  Treat as no limit.
		rl.rlim_cur -= used;
		if(rl.rlim_cur < (16<<20))
			return 0;

		return rl.rlim_cur - used;
	*/

	return 0
}

//#ifdef GOARCH_386
//#define sa_handler k_sa_handler
//#endif

func sigreturn()
func sigtramp()

func setsig(i int32, fn uintptr, restart bool) {
	var sa sigactiont
	memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTORER
	if restart {
		sa.sa_flags |= _SA_RESTART
	}
	sa.sa_mask = ^uint64(0)
	// Although Linux manpage says "sa_restorer element is obsolete and
	// should not be used". x86_64 kernel requires it. Only use it on
	// x86.
	if GOARCH == "386" || GOARCH == "amd64" {
		sa.sa_restorer = funcPC(sigreturn)
	}
	if fn == funcPC(sighandler) {
		fn = funcPC(sigtramp)
	}
	sa.sa_handler = fn
	if rt_sigaction(uintptr(i), &sa, nil, unsafe.Sizeof(sa.sa_mask)) != 0 {
		throw("rt_sigaction failure")
	}
}

func setsigstack(i int32) {
	var sa sigactiont
	if rt_sigaction(uintptr(i), nil, &sa, unsafe.Sizeof(sa.sa_mask)) != 0 {
		throw("rt_sigaction failure")
	}
	if sa.sa_handler == 0 || sa.sa_handler == _SIG_DFL || sa.sa_handler == _SIG_IGN || sa.sa_flags&_SA_ONSTACK != 0 {
		return
	}
	sa.sa_flags |= _SA_ONSTACK
	if rt_sigaction(uintptr(i), &sa, nil, unsafe.Sizeof(sa.sa_mask)) != 0 {
		throw("rt_sigaction failure")
	}
}

func getsig(i int32) uintptr {
	var sa sigactiont

	memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
	if rt_sigaction(uintptr(i), nil, &sa, unsafe.Sizeof(sa.sa_mask)) != 0 {
		throw("rt_sigaction read failure")
	}
	if sa.sa_handler == funcPC(sigtramp) {
		return funcPC(sighandler)
	}
	return sa.sa_handler
}

func signalstack(s *stack) {
	var st sigaltstackt
	if s == nil {
		st.ss_flags = _SS_DISABLE
	} else {
		st.ss_sp = (*byte)(unsafe.Pointer(s.lo))
		st.ss_size = s.hi - s.lo
		st.ss_flags = 0
	}
	sigaltstack(&st, nil)
}

func updatesigmask(m sigmask) {
	var mask sigset
	copy(mask[:], m[:])
	rtsigprocmask(_SIG_SETMASK, &mask, nil, int32(unsafe.Sizeof(mask)))
}

func unblocksig(sig int32) {
	var mask sigset
	mask[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
	rtsigprocmask(_SIG_UNBLOCK, &mask, nil, int32(unsafe.Sizeof(mask)))
}
<commit_msg>runtime: pass a smaller buffer to sched_getaffinity on ARM<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package runtime

import "unsafe"

var sigset_all sigset = sigset{^uint32(0), ^uint32(0)}

// Linux futex.
//
//	futexsleep(uint32 *addr, uint32 val)
//	futexwakeup(uint32 *addr)
//
// Futexsleep atomically checks if *addr == val and if so, sleeps on addr.
// Futexwakeup wakes up threads sleeping on addr.
// Futexsleep is allowed to wake up spuriously.

const (
	_FUTEX_WAIT = 0
	_FUTEX_WAKE = 1
)

// Atomically,
//	if(*addr == val) sleep
// Might be woken up spuriously; that's allowed.
// Don't sleep longer than ns; ns < 0 means forever.
//go:nosplit
func futexsleep(addr *uint32, val uint32, ns int64) {
	var ts timespec

	// Some Linux kernels have a bug where futex of
	// FUTEX_WAIT returns an internal error code
	// as an errno.  Libpthread ignores the return value
	// here, and so can we: as it says a few lines up,
	// spurious wakeups are allowed.
	if ns < 0 {
		futex(unsafe.Pointer(addr), _FUTEX_WAIT, val, nil, nil, 0)
		return
	}

	// It's difficult to live within the no-split stack limits here.
	// On ARM and 386, a 64-bit divide invokes a general software routine
	// that needs more stack than we can afford. So we use timediv instead.
	// But on real 64-bit systems, where words are larger but the stack limit
	// is not, even timediv is too heavy, and we really need to use just an
	// ordinary machine instruction.
	if ptrSize == 8 {
		ts.set_sec(ns / 1000000000)
		ts.set_nsec(int32(ns % 1000000000))
	} else {
		ts.tv_nsec = 0
		ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec)))))
	}
	futex(unsafe.Pointer(addr), _FUTEX_WAIT, val, unsafe.Pointer(&ts), nil, 0)
}

// If any procs are sleeping on addr, wake up at most cnt.
//go:nosplit
func futexwakeup(addr *uint32, cnt uint32) {
	ret := futex(unsafe.Pointer(addr), _FUTEX_WAKE, cnt, nil, nil, 0)
	if ret >= 0 {
		return
	}

	// I don't know that futex wakeup can return
	// EAGAIN or EINTR, but if it does, it would be
	// safe to loop and call futex again.
	systemstack(func() {
		print("futexwakeup addr=", addr, " returned ", ret, "\n")
	})

	*(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006
}

func getproccount() int32 {
	// This buffer is huge (8 kB) but we are on the system stack
	// and there should be plenty of space (64 kB) -- except on ARM where
	// the system stack itself is only 8kb (see golang.org/issue/11873).
	// Also this is a leaf, so we're not holding up the memory for long.
	// See golang.org/issue/11823.
	// The suggested behavior here is to keep trying with ever-larger
	// buffers, but we don't have a dynamic memory allocator at the
	// moment, so that's a bit tricky and seems like overkill.
	const maxCPUs = 64*1024*(1-goarch_arm) + 1024*goarch_arm
	var buf [maxCPUs / (ptrSize * 8)]uintptr
	r := sched_getaffinity(0, unsafe.Sizeof(buf), &buf[0])
	n := int32(0)
	for _, v := range buf[:r/ptrSize] {
		for v != 0 {
			n += int32(v & 1)
			v >>= 1
		}
	}
	if n == 0 {
		n = 1
	}
	return n
}

// Clone, the Linux rfork.
const (
	_CLONE_VM             = 0x100
	_CLONE_FS             = 0x200
	_CLONE_FILES          = 0x400
	_CLONE_SIGHAND        = 0x800
	_CLONE_PTRACE         = 0x2000
	_CLONE_VFORK          = 0x4000
	_CLONE_PARENT         = 0x8000
	_CLONE_THREAD         = 0x10000
	_CLONE_NEWNS          = 0x20000
	_CLONE_SYSVSEM        = 0x40000
	_CLONE_SETTLS         = 0x80000
	_CLONE_PARENT_SETTID  = 0x100000
	_CLONE_CHILD_CLEARTID = 0x200000
	_CLONE_UNTRACED       = 0x800000
	_CLONE_CHILD_SETTID   = 0x1000000
	_CLONE_STOPPED        = 0x2000000
	_CLONE_NEWUTS         = 0x4000000
	_CLONE_NEWIPC         = 0x8000000

	cloneFlags = _CLONE_VM | /* share memory */
		_CLONE_FS | /* share cwd, etc */
		_CLONE_FILES | /* share fd table */
		_CLONE_SIGHAND | /* share sig handler table */
		_CLONE_THREAD /* revisit - okay for now */
)

// May run with m.p==nil, so write barriers are not allowed.
//go:nowritebarrier
func newosproc(mp *m, stk unsafe.Pointer) {
	/*
	 * note: strace gets confused if we use CLONE_PTRACE here.
	 */
	mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
	if false {
		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " clone=", funcPC(clone), " id=", mp.id, "/", mp.tls[0], " ostk=", &mp, "\n")
	}

	// Disable signals during clone, so that the new thread starts
	// with signals disabled.  It will enable them in minit.
	var oset sigset
	rtsigprocmask(_SIG_SETMASK, &sigset_all, &oset, int32(unsafe.Sizeof(oset)))
	ret := clone(cloneFlags, stk, unsafe.Pointer(mp), unsafe.Pointer(mp.g0), unsafe.Pointer(funcPC(mstart)))
	rtsigprocmask(_SIG_SETMASK, &oset, nil, int32(unsafe.Sizeof(oset)))

	if ret < 0 {
		print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", -ret, ")\n")
		throw("newosproc")
	}
}

// Version of newosproc that doesn't require a valid G.
//go:nosplit
func newosproc0(stacksize uintptr, fn unsafe.Pointer) {
	stack := sysAlloc(stacksize, &memstats.stacks_sys)
	if stack == nil {
		write(2, unsafe.Pointer(&failallocatestack[0]), int32(len(failallocatestack)))
		exit(1)
	}
	ret := clone(cloneFlags, unsafe.Pointer(uintptr(stack)+stacksize), nil, nil, fn)
	if ret < 0 {
		write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
		exit(1)
	}
}

var failallocatestack = []byte("runtime: failed to allocate stack for the new OS thread\n")
var failthreadcreate = []byte("runtime: failed to create new OS thread\n")

func osinit() {
	ncpu = getproccount()
}

var urandom_dev = []byte("/dev/urandom\x00")

func getRandomData(r []byte) {
	if startupRandomData != nil {
		n := copy(r, startupRandomData)
		extendRandom(r, n)
		return
	}
	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
	closefd(fd)
	extendRandom(r, int(n))
}

func goenvs() {
	goenvs_unix()
}

// Called to initialize a new m (including the bootstrap m).
// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
func mpreinit(mp *m) {
	mp.gsignal = malg(32 * 1024) // Linux wants >= 2K
	mp.gsignal.m = mp
}

func msigsave(mp *m) {
	smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
	if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
		throw("insufficient storage for signal mask")
	}
	rtsigprocmask(_SIG_SETMASK, nil, smask, int32(unsafe.Sizeof(*smask)))
}

func gettid() uint32

// Called to initialize a new m (including the bootstrap m).
// Called on the new thread, can not allocate memory.
func minit() {
	// Initialize signal handling.
	_g_ := getg()
	signalstack(&_g_.m.gsignal.stack)

	// for debuggers, in case cgo created the thread
	_g_.m.procid = uint64(gettid())

	// restore signal mask from m.sigmask and unblock essential signals
	nmask := *(*sigset)(unsafe.Pointer(&_g_.m.sigmask))
	for i := range sigtable {
		if sigtable[i].flags&_SigUnblock != 0 {
			nmask[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
		}
	}
	rtsigprocmask(_SIG_SETMASK, &nmask, nil, int32(unsafe.Sizeof(nmask)))
}

// Called from dropm to undo the effect of an minit.
func unminit() {
	_g_ := getg()
	smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
	rtsigprocmask(_SIG_SETMASK, smask, nil, int32(unsafe.Sizeof(*smask)))
	signalstack(nil)
}

func memlimit() uintptr {
	/*
		TODO: Convert to Go when something actually uses the result.

		Rlimit rl;
		extern byte runtime·text[], runtime·end[];
		uintptr used;

		if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
			return 0;
		if(rl.rlim_cur >= 0x7fffffff)
			return 0;

		// Estimate our VM footprint excluding the heap.
		// Not an exact science: use size of binary plus
		// some room for thread stacks.
		used = runtime·end - runtime·text + (64<<20);
		if(used >= rl.rlim_cur)
			return 0;

		// If there's not at least 16 MB left, we're probably
		// not going to be able to do much.  Treat as no limit.
		rl.rlim_cur -= used;
		if(rl.rlim_cur < (16<<20))
			return 0;

		return rl.rlim_cur - used;
	*/

	return 0
}

//#ifdef GOARCH_386
//#define sa_handler k_sa_handler
//#endif

func sigreturn()
func sigtramp()

func setsig(i int32, fn uintptr, restart bool) {
	var sa sigactiont
	memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTORER
	if restart {
		sa.sa_flags |= _SA_RESTART
	}
	sa.sa_mask = ^uint64(0)
	// Although Linux manpage says "sa_restorer element is obsolete and
	// should not be used". x86_64 kernel requires it. Only use it on
	// x86.
	if GOARCH == "386" || GOARCH == "amd64" {
		sa.sa_restorer = funcPC(sigreturn)
	}
	if fn == funcPC(sighandler) {
		fn = funcPC(sigtramp)
	}
	sa.sa_handler = fn
	if rt_sigaction(uintptr(i), &sa, nil, unsafe.Sizeof(sa.sa_mask)) != 0 {
		throw("rt_sigaction failure")
	}
}

func setsigstack(i int32) {
	var sa sigactiont
	if rt_sigaction(uintptr(i), nil, &sa, unsafe.Sizeof(sa.sa_mask)) != 0 {
		throw("rt_sigaction failure")
	}
	if sa.sa_handler == 0 || sa.sa_handler == _SIG_DFL || sa.sa_handler == _SIG_IGN || sa.sa_flags&_SA_ONSTACK != 0 {
		return
	}
	sa.sa_flags |= _SA_ONSTACK
	if rt_sigaction(uintptr(i), &sa, nil, unsafe.Sizeof(sa.sa_mask)) != 0 {
		throw("rt_sigaction failure")
	}
}

func getsig(i int32) uintptr {
	var sa sigactiont

	memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
	if rt_sigaction(uintptr(i), nil, &sa, unsafe.Sizeof(sa.sa_mask)) != 0 {
		throw("rt_sigaction read failure")
	}
	if sa.sa_handler == funcPC(sigtramp) {
		return funcPC(sighandler)
	}
	return sa.sa_handler
}

func signalstack(s *stack) {
	var st sigaltstackt
	if s == nil {
		st.ss_flags = _SS_DISABLE
	} else {
		st.ss_sp = (*byte)(unsafe.Pointer(s.lo))
		st.ss_size = s.hi - s.lo
		st.ss_flags = 0
	}
	sigaltstack(&st, nil)
}

func updatesigmask(m sigmask) {
	var mask sigset
	copy(mask[:], m[:])
	rtsigprocmask(_SIG_SETMASK, &mask, nil, int32(unsafe.Sizeof(mask)))
}

func unblocksig(sig int32) {
	var mask sigset
	mask[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
	rtsigprocmask(_SIG_UNBLOCK, &mask, nil, int32(unsafe.Sizeof(mask)))
}
<|endoftext|>


<commit_before>package main

import (
	"strings"
	"testing"
	"time"

	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack"
	blockstorage_quota "github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/quotasets"
	compute_quota "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/quotasets"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups"
	"github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
	"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/loadbalancers"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/sapcc/kubernikus/pkg/api/client/operations"
	"github.com/sapcc/kubernikus/pkg/api/models"
	"github.com/sapcc/kubernikus/test/e2e/framework"
)

const (
	KlusterPhaseBecomesTerminatingTimeout = 1 * time.Minute
	WaitForKlusterToBeDeletedTimeout      = 10 * time.Minute
)

type CleanupTests struct {
	Kubernikus  *framework.Kubernikus
	OpenStack   *framework.OpenStack
	KlusterName string
	Reuse       bool
}

func (s *CleanupTests) Run(t *testing.T) {
	if t.Run("Cluster/Terminate", s.TerminateCluster) {
		t.Run("Cluster/BecomesTerminating", s.KlusterPhaseBecomesTerminating)
		t.Run("Cluster/IsDeleted", s.WaitForKlusterToBeDeleted)

		if s.Reuse == false {
			t.Run("QuotaPostFlightCheck", s.QuotaPostFlightCheck)
			t.Run("ServerGroupsGotDeleted", s.ServerGroupsGotDeleted)
			t.Run("LoadbalancerGotDeleted", s.LoadbalancerGotDeleted)
		}
	}
}

func (s *CleanupTests) TerminateCluster(t *testing.T) {
	_, err := s.Kubernikus.Client.Operations.TerminateCluster(
		operations.NewTerminateClusterParams().WithName(s.KlusterName),
		s.Kubernikus.AuthInfo,
	)
	assert.NoError(t, err, "There should be no error")
}

func (s *CleanupTests) WaitForKlusterToBeDeleted(t *testing.T) {
	err := s.Kubernikus.WaitForKlusterToBeDeleted(s.KlusterName, WaitForKlusterToBeDeletedTimeout)
	require.NoError(t, err, "There should be no error while waiting %v for the kluster to be deleted", WaitForKlusterToBeDeletedTimeout)
}

func (s *CleanupTests) KlusterPhaseBecomesTerminating(t *testing.T) {
	phase, err := s.Kubernikus.WaitForKlusterPhase(s.KlusterName, models.KlusterPhaseTerminating, KlusterPhaseBecomesTerminatingTimeout)

	if assert.NoError(t, err, "There should be no error") {
		assert.Equal(t, phase, models.KlusterPhaseTerminating, "Kluster should become Terminating")
	}
}

func (s *CleanupTests) QuotaPostFlightCheck(t *testing.T) {
	project, err := tokens.Get(s.OpenStack.Identity, s.OpenStack.Provider.Token()).ExtractProject()
	require.NoError(t, err, "There should be no error while getting project from token")
	require.NotNil(t, project, "project returned from Token %s was nil. WTF?", s.OpenStack.Provider.Token())

	quota, err := compute_quota.GetDetail(s.OpenStack.Compute, project.ID).Extract()
	require.NoError(t, err, "There should be no error while getting compute quota details")

	storage, err := blockstorage_quota.GetUsage(s.OpenStack.BlockStorage, project.ID).Extract()
	require.NoError(t, err, "There should be no error while getting storage quota details")

	assert.Zero(t, quota.Cores.InUse, "There should be no cores left in use")
	assert.Zero(t, quota.Instances.InUse, "There should be no instances left in use")
	assert.Zero(t, quota.RAM.InUse, "There should be no RAM left in use")
	assert.Zero(t, storage.Volumes.InUse, "There should be no Volume left in use")
	assert.Zero(t, storage.Gigabytes.InUse, "There should be no Storage left in use")
}

func (s *CleanupTests) ServerGroupsGotDeleted(t *testing.T) {
	computeClient, err := openstack.NewComputeV2(s.OpenStack.Provider, gophercloud.EndpointOpts{})
	require.NoError(t, err, "There should be no error creating compute client")

	allPages, err := servergroups.List(computeClient).AllPages()
	require.NoError(t, err, "There should be no error listing server groups")

	allGroups, err := servergroups.ExtractServerGroups(allPages)
	require.NoError(t, err, "There should be no error extracting server groups")

	count := 0
	for _, sg := range allGroups {
		if strings.HasPrefix(sg.Name, "e2e-") {
			count++
		}
	}
	require.Equal(t, 0, count, "There should be no server groups left")
}

func (s *CleanupTests) LoadbalancerGotDeleted(t *testing.T) {
	lbClient, err := openstack.NewLoadBalancerV2(s.OpenStack.Provider, gophercloud.EndpointOpts{})
	require.NoError(t, err, "There should be no error getting a loadbalancer client")

	allPages, err := loadbalancers.List(lbClient, loadbalancers.ListOpts{}).AllPages()
	require.NoError(t, err, "There should be no error while listing loadbalancers")

	allLoadbalancers, err := loadbalancers.ExtractLoadBalancers(allPages)
	require.NoError(t, err, "There should be no error while extracting loadbalancers")

	count := 0
	for _, lb := range allLoadbalancers {
		if strings.HasSuffix(lb.Name, "_e2e-lb") {
			count++
		}
	}

	require.Equal(t, 0, count, "There should be no Loadbalancers left")
}
<commit_msg>Raise e2e test kluster deletion timeout<commit_after>package main

import (
	"strings"
	"testing"
	"time"

	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack"
	blockstorage_quota "github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/quotasets"
	compute_quota "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/quotasets"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups"
	"github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
	"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/loadbalancers"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/sapcc/kubernikus/pkg/api/client/operations"
	"github.com/sapcc/kubernikus/pkg/api/models"
	"github.com/sapcc/kubernikus/test/e2e/framework"
)

const (
	KlusterPhaseBecomesTerminatingTimeout = 1 * time.Minute
	WaitForKlusterToBeDeletedTimeout      = 15 * time.Minute
)

type CleanupTests struct {
	Kubernikus  *framework.Kubernikus
	OpenStack   *framework.OpenStack
	KlusterName string
	Reuse       bool
}

func (s *CleanupTests) Run(t *testing.T) {
	if t.Run("Cluster/Terminate", s.TerminateCluster) {
		t.Run("Cluster/BecomesTerminating", s.KlusterPhaseBecomesTerminating)
		t.Run("Cluster/IsDeleted", s.WaitForKlusterToBeDeleted)

		if s.Reuse == false {
			t.Run("QuotaPostFlightCheck", s.QuotaPostFlightCheck)
			t.Run("ServerGroupsGotDeleted", s.ServerGroupsGotDeleted)
			t.Run("LoadbalancerGotDeleted", s.LoadbalancerGotDeleted)
		}
	}
}

func (s *CleanupTests) TerminateCluster(t *testing.T) {
	_, err := s.Kubernikus.Client.Operations.TerminateCluster(
		operations.NewTerminateClusterParams().WithName(s.KlusterName),
		s.Kubernikus.AuthInfo,
	)
	assert.NoError(t, err, "There should be no error")
}

func (s *CleanupTests) WaitForKlusterToBeDeleted(t *testing.T) {
	err := s.Kubernikus.WaitForKlusterToBeDeleted(s.KlusterName, WaitForKlusterToBeDeletedTimeout)
	require.NoError(t, err, "There should be no error while waiting %v for the kluster to be deleted", WaitForKlusterToBeDeletedTimeout)
}

func (s *CleanupTests) KlusterPhaseBecomesTerminating(t *testing.T) {
	phase, err := s.Kubernikus.WaitForKlusterPhase(s.KlusterName, models.KlusterPhaseTerminating, KlusterPhaseBecomesTerminatingTimeout)

	if assert.NoError(t, err, "There should be no error") {
		assert.Equal(t, phase, models.KlusterPhaseTerminating, "Kluster should become Terminating")
	}
}

func (s *CleanupTests) QuotaPostFlightCheck(t *testing.T) {
	project, err := tokens.Get(s.OpenStack.Identity, s.OpenStack.Provider.Token()).ExtractProject()
	require.NoError(t, err, "There should be no error while getting project from token")
	require.NotNil(t, project, "project returned from Token %s was nil. WTF?", s.OpenStack.Provider.Token())

	quota, err := compute_quota.GetDetail(s.OpenStack.Compute, project.ID).Extract()
	require.NoError(t, err, "There should be no error while getting compute quota details")

	storage, err := blockstorage_quota.GetUsage(s.OpenStack.BlockStorage, project.ID).Extract()
	require.NoError(t, err, "There should be no error while getting storage quota details")

	assert.Zero(t, quota.Cores.InUse, "There should be no cores left in use")
	assert.Zero(t, quota.Instances.InUse, "There should be no instances left in use")
	assert.Zero(t, quota.RAM.InUse, "There should be no RAM left in use")
	assert.Zero(t, storage.Volumes.InUse, "There should be no Volume left in use")
	assert.Zero(t, storage.Gigabytes.InUse, "There should be no Storage left in use")
}

func (s *CleanupTests) ServerGroupsGotDeleted(t *testing.T) {
	computeClient, err := openstack.NewComputeV2(s.OpenStack.Provider, gophercloud.EndpointOpts{})
	require.NoError(t, err, "There should be no error creating compute client")

	allPages, err := servergroups.List(computeClient).AllPages()
	require.NoError(t, err, "There should be no error listing server groups")

	allGroups, err := servergroups.ExtractServerGroups(allPages)
	require.NoError(t, err, "There should be no error extracting server groups")

	count := 0
	for _, sg := range allGroups {
		if strings.HasPrefix(sg.Name, "e2e-") {
			count++
		}
	}
	require.Equal(t, 0, count, "There should be no server groups left")
}

func (s *CleanupTests) LoadbalancerGotDeleted(t *testing.T) {
	lbClient, err := openstack.NewLoadBalancerV2(s.OpenStack.Provider, gophercloud.EndpointOpts{})
	require.NoError(t, err, "There should be no error getting a loadbalancer client")

	allPages, err := loadbalancers.List(lbClient, loadbalancers.ListOpts{}).AllPages()
	require.NoError(t, err, "There should be no error while listing loadbalancers")

	allLoadbalancers, err := loadbalancers.ExtractLoadBalancers(allPages)
	require.NoError(t, err, "There should be no error while extracting loadbalancers")

	count := 0
	for _, lb := range allLoadbalancers {
		if strings.HasSuffix(lb.Name, "_e2e-lb") {
			count++
		}
	}

	require.Equal(t, 0, count, "There should be no Loadbalancers left")
}
<|endoftext|>


<commit_before>// errorcheck

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

package main

func f() int {	// GCCGO_ERROR "control"
	if false {
		return 0;
	}
	// we should not be able to return successfully w/o a return statement
} // GC_ERROR "return"

func main() {
	print(f(), "\n");
}

/*
uetli:~/Source/go1/usr/gri/gosrc gri$ 6g bug.go && 6l bug.6 && 6.out
4882
*/
<commit_msg>test: update bug086.go for current gccgo behaviour<commit_after>// errorcheck

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

package main

func f() int {
	if false {
		return 0;
	}
	// we should not be able to return successfully w/o a return statement
} // ERROR "return"

func main() {
	print(f(), "\n");
}

/*
uetli:~/Source/go1/usr/gri/gosrc gri$ 6g bug.go && 6l bug.6 && 6.out
4882
*/
<|endoftext|>