<commit_before>//
// DISCLAIMER
//
// Copyright 2017 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
// Author Ewout Prangsma
//

package protocol

import (
	"context"
	"crypto/tls"
	"fmt"
	"io"
	"net"
	"sync"
	"sync/atomic"
	"time"

	driver "github.com/arangodb/go-driver"
)

// Connection is a single socket connection to a server.
type Connection struct {
	version       Version
	lastMessageID uint64
	maxChunkSize  uint32
	msgStore      messageStore
	conn          net.Conn
	writeMutex    sync.Mutex
	closing       int32
	lastActivity  time.Time
	configured    int32 // Set to 1 after the configuration callback has finished without errors.
}

const (
	defaultMaxChunkSize = 30000
	maxRecentErrors     = 64
)

var (
	vstProtocolHeader1_0 = []byte("VST/1.0\r\n\r\n")
	vstProtocolHeader1_1 = []byte("VST/1.1\r\n\r\n")
)

// dial opens a new connection to the server on the given address.
func dial(version Version, addr string, tlsConfig *tls.Config) (*Connection, error) {
	// Create TCP connection
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		return nil, driver.WithStack(err)
	}

	// Configure connection
	if tcpConn, ok := conn.(*net.TCPConn); ok {
		tcpConn.SetKeepAlive(true)
		tcpConn.SetNoDelay(true)
	}

	// Add TLS if needed
	if tlsConfig != nil {
		tlsConfig = tlsConfig.Clone()
		tlsConfig.MaxVersion = tls.VersionTLS10
		tlsConn := tls.Client(conn, tlsConfig)
		conn = tlsConn
	}

	// Send protocol header
	switch version {
	case Version1_0:
		if _, err := conn.Write(vstProtocolHeader1_0); err != nil {
			return nil, driver.WithStack(err)
		}
	case Version1_1:
		if _, err := conn.Write(vstProtocolHeader1_1); err != nil {
			return nil, driver.WithStack(err)
		}
	default:
		return nil, driver.WithStack(fmt.Errorf("Unknown protocol version %d", int(version)))
	}

	// prepare connection
	c := &Connection{
		version:      version,
		maxChunkSize: defaultMaxChunkSize,
		conn:         conn,
	}
	c.updateLastActivity()

	// Start reading responses
	go c.readChunkLoop()

	return c, nil
}

// load returns an indication of the amount of work this connection has.
// 0 means no work at all, >0 means some work.
func (c *Connection) load() int {
	return c.msgStore.Size()
}

// Close the connection to the server
func (c *Connection) Close() error {
	if atomic.CompareAndSwapInt32(&c.closing, 0, 1) {
		if err := c.conn.Close(); err != nil {
			return driver.WithStack(err)
		}
		c.msgStore.ForEach(func(m *Message) {
			m.closeResponseChan()
		})
	}
	return nil
}

// IsClosed returns true when the connection is closed, false otherwise.
func (c *Connection) IsClosed() bool {
	return atomic.LoadInt32(&c.closing) == 1
}

// IsConfigured returns true when the configuration callback has finished on this connection, without errors.
func (c *Connection) IsConfigured() bool {
	return atomic.LoadInt32(&c.configured) == 1
}

// Send sends a message (consisting of given parts) to the server and returns
// a channel on which the response will be delivered.
// When the connection is closed before a response was received, the returned
// channel will be closed.
func (c *Connection) Send(ctx context.Context, messageParts ...[]byte) (<-chan Message, error) {
	if ctx == nil {
		ctx = context.Background()
	}
	msgID := atomic.AddUint64(&c.lastMessageID, 1)
	chunks, err := buildChunks(msgID, c.maxChunkSize, messageParts...)
	if err != nil {
		return nil, driver.WithStack(err)
	}
	// Prepare for receiving a response
	m := c.msgStore.Add(msgID)
	responseChan := m.responseChan

	//panic(fmt.Sprintf("chunks: %d, messageParts: %d, first: %s", len(chunks), len(messageParts), hex.EncodeToString(messageParts[0])))

	// Send all chunks
	sendErrors := make(chan error)
	deadline, ok := ctx.Deadline()
	if !ok {
		deadline = time.Time{}
	}
	go func() {
		defer close(sendErrors)
		for _, chunk := range chunks {
			if err := c.sendChunk(deadline, chunk); err != nil {
				// Cancel response
				c.msgStore.Remove(msgID)
				// Return error
				sendErrors <- driver.WithStack(err)
				return
			}
		}
	}()

	// Wait for sending to be ready, or context to be cancelled.
	select {
	case err := <-sendErrors:
		if err != nil {
			return nil, driver.WithStack(err)
		}
		return responseChan, nil
	case <-ctx.Done():
		return nil, ctx.Err()
	}
}

// sendChunk sends a single chunk to the server.
func (c *Connection) sendChunk(deadline time.Time, chunk chunk) error {
	c.writeMutex.Lock()
	defer c.writeMutex.Unlock()

	c.conn.SetWriteDeadline(deadline)
	var err error
	switch c.version {
	case Version1_0:
		_, err = chunk.WriteToVST1_0(c.conn)
	case Version1_1:
		_, err = chunk.WriteToVST1_1(c.conn)
	default:
		err = driver.WithStack(fmt.Errorf("Unknown protocol version %d", int(c.version)))
	}
	c.updateLastActivity()
	if err != nil {
		return driver.WithStack(err)
	}
	return nil
}

// readChunkLoop reads chunks from the connection until it is closed.
func (c *Connection) readChunkLoop() {
	recentErrors := 0
	goodChunks := 0
	for {
		if c.IsClosed() {
			// Closing, we're done
			return
		}
		var chunk chunk
		var err error
		switch c.version {
		case Version1_0:
			chunk, err = readChunkVST1_0(c.conn)
		case Version1_1:
			chunk, err = readChunkVST1_1(c.conn)
		default:
			err = driver.WithStack(fmt.Errorf("Unknown protocol version %d", int(c.version)))
		}
		c.updateLastActivity()
		if err != nil {
			if !c.IsClosed() {
				// Handle error
				if err == io.EOF {
					// Connection closed
					c.Close()
				} else {
					recentErrors++
					fmt.Printf("readChunkLoop error: %#v (goodChunks=%d)\n", err, goodChunks)
					if recentErrors > maxRecentErrors {
						// When we get to many errors in a row, close this connection
						c.Close()
					} else {
						// Backoff a bit, so we allow things to settle.
						time.Sleep(time.Millisecond * time.Duration(recentErrors*5))
					}
				}
			}
		} else {
			// Process chunk
			recentErrors = 0
			goodChunks++
			go c.processChunk(chunk)
		}
	}
}

// processChunk adds the given chunk to its message and notifies the listener
// when the message is complete.
func (c *Connection) processChunk(chunk chunk) {
	m := c.msgStore.Get(chunk.MessageID)
	if m == nil {
		// Unexpected chunk, ignore it
		return
	}

	// Add chunk to message
	m.addChunk(chunk)

	// Try to assembly
	if m.assemble() {
		// Message is complete
		// Remove message from store
		c.msgStore.Remove(m.ID)

		//fmt.Println("Chunk: " + hex.EncodeToString(chunk.Data) + "\nMessage: " + hex.EncodeToString(m.Data))

		// Notify listener
		m.notifyListener()
	}
}

// updateLastActivity sets the lastActivity field to the current time.
func (c *Connection) updateLastActivity() {
	c.lastActivity = time.Now()
}

// IsIdle returns true when the last activity was more than the given timeout ago.
func (c *Connection) IsIdle(idleTimeout time.Duration) bool {
	return time.Since(c.lastActivity) > idleTimeout
}
<commit_msg>Removed TLS1.0 limitation<commit_after>//
// DISCLAIMER
//
// Copyright 2017 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
// Author Ewout Prangsma
//

package protocol

import (
	"context"
	"crypto/tls"
	"fmt"
	"io"
	"net"
	"sync"
	"sync/atomic"
	"time"

	driver "github.com/arangodb/go-driver"
)

// Connection is a single socket connection to a server.
type Connection struct {
	version       Version
	lastMessageID uint64
	maxChunkSize  uint32
	msgStore      messageStore
	conn          net.Conn
	writeMutex    sync.Mutex
	closing       int32
	lastActivity  time.Time
	configured    int32 // Set to 1 after the configuration callback has finished without errors.
}

const (
	defaultMaxChunkSize = 30000
	maxRecentErrors     = 64
)

var (
	vstProtocolHeader1_0 = []byte("VST/1.0\r\n\r\n")
	vstProtocolHeader1_1 = []byte("VST/1.1\r\n\r\n")
)

// dial opens a new connection to the server on the given address.
func dial(version Version, addr string, tlsConfig *tls.Config) (*Connection, error) {
	// Create TCP connection
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		return nil, driver.WithStack(err)
	}

	// Configure connection
	if tcpConn, ok := conn.(*net.TCPConn); ok {
		tcpConn.SetKeepAlive(true)
		tcpConn.SetNoDelay(true)
	}

	// Add TLS if needed
	if tlsConfig != nil {
		tlsConn := tls.Client(conn, tlsConfig)
		conn = tlsConn
	}

	// Send protocol header
	switch version {
	case Version1_0:
		if _, err := conn.Write(vstProtocolHeader1_0); err != nil {
			return nil, driver.WithStack(err)
		}
	case Version1_1:
		if _, err := conn.Write(vstProtocolHeader1_1); err != nil {
			return nil, driver.WithStack(err)
		}
	default:
		return nil, driver.WithStack(fmt.Errorf("Unknown protocol version %d", int(version)))
	}

	// prepare connection
	c := &Connection{
		version:      version,
		maxChunkSize: defaultMaxChunkSize,
		conn:         conn,
	}
	c.updateLastActivity()

	// Start reading responses
	go c.readChunkLoop()

	return c, nil
}

// load returns an indication of the amount of work this connection has.
// 0 means no work at all, >0 means some work.
func (c *Connection) load() int {
	return c.msgStore.Size()
}

// Close the connection to the server
func (c *Connection) Close() error {
	if atomic.CompareAndSwapInt32(&c.closing, 0, 1) {
		if err := c.conn.Close(); err != nil {
			return driver.WithStack(err)
		}
		c.msgStore.ForEach(func(m *Message) {
			m.closeResponseChan()
		})
	}
	return nil
}

// IsClosed returns true when the connection is closed, false otherwise.
func (c *Connection) IsClosed() bool {
	return atomic.LoadInt32(&c.closing) == 1
}

// IsConfigured returns true when the configuration callback has finished on this connection, without errors.
func (c *Connection) IsConfigured() bool {
	return atomic.LoadInt32(&c.configured) == 1
}

// Send sends a message (consisting of given parts) to the server and returns
// a channel on which the response will be delivered.
// When the connection is closed before a response was received, the returned
// channel will be closed.
func (c *Connection) Send(ctx context.Context, messageParts ...[]byte) (<-chan Message, error) {
	if ctx == nil {
		ctx = context.Background()
	}
	msgID := atomic.AddUint64(&c.lastMessageID, 1)
	chunks, err := buildChunks(msgID, c.maxChunkSize, messageParts...)
	if err != nil {
		return nil, driver.WithStack(err)
	}
	// Prepare for receiving a response
	m := c.msgStore.Add(msgID)
	responseChan := m.responseChan

	//panic(fmt.Sprintf("chunks: %d, messageParts: %d, first: %s", len(chunks), len(messageParts), hex.EncodeToString(messageParts[0])))

	// Send all chunks
	sendErrors := make(chan error)
	deadline, ok := ctx.Deadline()
	if !ok {
		deadline = time.Time{}
	}
	go func() {
		defer close(sendErrors)
		for _, chunk := range chunks {
			if err := c.sendChunk(deadline, chunk); err != nil {
				// Cancel response
				c.msgStore.Remove(msgID)
				// Return error
				sendErrors <- driver.WithStack(err)
				return
			}
		}
	}()

	// Wait for sending to be ready, or context to be cancelled.
	select {
	case err := <-sendErrors:
		if err != nil {
			return nil, driver.WithStack(err)
		}
		return responseChan, nil
	case <-ctx.Done():
		return nil, ctx.Err()
	}
}

// sendChunk sends a single chunk to the server.
func (c *Connection) sendChunk(deadline time.Time, chunk chunk) error {
	c.writeMutex.Lock()
	defer c.writeMutex.Unlock()

	c.conn.SetWriteDeadline(deadline)
	var err error
	switch c.version {
	case Version1_0:
		_, err = chunk.WriteToVST1_0(c.conn)
	case Version1_1:
		_, err = chunk.WriteToVST1_1(c.conn)
	default:
		err = driver.WithStack(fmt.Errorf("Unknown protocol version %d", int(c.version)))
	}
	c.updateLastActivity()
	if err != nil {
		return driver.WithStack(err)
	}
	return nil
}

// readChunkLoop reads chunks from the connection until it is closed.
func (c *Connection) readChunkLoop() {
	recentErrors := 0
	goodChunks := 0
	for {
		if c.IsClosed() {
			// Closing, we're done
			return
		}
		var chunk chunk
		var err error
		switch c.version {
		case Version1_0:
			chunk, err = readChunkVST1_0(c.conn)
		case Version1_1:
			chunk, err = readChunkVST1_1(c.conn)
		default:
			err = driver.WithStack(fmt.Errorf("Unknown protocol version %d", int(c.version)))
		}
		c.updateLastActivity()
		if err != nil {
			if !c.IsClosed() {
				// Handle error
				if err == io.EOF {
					// Connection closed
					c.Close()
				} else {
					recentErrors++
					fmt.Printf("readChunkLoop error: %#v (goodChunks=%d)\n", err, goodChunks)
					if recentErrors > maxRecentErrors {
						// When we get to many errors in a row, close this connection
						c.Close()
					} else {
						// Backoff a bit, so we allow things to settle.
						time.Sleep(time.Millisecond * time.Duration(recentErrors*5))
					}
				}
			}
		} else {
			// Process chunk
			recentErrors = 0
			goodChunks++
			go c.processChunk(chunk)
		}
	}
}

// processChunk adds the given chunk to its message and notifies the listener
// when the message is complete.
func (c *Connection) processChunk(chunk chunk) {
	m := c.msgStore.Get(chunk.MessageID)
	if m == nil {
		// Unexpected chunk, ignore it
		return
	}

	// Add chunk to message
	m.addChunk(chunk)

	// Try to assembly
	if m.assemble() {
		// Message is complete
		// Remove message from store
		c.msgStore.Remove(m.ID)

		//fmt.Println("Chunk: " + hex.EncodeToString(chunk.Data) + "\nMessage: " + hex.EncodeToString(m.Data))

		// Notify listener
		m.notifyListener()
	}
}

// updateLastActivity sets the lastActivity field to the current time.
func (c *Connection) updateLastActivity() {
	c.lastActivity = time.Now()
}

// IsIdle returns true when the last activity was more than the given timeout ago.
func (c *Connection) IsIdle(idleTimeout time.Duration) bool {
	return time.Since(c.lastActivity) > idleTimeout
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Kubernetes Authors.

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

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

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

package e2e

// Put common test fixtures (e.g. resources to be created) here.

import (
	"context"
	"fmt"
	"reflect"

	"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud/meta"
	"google.golang.org/api/compute/v1"
	apps "k8s.io/api/apps/v1"
	"k8s.io/api/core/v1"
	"k8s.io/api/networking/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/util/intstr"
	"k8s.io/ingress-gce/cmd/echo/app"
	"k8s.io/klog"
)

const (
	echoheadersImage = "gcr.io/k8s-ingress-image-push/ingress-gce-echo-amd64:master"

	// TODO: remove beta topology key once it is GAed
	zoneBetaTopologyKey = "failure-domain.beta.kubernetes.io/zone"
	zoneGATopologyKey   = "failure-domain.beta.kubernetes.io/zone"
)

// NoopModify does not modify the input deployment
func NoopModify(*apps.Deployment) {}

// SpreadPodAcrossZones sets pod anti affinity rules to try to spread pods across zones
func SpreadPodAcrossZones(deployment *apps.Deployment) {
	podLabels := deployment.Spec.Template.Labels
	deployment.Spec.Template.Spec.Affinity = &v1.Affinity{
		PodAntiAffinity: &v1.PodAntiAffinity{
			PreferredDuringSchedulingIgnoredDuringExecution: []v1.WeightedPodAffinityTerm{
				{
					Weight: int32(1),
					PodAffinityTerm: v1.PodAffinityTerm{
						LabelSelector: metav1.SetAsLabelSelector(labels.Set(podLabels)),
						TopologyKey:   zoneBetaTopologyKey,
					},
				},
				{
					Weight: int32(2),
					PodAffinityTerm: v1.PodAffinityTerm{
						LabelSelector: metav1.SetAsLabelSelector(labels.Set(podLabels)),
						TopologyKey:   zoneGATopologyKey,
					},
				},
			},
		},
	}

}

// CreateEchoService creates the pod and service serving echoheaders
// Todo: (shance) remove this and replace uses with EnsureEchoService()
func CreateEchoService(s *Sandbox, name string, annotations map[string]string) (*v1.Service, error) {
	return EnsureEchoService(s, name, annotations, v1.ServiceTypeNodePort, 1)
}

// EnsureEchoService that the Echo service with the given description is set up
func EnsureEchoService(s *Sandbox, name string, annotations map[string]string, svcType v1.ServiceType, numReplicas int32) (*v1.Service, error) {
	if err := EnsureEchoDeployment(s, name, numReplicas, NoopModify); err != nil {
		return nil, err
	}

	expectedSvc := &v1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Name:        name,
			Annotations: annotations,
		},
		Spec: v1.ServiceSpec{
			Ports: []v1.ServicePort{
				{
					Name:       "http-port",
					Protocol:   v1.ProtocolTCP,
					Port:       80,
					TargetPort: intstr.FromInt(8080),
				},
				{
					Name:       "https-port",
					Protocol:   v1.ProtocolTCP,
					Port:       443,
					TargetPort: intstr.FromInt(8443),
				},
			},
			Selector: map[string]string{"app": name},
			Type:     svcType,
		},
	}
	svc, err := s.f.Clientset.CoreV1().Services(s.Namespace).Get(name, metav1.GetOptions{})

	if svc == nil || err != nil {
		if svc, err = s.f.Clientset.CoreV1().Services(s.Namespace).Create(expectedSvc); err != nil {
			return nil, err
		}
		return svc, err
	}

	if !reflect.DeepEqual(svc.Spec, expectedSvc.Spec) {
		// Update the fields individually since we don't want to override everything
		svc.ObjectMeta.Annotations = expectedSvc.ObjectMeta.Annotations
		svc.Spec.Ports = expectedSvc.Spec.Ports
		svc.Spec.Type = expectedSvc.Spec.Type

		if svc, err := s.f.Clientset.CoreV1().Services(s.Namespace).Update(svc); err != nil {
			return nil, fmt.Errorf("svc: %v\nexpectedSvc: %v\nerr: %v", svc, expectedSvc, err)
		}
	}
	return svc, nil
}

// Ensures that the Echo deployment with the given description is set up
func EnsureEchoDeployment(s *Sandbox, name string, numReplicas int32, modify func(deployment *apps.Deployment)) error {
	podTemplate := v1.PodTemplateSpec{
		ObjectMeta: metav1.ObjectMeta{
			Name:   name,
			Labels: map[string]string{"app": name},
		},
		Spec: v1.PodSpec{
			Containers: []v1.Container{
				{
					Name:  "echoheaders",
					Image: echoheadersImage,
					Ports: []v1.ContainerPort{
						{ContainerPort: 8080, Name: "http-port"},
						{ContainerPort: 8443, Name: "https-port"},
					},
					Env: []v1.EnvVar{
						{
							Name: app.HostEnvVar,
							ValueFrom: &v1.EnvVarSource{
								FieldRef: &v1.ObjectFieldSelector{
									FieldPath: "spec.nodeName",
								},
							},
						},
						{
							Name: app.PodEnvVar,
							ValueFrom: &v1.EnvVarSource{
								FieldRef: &v1.ObjectFieldSelector{
									FieldPath: "metadata.name",
								},
							},
						},
						{
							Name: app.NamespaceEnvVar,
							ValueFrom: &v1.EnvVarSource{
								FieldRef: &v1.ObjectFieldSelector{
									FieldPath: "metadata.namespace",
								},
							},
						},
					},
				},
			},
		},
	}

	deployment := &apps.Deployment{
		ObjectMeta: metav1.ObjectMeta{Name: name},
		Spec: apps.DeploymentSpec{
			Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": name}},
			Template: podTemplate,
			Replicas: &numReplicas,
		},
	}
	modify(deployment)

	existingDeployment, err := s.f.Clientset.ExtensionsV1beta1().Deployments(s.Namespace).Get(name, metav1.GetOptions{})
	if existingDeployment == nil || err != nil {
		if _, err = s.f.Clientset.AppsV1().Deployments(s.Namespace).Create(deployment); err != nil {
			return err
		}
	} else {
		if _, err = s.f.Clientset.AppsV1().Deployments(s.Namespace).Update(deployment); err != nil {
			return err
		}
	}

	deployment.Spec.Replicas = &numReplicas
	if _, err = s.f.Clientset.AppsV1().Deployments(s.Namespace).Update(deployment); err != nil {
		return fmt.Errorf("Error updating deployment scale: %v", err)
	}
	return nil
}

// CreateSecret creates a secret from the given data.
func CreateSecret(s *Sandbox, name string, data map[string][]byte) (*v1.Secret, error) {
	secret := &v1.Secret{
		ObjectMeta: metav1.ObjectMeta{
			Name: name,
		},
		Data: data,
	}
	var err error
	if secret, err = s.f.Clientset.CoreV1().Secrets(s.Namespace).Create(secret); err != nil {
		return nil, err
	}
	klog.V(2).Infof("Secret %q:%q created", s.Namespace, name)

	return secret, nil
}

// DeleteSecret deletes a secret.
func DeleteSecret(s *Sandbox, name string) error {
	if err := s.f.Clientset.CoreV1().Secrets(s.Namespace).Delete(name, &metav1.DeleteOptions{}); err != nil {
		return err
	}
	klog.V(2).Infof("Secret %q:%q created", s.Namespace, name)

	return nil
}

// EnsureIngress creates a new Ingress or updates an existing one.
func EnsureIngress(s *Sandbox, ing *v1beta1.Ingress) (*v1beta1.Ingress, error) {
	crud := &IngressCRUD{s.f.Clientset}
	currentIng, err := crud.Get(ing.ObjectMeta.Namespace, ing.ObjectMeta.Name)
	if currentIng == nil || err != nil {
		return crud.Create(ing)
	}
	// Update ingress spec if they are not equal
	if !reflect.DeepEqual(ing.Spec, currentIng.Spec) {
		return crud.Update(ing)
	}
	return ing, nil
}

// NewGCPAddress reserves a global static IP address with the given name.
func NewGCPAddress(s *Sandbox, name string) error {
	addr := &compute.Address{Name: name}
	if err := s.f.Cloud.GlobalAddresses().Insert(context.Background(), meta.GlobalKey(addr.Name), addr); err != nil {
		return err
	}
	klog.V(2).Infof("Global static IP %s created", name)

	return nil
}

// DeleteGCPAddress deletes a global static IP address with the given name.
func DeleteGCPAddress(s *Sandbox, name string) error {
	if err := s.f.Cloud.GlobalAddresses().Delete(context.Background(), meta.GlobalKey(name)); err != nil {
		return err
	}
	klog.V(2).Infof("Global static IP %s deleted", name)

	return nil
}
<commit_msg>use v1 zone topology key<commit_after>/*
Copyright 2018 The Kubernetes Authors.

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

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

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

package e2e

// Put common test fixtures (e.g. resources to be created) here.

import (
	"context"
	"fmt"
	"reflect"

	"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud/meta"
	"google.golang.org/api/compute/v1"
	apps "k8s.io/api/apps/v1"
	"k8s.io/api/core/v1"
	"k8s.io/api/networking/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/util/intstr"
	"k8s.io/ingress-gce/cmd/echo/app"
	"k8s.io/klog"
)

const (
	echoheadersImage = "gcr.io/k8s-ingress-image-push/ingress-gce-echo-amd64:master"
)

// NoopModify does not modify the input deployment
func NoopModify(*apps.Deployment) {}

// SpreadPodAcrossZones sets pod anti affinity rules to try to spread pods across zones
func SpreadPodAcrossZones(deployment *apps.Deployment) {
	podLabels := deployment.Spec.Template.Labels
	deployment.Spec.Template.Spec.Affinity = &v1.Affinity{
		PodAntiAffinity: &v1.PodAntiAffinity{
			PreferredDuringSchedulingIgnoredDuringExecution: []v1.WeightedPodAffinityTerm{
				{
					Weight: int32(1),
					PodAffinityTerm: v1.PodAffinityTerm{
						LabelSelector: metav1.SetAsLabelSelector(labels.Set(podLabels)),
						TopologyKey:   v1.LabelZoneFailureDomain,
					},
				},
			},
		},
	}
}

// CreateEchoService creates the pod and service serving echoheaders
// Todo: (shance) remove this and replace uses with EnsureEchoService()
func CreateEchoService(s *Sandbox, name string, annotations map[string]string) (*v1.Service, error) {
	return EnsureEchoService(s, name, annotations, v1.ServiceTypeNodePort, 1)
}

// EnsureEchoService that the Echo service with the given description is set up
func EnsureEchoService(s *Sandbox, name string, annotations map[string]string, svcType v1.ServiceType, numReplicas int32) (*v1.Service, error) {
	if err := EnsureEchoDeployment(s, name, numReplicas, NoopModify); err != nil {
		return nil, err
	}

	expectedSvc := &v1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Name:        name,
			Annotations: annotations,
		},
		Spec: v1.ServiceSpec{
			Ports: []v1.ServicePort{
				{
					Name:       "http-port",
					Protocol:   v1.ProtocolTCP,
					Port:       80,
					TargetPort: intstr.FromInt(8080),
				},
				{
					Name:       "https-port",
					Protocol:   v1.ProtocolTCP,
					Port:       443,
					TargetPort: intstr.FromInt(8443),
				},
			},
			Selector: map[string]string{"app": name},
			Type:     svcType,
		},
	}
	svc, err := s.f.Clientset.CoreV1().Services(s.Namespace).Get(name, metav1.GetOptions{})

	if svc == nil || err != nil {
		if svc, err = s.f.Clientset.CoreV1().Services(s.Namespace).Create(expectedSvc); err != nil {
			return nil, err
		}
		return svc, err
	}

	if !reflect.DeepEqual(svc.Spec, expectedSvc.Spec) {
		// Update the fields individually since we don't want to override everything
		svc.ObjectMeta.Annotations = expectedSvc.ObjectMeta.Annotations
		svc.Spec.Ports = expectedSvc.Spec.Ports
		svc.Spec.Type = expectedSvc.Spec.Type

		if svc, err := s.f.Clientset.CoreV1().Services(s.Namespace).Update(svc); err != nil {
			return nil, fmt.Errorf("svc: %v\nexpectedSvc: %v\nerr: %v", svc, expectedSvc, err)
		}
	}
	return svc, nil
}

// Ensures that the Echo deployment with the given description is set up
func EnsureEchoDeployment(s *Sandbox, name string, numReplicas int32, modify func(deployment *apps.Deployment)) error {
	podTemplate := v1.PodTemplateSpec{
		ObjectMeta: metav1.ObjectMeta{
			Name:   name,
			Labels: map[string]string{"app": name},
		},
		Spec: v1.PodSpec{
			Containers: []v1.Container{
				{
					Name:  "echoheaders",
					Image: echoheadersImage,
					Ports: []v1.ContainerPort{
						{ContainerPort: 8080, Name: "http-port"},
						{ContainerPort: 8443, Name: "https-port"},
					},
					Env: []v1.EnvVar{
						{
							Name: app.HostEnvVar,
							ValueFrom: &v1.EnvVarSource{
								FieldRef: &v1.ObjectFieldSelector{
									FieldPath: "spec.nodeName",
								},
							},
						},
						{
							Name: app.PodEnvVar,
							ValueFrom: &v1.EnvVarSource{
								FieldRef: &v1.ObjectFieldSelector{
									FieldPath: "metadata.name",
								},
							},
						},
						{
							Name: app.NamespaceEnvVar,
							ValueFrom: &v1.EnvVarSource{
								FieldRef: &v1.ObjectFieldSelector{
									FieldPath: "metadata.namespace",
								},
							},
						},
					},
				},
			},
		},
	}

	deployment := &apps.Deployment{
		ObjectMeta: metav1.ObjectMeta{Name: name},
		Spec: apps.DeploymentSpec{
			Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": name}},
			Template: podTemplate,
			Replicas: &numReplicas,
		},
	}
	modify(deployment)

	existingDeployment, err := s.f.Clientset.ExtensionsV1beta1().Deployments(s.Namespace).Get(name, metav1.GetOptions{})
	if existingDeployment == nil || err != nil {
		if _, err = s.f.Clientset.AppsV1().Deployments(s.Namespace).Create(deployment); err != nil {
			return err
		}
	} else {
		if _, err = s.f.Clientset.AppsV1().Deployments(s.Namespace).Update(deployment); err != nil {
			return err
		}
	}

	deployment.Spec.Replicas = &numReplicas
	if _, err = s.f.Clientset.AppsV1().Deployments(s.Namespace).Update(deployment); err != nil {
		return fmt.Errorf("Error updating deployment scale: %v", err)
	}
	return nil
}

// CreateSecret creates a secret from the given data.
func CreateSecret(s *Sandbox, name string, data map[string][]byte) (*v1.Secret, error) {
	secret := &v1.Secret{
		ObjectMeta: metav1.ObjectMeta{
			Name: name,
		},
		Data: data,
	}
	var err error
	if secret, err = s.f.Clientset.CoreV1().Secrets(s.Namespace).Create(secret); err != nil {
		return nil, err
	}
	klog.V(2).Infof("Secret %q:%q created", s.Namespace, name)

	return secret, nil
}

// DeleteSecret deletes a secret.
func DeleteSecret(s *Sandbox, name string) error {
	if err := s.f.Clientset.CoreV1().Secrets(s.Namespace).Delete(name, &metav1.DeleteOptions{}); err != nil {
		return err
	}
	klog.V(2).Infof("Secret %q:%q created", s.Namespace, name)

	return nil
}

// EnsureIngress creates a new Ingress or updates an existing one.
func EnsureIngress(s *Sandbox, ing *v1beta1.Ingress) (*v1beta1.Ingress, error) {
	crud := &IngressCRUD{s.f.Clientset}
	currentIng, err := crud.Get(ing.ObjectMeta.Namespace, ing.ObjectMeta.Name)
	if currentIng == nil || err != nil {
		return crud.Create(ing)
	}
	// Update ingress spec if they are not equal
	if !reflect.DeepEqual(ing.Spec, currentIng.Spec) {
		return crud.Update(ing)
	}
	return ing, nil
}

// NewGCPAddress reserves a global static IP address with the given name.
func NewGCPAddress(s *Sandbox, name string) error {
	addr := &compute.Address{Name: name}
	if err := s.f.Cloud.GlobalAddresses().Insert(context.Background(), meta.GlobalKey(addr.Name), addr); err != nil {
		return err
	}
	klog.V(2).Infof("Global static IP %s created", name)

	return nil
}

// DeleteGCPAddress deletes a global static IP address with the given name.
func DeleteGCPAddress(s *Sandbox, name string) error {
	if err := s.f.Cloud.GlobalAddresses().Delete(context.Background(), meta.GlobalKey(name)); err != nil {
		return err
	}
	klog.V(2).Infof("Global static IP %s deleted", name)

	return nil
}
<|endoftext|>


<commit_before>package model

import (
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/blkiodev"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/mount"
	"github.com/docker/docker/api/types/strslice"
	"github.com/docker/go-connections/nat"
	"github.com/docker/go-units"
)

type Instance struct {
	AccountID                   int    `json:"accountId"`
	AllocationState             string `json:"allocationState"`
	Created                     int64  `json:"created"`
	Data                        InstanceFieldsData
	Ports                       []Port
	Description                 string `json:"description"`
	Hostname                    string `json:"hostname"`
	ID                          int    `json:"id"`
	Image                       Image
	ImageID                     int    `json:"imageId"`
	Kind                        string `json:"kind"`
	Name                        string `json:"name"`
	Nics                        []Nic
	Offering                    interface{} `json:"offering"`
	OfferingID                  interface{} `json:"offeringId"`
	OnCrash                     string      `json:"onCrash"`
	PostComputeState            string      `json:"postComputeState"`
	RemoveTime                  interface{} `json:"removeTime"`
	Removed                     interface{} `json:"removed"`
	RequestedOfferingID         interface{} `json:"requestedOfferingId"`
	RequestedState              interface{} `json:"requestedState"`
	State                       string      `json:"state"`
	Type                        string      `json:"type"`
	UUID                        string      `json:"uuid"`
	Volumes                     []Volume
	ZoneID                      int    `json:"zoneId"`
	ExternalID                  string `json:"externalId"`
	AgentID                     int
	InstanceLinks               []Link
	NetworkContainer            *Instance
	NativeContainer             bool
	DataVolumesFromContainers   []*Instance
	CommandArgs                 []string
	Labels                      map[string]interface{}
	ProcessData                 ProcessData
	VolumesFromDataVolumeMounts []Volume
	Token                       string
	MilliCPUReservation         int64
	MemoryReservation           int64
	System                      bool
}

type InstanceFieldsData struct {
	Fields InstanceFields
	IPSec  map[string]struct {
		Nat    float64
		Isakmp float64
	} `json:"ipsec"`
	DockerInspect ContainerJSON `json:"dockerInspect,omitempty" yaml:"dockerInspect,omitempty"`
	Process       ProcessData
}

type ContainerJSON struct {
	ID              string `json:"Id"`
	Created         string
	Path            string
	Args            []string
	State           types.ContainerState
	Image           string
	ResolvConfPath  string
	HostnamePath    string
	HostsPath       string
	LogPath         string
	Node            types.ContainerNode `json:",omitempty"`
	Name            string
	RestartCount    int
	Driver          string
	MountLabel      string
	ProcessLabel    string
	AppArmorProfile string
	ExecIDs         []string
	HostConfig      HostConfig
	GraphDriver     types.GraphDriverData
	SizeRw          int64 `json:",omitempty"`
	SizeRootFs      int64 `json:",omitempty"`
	Mounts          []types.MountPoint
	Config          container.Config
	NetworkSettings types.NetworkSettings
}

type HostConfig struct {
	// Applicable to all platforms
	Binds           []string                // List of volume bindings for this container
	ContainerIDFile string                  // File (path) where the containerId is written
	LogConfig       LogConfig               // Configuration of the logs for this container
	NetworkMode     container.NetworkMode   // Network mode to use for the container
	PortBindings    nat.PortMap             // Port mapping between the exposed port (container) and the host
	RestartPolicy   container.RestartPolicy // Restart policy to be used for the container
	AutoRemove      bool                    // Automatically remove container when it exits
	VolumeDriver    string                  // Name of the volume driver used to mount volumes
	VolumesFrom     []string                // List of volumes to take from other container

	// Applicable to UNIX platforms
	CapAdd          strslice.StrSlice    // List of kernel capabilities to add to the container
	CapDrop         strslice.StrSlice    // List of kernel capabilities to remove from the container
	DNS             []string             `json:"Dns"`        // List of DNS server to lookup
	DNSOptions      []string             `json:"DnsOptions"` // List of DNSOption to look for
	DNSSearch       []string             `json:"DnsSearch"`  // List of DNSSearch to look for
	ExtraHosts      []string             // List of extra hosts
	GroupAdd        []string             // List of additional groups that the container process will run as
	IpcMode         container.IpcMode    // IPC namespace to use for the container
	Cgroup          container.CgroupSpec // Cgroup to use for the container
	Links           []string             // List of links (in the name:alias form)
	OomScoreAdj     int                  // Container preference for OOM-killing
	PidMode         container.PidMode    // PID namespace to use for the container
	Privileged      bool                 // Is the container in privileged mode
	PublishAllPorts bool                 // Should docker publish all exposed port for the container
	ReadonlyRootfs  bool                 // Is the container root filesystem in read-only
	SecurityOpt     []string             // List of string values to customize labels for MLS systems, such as SELinux.
	StorageOpt      map[string]string    `json:",omitempty"` // Storage driver options per container.
	Tmpfs           map[string]string    `json:",omitempty"` // List of tmpfs (mounts) used for the container
	UTSMode         container.UTSMode    // UTS namespace to use for the container
	UsernsMode      container.UsernsMode // The user namespace to use for the container
	ShmSize         int64                // Total shm memory usage
	Sysctls         map[string]string    `json:",omitempty"` // List of Namespaced sysctls used for the container
	Runtime         string               `json:",omitempty"` // Runtime to use with this container

	// Applicable to Windows
	//ConsoleSize [2]int    // Initial console size
	Isolation container.Isolation // Isolation technology of the container (eg default, hyperv)

	// Contains container's resources (cgroups, ulimits)
	Resources

	// Mounts specs used by the container
	Mounts []mount.Mount `json:",omitempty"`
}

type Resources struct {
	// Applicable to all platforms
	CPUShares int64 `json:"CpuShares"` // CPU shares (relative weight vs. other containers)
	Memory    int64 // Memory limit (in bytes)

	// Applicable to UNIX platforms
	CgroupParent         string // Parent cgroup.
	BlkioWeight          uint16 // Block IO weight (relative weight vs. other containers)
	BlkioWeightDevice    []*blkiodev.WeightDevice
	BlkioDeviceReadBps   []*blkiodev.ThrottleDevice
	BlkioDeviceWriteBps  []*blkiodev.ThrottleDevice
	BlkioDeviceReadIOps  []*blkiodev.ThrottleDevice
	BlkioDeviceWriteIOps []*blkiodev.ThrottleDevice
	CPUPeriod            int64                     `json:"CpuPeriod"` // CPU CFS (Completely Fair Scheduler) period
	CPUQuota             int64                     `json:"CpuQuota"`  // CPU CFS (Completely Fair Scheduler) quota
	CpusetCpus           string                    // CpusetCpus 0-2, 0,1
	CpusetMems           string                    // CpusetMems 0-2, 0,1
	Devices              []container.DeviceMapping // List of devices to map inside the container
	DiskQuota            int64                     // Disk limit (in bytes)
	KernelMemory         int64                     // Kernel memory limit (in bytes)
	MemoryReservation    int64                     // Memory soft limit (in bytes)
	MemorySwap           int64                     // Total memory usage (memory + swap); set `-1` to enable unlimited swap
	MemorySwappiness     *int64                    // Tuning container memory swappiness behaviour
	OomKillDisable       *bool                     // Whether to disable OOM Killer or not
	PidsLimit            int64                     // Setting pids limit for a container
	Ulimits              []*units.Ulimit           // List of ulimits to be set in the container

	// Applicable to Windows
	CPUCount           int64  `json:"CpuCount"`   // CPU count
	CPUPercent         int64  `json:"CpuPercent"` // CPU percent
	IOMaximumIOps      uint64 // Maximum IOps for the container system drive
	IOMaximumBandwidth uint64 // Maximum IO in bytes per second for the container system drive
}

type InstanceFields struct {
	ImageUUID          string `json:"imageUuid"`
	PublishAllPorts    bool
	DataVolumes        []string
	Privileged         bool
	ReadOnly           bool
	BlkioDeviceOptions map[string]DeviceOptions
	CommandArgs        []string
	ExtraHosts         []string
	PidMode            container.PidMode
	LogConfig          LogConfig
	SecurityOpt        []string
	Devices            []string
	DNS                []string `json:"dns"`
	DNSSearch          []string `json:"dnsSearch"`
	CapAdd             []string
	CapDrop            []string
	RestartPolicy      container.RestartPolicy
	CPUShares          int64 `json:"cpuShares"`
	VolumeDriver       string
	CPUSet             string
	BlkioWeight        uint16
	CgroupParent       string
	CPUPeriod          int64  `json:"cpuPeriod"`
	CPUQuota           int64  `json:"cpuQuota"`
	CPUsetMems         string `json:"cpuSetMems"`
	DNSOpt             []string
	GroupAdd           []string
	Isolation          container.Isolation
	KernelMemory       int64
	Memory             int64
	MemorySwap         int64
	MemorySwappiness   *int64
	OomKillDisable     *bool
	OomScoreAdj        int
	ShmSize            int64
	Tmpfs              map[string]string
	Ulimits            []*units.Ulimit
	Uts                container.UTSMode
	IpcMode            container.IpcMode
	ConsoleSize        [2]int
	CPUCount           int64
	CPUPercent         int64
	IOMaximumIOps      uint64
	IOMaximumBandwidth uint64
	Command            interface{} // this one is so weird
	Environment        map[string]string
	WorkingDir         string
	EntryPoint         []string
	Tty                bool
	StdinOpen          bool
	DomainName         string
	Labels             map[string]string
	StopSignal         string
	User               string
	Sysctls            map[string]string
	HealthCmd          []string
	HealthTimeout      int
	HealthInterval     int
	HealthRetries      int
	StorageOpt         map[string]string
	PidsLimit          int64
	Cgroup             container.CgroupSpec
	DiskQuota          int64
	UsernsMode         container.UsernsMode
}

type LogConfig struct {
	Driver string
	Config map[string]string
}

type DeviceOptions struct {
	Weight    uint16
	ReadIops  uint64
	WriteIops uint64
	ReadBps   uint64
	WriteBps  uint64
}
<commit_msg>don't use strong type for DockerInspect.State<commit_after>package model

import (
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/blkiodev"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/mount"
	"github.com/docker/docker/api/types/strslice"
	"github.com/docker/go-connections/nat"
	"github.com/docker/go-units"
)

type Instance struct {
	AccountID                   int    `json:"accountId"`
	AllocationState             string `json:"allocationState"`
	Created                     int64  `json:"created"`
	Data                        InstanceFieldsData
	Ports                       []Port
	Description                 string `json:"description"`
	Hostname                    string `json:"hostname"`
	ID                          int    `json:"id"`
	Image                       Image
	ImageID                     int    `json:"imageId"`
	Kind                        string `json:"kind"`
	Name                        string `json:"name"`
	Nics                        []Nic
	Offering                    interface{} `json:"offering"`
	OfferingID                  interface{} `json:"offeringId"`
	OnCrash                     string      `json:"onCrash"`
	PostComputeState            string      `json:"postComputeState"`
	RemoveTime                  interface{} `json:"removeTime"`
	Removed                     interface{} `json:"removed"`
	RequestedOfferingID         interface{} `json:"requestedOfferingId"`
	RequestedState              interface{} `json:"requestedState"`
	State                       string      `json:"state"`
	Type                        string      `json:"type"`
	UUID                        string      `json:"uuid"`
	Volumes                     []Volume
	ZoneID                      int    `json:"zoneId"`
	ExternalID                  string `json:"externalId"`
	AgentID                     int
	InstanceLinks               []Link
	NetworkContainer            *Instance
	NativeContainer             bool
	DataVolumesFromContainers   []*Instance
	CommandArgs                 []string
	Labels                      map[string]interface{}
	ProcessData                 ProcessData
	VolumesFromDataVolumeMounts []Volume
	Token                       string
	MilliCPUReservation         int64
	MemoryReservation           int64
	System                      bool
}

type InstanceFieldsData struct {
	Fields InstanceFields
	IPSec  map[string]struct {
		Nat    float64
		Isakmp float64
	} `json:"ipsec"`
	DockerInspect ContainerJSON `json:"dockerInspect,omitempty" yaml:"dockerInspect,omitempty"`
	Process       ProcessData
}

type ContainerJSON struct {
	ID              string `json:"Id"`
	Created         string
	Path            string
	Args            []string
	State           interface{}
	Image           string
	ResolvConfPath  string
	HostnamePath    string
	HostsPath       string
	LogPath         string
	Node            types.ContainerNode `json:",omitempty"`
	Name            string
	RestartCount    int
	Driver          string
	MountLabel      string
	ProcessLabel    string
	AppArmorProfile string
	ExecIDs         []string
	HostConfig      HostConfig
	GraphDriver     types.GraphDriverData
	SizeRw          int64 `json:",omitempty"`
	SizeRootFs      int64 `json:",omitempty"`
	Mounts          []types.MountPoint
	Config          container.Config
	NetworkSettings types.NetworkSettings
}

type HostConfig struct {
	// Applicable to all platforms
	Binds           []string                // List of volume bindings for this container
	ContainerIDFile string                  // File (path) where the containerId is written
	LogConfig       LogConfig               // Configuration of the logs for this container
	NetworkMode     container.NetworkMode   // Network mode to use for the container
	PortBindings    nat.PortMap             // Port mapping between the exposed port (container) and the host
	RestartPolicy   container.RestartPolicy // Restart policy to be used for the container
	AutoRemove      bool                    // Automatically remove container when it exits
	VolumeDriver    string                  // Name of the volume driver used to mount volumes
	VolumesFrom     []string                // List of volumes to take from other container

	// Applicable to UNIX platforms
	CapAdd          strslice.StrSlice    // List of kernel capabilities to add to the container
	CapDrop         strslice.StrSlice    // List of kernel capabilities to remove from the container
	DNS             []string             `json:"Dns"`        // List of DNS server to lookup
	DNSOptions      []string             `json:"DnsOptions"` // List of DNSOption to look for
	DNSSearch       []string             `json:"DnsSearch"`  // List of DNSSearch to look for
	ExtraHosts      []string             // List of extra hosts
	GroupAdd        []string             // List of additional groups that the container process will run as
	IpcMode         container.IpcMode    // IPC namespace to use for the container
	Cgroup          container.CgroupSpec // Cgroup to use for the container
	Links           []string             // List of links (in the name:alias form)
	OomScoreAdj     int                  // Container preference for OOM-killing
	PidMode         container.PidMode    // PID namespace to use for the container
	Privileged      bool                 // Is the container in privileged mode
	PublishAllPorts bool                 // Should docker publish all exposed port for the container
	ReadonlyRootfs  bool                 // Is the container root filesystem in read-only
	SecurityOpt     []string             // List of string values to customize labels for MLS systems, such as SELinux.
	StorageOpt      map[string]string    `json:",omitempty"` // Storage driver options per container.
	Tmpfs           map[string]string    `json:",omitempty"` // List of tmpfs (mounts) used for the container
	UTSMode         container.UTSMode    // UTS namespace to use for the container
	UsernsMode      container.UsernsMode // The user namespace to use for the container
	ShmSize         int64                // Total shm memory usage
	Sysctls         map[string]string    `json:",omitempty"` // List of Namespaced sysctls used for the container
	Runtime         string               `json:",omitempty"` // Runtime to use with this container

	// Applicable to Windows
	//ConsoleSize [2]int    // Initial console size
	Isolation container.Isolation // Isolation technology of the container (eg default, hyperv)

	// Contains container's resources (cgroups, ulimits)
	Resources

	// Mounts specs used by the container
	Mounts []mount.Mount `json:",omitempty"`
}

type Resources struct {
	// Applicable to all platforms
	CPUShares int64 `json:"CpuShares"` // CPU shares (relative weight vs. other containers)
	Memory    int64 // Memory limit (in bytes)

	// Applicable to UNIX platforms
	CgroupParent         string // Parent cgroup.
	BlkioWeight          uint16 // Block IO weight (relative weight vs. other containers)
	BlkioWeightDevice    []*blkiodev.WeightDevice
	BlkioDeviceReadBps   []*blkiodev.ThrottleDevice
	BlkioDeviceWriteBps  []*blkiodev.ThrottleDevice
	BlkioDeviceReadIOps  []*blkiodev.ThrottleDevice
	BlkioDeviceWriteIOps []*blkiodev.ThrottleDevice
	CPUPeriod            int64                     `json:"CpuPeriod"` // CPU CFS (Completely Fair Scheduler) period
	CPUQuota             int64                     `json:"CpuQuota"`  // CPU CFS (Completely Fair Scheduler) quota
	CpusetCpus           string                    // CpusetCpus 0-2, 0,1
	CpusetMems           string                    // CpusetMems 0-2, 0,1
	Devices              []container.DeviceMapping // List of devices to map inside the container
	DiskQuota            int64                     // Disk limit (in bytes)
	KernelMemory         int64                     // Kernel memory limit (in bytes)
	MemoryReservation    int64                     // Memory soft limit (in bytes)
	MemorySwap           int64                     // Total memory usage (memory + swap); set `-1` to enable unlimited swap
	MemorySwappiness     *int64                    // Tuning container memory swappiness behaviour
	OomKillDisable       *bool                     // Whether to disable OOM Killer or not
	PidsLimit            int64                     // Setting pids limit for a container
	Ulimits              []*units.Ulimit           // List of ulimits to be set in the container

	// Applicable to Windows
	CPUCount           int64  `json:"CpuCount"`   // CPU count
	CPUPercent         int64  `json:"CpuPercent"` // CPU percent
	IOMaximumIOps      uint64 // Maximum IOps for the container system drive
	IOMaximumBandwidth uint64 // Maximum IO in bytes per second for the container system drive
}

type InstanceFields struct {
	ImageUUID          string `json:"imageUuid"`
	PublishAllPorts    bool
	DataVolumes        []string
	Privileged         bool
	ReadOnly           bool
	BlkioDeviceOptions map[string]DeviceOptions
	CommandArgs        []string
	ExtraHosts         []string
	PidMode            container.PidMode
	LogConfig          LogConfig
	SecurityOpt        []string
	Devices            []string
	DNS                []string `json:"dns"`
	DNSSearch          []string `json:"dnsSearch"`
	CapAdd             []string
	CapDrop            []string
	RestartPolicy      container.RestartPolicy
	CPUShares          int64 `json:"cpuShares"`
	VolumeDriver       string
	CPUSet             string
	BlkioWeight        uint16
	CgroupParent       string
	CPUPeriod          int64  `json:"cpuPeriod"`
	CPUQuota           int64  `json:"cpuQuota"`
	CPUsetMems         string `json:"cpuSetMems"`
	DNSOpt             []string
	GroupAdd           []string
	Isolation          container.Isolation
	KernelMemory       int64
	Memory             int64
	MemorySwap         int64
	MemorySwappiness   *int64
	OomKillDisable     *bool
	OomScoreAdj        int
	ShmSize            int64
	Tmpfs              map[string]string
	Ulimits            []*units.Ulimit
	Uts                container.UTSMode
	IpcMode            container.IpcMode
	ConsoleSize        [2]int
	CPUCount           int64
	CPUPercent         int64
	IOMaximumIOps      uint64
	IOMaximumBandwidth uint64
	Command            interface{} // this one is so weird
	Environment        map[string]string
	WorkingDir         string
	EntryPoint         []string
	Tty                bool
	StdinOpen          bool
	DomainName         string
	Labels             map[string]string
	StopSignal         string
	User               string
	Sysctls            map[string]string
	HealthCmd          []string
	HealthTimeout      int
	HealthInterval     int
	HealthRetries      int
	StorageOpt         map[string]string
	PidsLimit          int64
	Cgroup             container.CgroupSpec
	DiskQuota          int64
	UsernsMode         container.UsernsMode
}

type LogConfig struct {
	Driver string
	Config map[string]string
}

type DeviceOptions struct {
	Weight    uint16
	ReadIops  uint64
	WriteIops uint64
	ReadBps   uint64
	WriteBps  uint64
}
<|endoftext|>


<commit_before>package stats

import (
	"fmt"

	"github.com/fsouza/go-dockerclient"
)

type Docker struct {
	sockFile string
}

func NewDocker(f string) *Docker {
	return &Docker{f}
}

func (d *Docker) Start() {
	client, err := docker.NewClient(d.sockFile)
	if err != nil {
		panic(err)
	}
	containers, err := client.ListContainers(docker.ListContainersOptions{All: false})
	if err != nil {
		panic(err)
	}

	for _, c := range containers {
		s := make(chan *docker.Stats)
		go func(id string) {
			go client.Stats(docker.StatsOptions{
				ID:     id,
				Stats:  s,
				Stream: true,
			})
			for {
				st := <-s
				cpuDelta := float64(st.CPUStats.CPUUsage.TotalUsage) - float64(st.PreCPUStats.CPUUsage.TotalUsage)
				sysDelta := float64(st.CPUStats.SystemCPUUsage) - float64(st.PreCPUStats.SystemCPUUsage)
				cpuPercent := (cpuDelta / sysDelta) * float64(len(st.CPUStats.CPUUsage.PercpuUsage)) * 100.0
				memPercent := float64(st.MemoryStats.Usage) / float64(st.MemoryStats.Limit) * 100.0
				fmt.Printf("%s: Mem: %.2f%% CPU: %.2f%%\n", id[:7], memPercent, cpuPercent)
			}
		}(c.ID)
	}
	for {
	}
}
<commit_msg>Remove old file<commit_after><|endoftext|>


<commit_before>package ovs

import (
	"bytes"
	"fmt"
	"strconv"
	"strings"

	"github.com/golang/glog"

	utilversion "k8s.io/kubernetes/pkg/util/version"
	"k8s.io/utils/exec"
)

// Interface represents an interface to OVS
type Interface interface {
	// AddBridge creates the bridge associated with the interface, optionally setting
	// properties on it (as with "ovs-vsctl set Bridge ..."). If the bridge already
	// exists this errors.
	AddBridge(properties ...string) error

	// DeleteBridge deletes the bridge associated with the interface. The boolean
	// that can be passed determines if a bridge not existing is an error. Passing
	// true will delete bridge --if-exists, passing false will error if the bridge
	// does not exist.
	DeleteBridge(ifExists bool) error

	// AddPort adds an interface to the bridge, requesting the indicated port
	// number, and optionally setting properties on it (as with "ovs-vsctl set
	// Interface ..."). Returns the allocated port number (or an error).
	AddPort(port string, ofportRequest int, properties ...string) (int, error)

	// DeletePort removes an interface from the bridge. (It is not an
	// error if the interface is not currently a bridge port.)
	DeletePort(port string) error

	// GetOFPort returns the OpenFlow port number of a given network interface
	// attached to a bridge.
	GetOFPort(port string) (int, error)

	// SetFrags sets the fragmented-packet-handling mode (as with
	// "ovs-ofctl set-frags")
	SetFrags(mode string) error

	// Create creates a record in the OVS database, as with "ovs-vsctl create" and
	// returns the UUID of the newly-created item.
	// NOTE: This only works for QoS; for all other tables the created object will
	// immediately be garbage-collected; we'd need an API that calls "create" and "set"
	// in the same "ovs-vsctl" call.
	Create(table string, values ...string) (string, error)

	// Destroy deletes the indicated record in the OVS database. It is not an error if
	// the record does not exist
	Destroy(table, record string) error

	// Get gets the indicated value from the OVS database. For multi-valued or
	// map-valued columns, the data is returned in the same format as "ovs-vsctl get".
	Get(table, record, column string) (string, error)

	// Set sets one or more columns on a record in the OVS database, as with
	// "ovs-vsctl set"
	Set(table, record string, values ...string) error

	// Clear unsets the indicated columns in the OVS database. It is not an error if
	// the value is already unset
	Clear(table, record string, columns ...string) error

	// Find finds records in the OVS database that match the given condition.
	// It returns the value of the given column of matching records.
	Find(table, column, condition string) ([]string, error)

	// DumpFlows dumps the flow table for the bridge and returns it as an array of
	// strings, one per flow. If flow is not "" then it describes the flows to dump.
	DumpFlows(flow string, args ...interface{}) ([]string, error)

	// NewTransaction begins a new OVS transaction.
	NewTransaction() Transaction
}

// Transaction manages a single set of OVS flow modifications
type Transaction interface {
	// AddFlow prepares adding a flow to the bridge.
	// Given flow is cached but not executed at this time.
	// The arguments are passed to fmt.Sprintf().
	AddFlow(flow string, args ...interface{})

	// DeleteFlows prepares deleting all matching flows from the bridge.
	// Given flow is cached but not executed at this time.
	// The arguments are passed to fmt.Sprintf().
	DeleteFlows(flow string, args ...interface{})

	// Commit executes all cached flows as a single atomic transaction and
	// returns any error that occurred during the transaction.
	Commit() error
}

const (
	OVS_OFCTL = "ovs-ofctl"
	OVS_VSCTL = "ovs-vsctl"
)

// ovsExec implements ovs.Interface via calls to ovs-ofctl and ovs-vsctl
type ovsExec struct {
	execer exec.Interface
	bridge string
}

// New returns a new ovs.Interface
func New(execer exec.Interface, bridge string, minVersion string) (Interface, error) {
	if _, err := execer.LookPath(OVS_OFCTL); err != nil {
		return nil, fmt.Errorf("OVS is not installed")
	}
	if _, err := execer.LookPath(OVS_VSCTL); err != nil {
		return nil, fmt.Errorf("OVS is not installed")
	}

	ovsif := &ovsExec{execer: execer, bridge: bridge}

	if minVersion != "" {
		minVer := utilversion.MustParseGeneric(minVersion)

		out, err := ovsif.exec(OVS_VSCTL, "--version")
		if err != nil {
			return nil, fmt.Errorf("could not check OVS version is %s or higher", minVersion)
		}
		// First output line should end with version
		lines := strings.Split(out, "\n")
		spc := strings.LastIndex(lines[0], " ")
		instVer, err := utilversion.ParseGeneric(lines[0][spc+1:])
		if err != nil {
			return nil, fmt.Errorf("could not find OVS version in %q", lines[0])
		}
		if !instVer.AtLeast(minVer) {
			return nil, fmt.Errorf("found OVS %v, need %s or later", instVer, minVersion)
		}
	}

	return ovsif, nil
}

func (ovsif *ovsExec) execWithStdin(cmd string, stdinArgs []string, args ...string) (string, error) {
	switch cmd {
	case OVS_OFCTL:
		args = append([]string{"-O", "OpenFlow13"}, args...)
	case OVS_VSCTL:
		args = append([]string{"--timeout=30"}, args...)
	}

	kcmd := ovsif.execer.Command(cmd, args...)
	if stdinArgs != nil {
		stdinString := strings.Join(stdinArgs, "\n")
		stdin := bytes.NewBufferString(stdinString)
		kcmd.SetStdin(stdin)

		glog.V(4).Infof("Executing: %s %s <<\n%s", cmd, strings.Join(args, " "), stdinString)
	} else {
		glog.V(4).Infof("Executing: %s %s", cmd, strings.Join(args, " "))
	}

	output, err := kcmd.CombinedOutput()
	if err != nil {
		glog.V(2).Infof("Error executing %s: %s", cmd, string(output))
		return "", err
	}

	outStr := string(output)
	if outStr != "" {
		// If output is a single line, strip the trailing newline
		nl := strings.Index(outStr, "\n")
		if nl == len(outStr)-1 {
			outStr = outStr[:nl]
		}
	}
	return outStr, nil
}

func (ovsif *ovsExec) exec(cmd string, args ...string) (string, error) {
	return ovsif.execWithStdin(cmd, nil, args...)
}

func (ovsif *ovsExec) AddBridge(properties ...string) error {
	args := []string{"add-br", ovsif.bridge}
	if len(properties) > 0 {
		args = append(args, "--", "set", "Bridge", ovsif.bridge)
		args = append(args, properties...)
	}
	_, err := ovsif.exec(OVS_VSCTL, args...)
	return err
}

func (ovsif *ovsExec) DeleteBridge(ifExists bool) error {
	args := []string{"del-br", ovsif.bridge}

	if ifExists {
		args = append([]string{"--if-exists"}, args...)
	}
	_, err := ovsif.exec(OVS_VSCTL, args...)
	return err
}

func (ovsif *ovsExec) GetOFPort(port string) (int, error) {
	ofportStr, err := ovsif.exec(OVS_VSCTL, "get", "Interface", port, "ofport")
	if err != nil {
		return -1, fmt.Errorf("failed to get OVS port for %s: %v", port, err)
	}
	ofport, err := strconv.Atoi(ofportStr)
	if err != nil {
		return -1, fmt.Errorf("could not parse allocated ofport %q: %v", ofportStr, err)
	}
	if ofport == -1 {
		errStr, err := ovsif.exec(OVS_VSCTL, "get", "Interface", port, "error")
		if err != nil || errStr == "" {
			errStr = "unknown error"
		}
		return -1, fmt.Errorf("error on port %s: %s", port, errStr)
	}
	return ofport, nil
}

func (ovsif *ovsExec) AddPort(port string, ofportRequest int, properties ...string) (int, error) {
	args := []string{"--may-exist", "add-port", ovsif.bridge, port}
	if ofportRequest > 0 || len(properties) > 0 {
		args = append(args, "--", "set", "Interface", port)
		if ofportRequest > 0 {
			args = append(args, fmt.Sprintf("ofport_request=%d", ofportRequest))
		}
		if len(properties) > 0 {
			args = append(args, properties...)
		}
	}
	_, err := ovsif.exec(OVS_VSCTL, args...)
	if err != nil {
		return -1, err
	}
	ofport, err := ovsif.GetOFPort(port)
	if err != nil {
		return -1, err
	}
	if ofportRequest > 0 && ofportRequest != ofport {
		return -1, fmt.Errorf("allocated ofport (%d) did not match request (%d)", ofport, ofportRequest)
	}
	return ofport, nil
}

func (ovsif *ovsExec) DeletePort(port string) error {
	_, err := ovsif.exec(OVS_VSCTL, "--if-exists", "del-port", ovsif.bridge, port)
	return err
}

func (ovsif *ovsExec) SetFrags(mode string) error {
	_, err := ovsif.exec(OVS_OFCTL, "set-frags", ovsif.bridge, mode)
	return err
}

func (ovsif *ovsExec) Create(table string, values ...string) (string, error) {
	args := append([]string{"create", table}, values...)
	return ovsif.exec(OVS_VSCTL, args...)
}

func (ovsif *ovsExec) Destroy(table, record string) error {
	_, err := ovsif.exec(OVS_VSCTL, "--if-exists", "destroy", table, record)
	return err
}

func (ovsif *ovsExec) Get(table, record, column string) (string, error) {
	return ovsif.exec(OVS_VSCTL, "get", table, record, column)
}

func (ovsif *ovsExec) Set(table, record string, values ...string) error {
	args := append([]string{"set", table, record}, values...)
	_, err := ovsif.exec(OVS_VSCTL, args...)
	return err
}

// Returns the given column of records that match the condition
func (ovsif *ovsExec) Find(table, column, condition string) ([]string, error) {
	output, err := ovsif.exec(OVS_VSCTL, "--no-heading", "--columns="+column, "find", table, condition)
	if err != nil {
		return nil, err
	}
	values := strings.Split(output, "\n\n")
	// We want "bare" values for strings, but we can't pass --bare to ovs-vsctl because
	// it breaks more complicated types. So try passing each value through Unquote();
	// if it fails, that means the value wasn't a quoted string, so use it as-is.
	for i, val := range values {
		if unquoted, err := strconv.Unquote(val); err == nil {
			values[i] = unquoted
		}
	}
	return values, nil
}

func (ovsif *ovsExec) Clear(table, record string, columns ...string) error {
	args := append([]string{"--if-exists", "clear", table, record}, columns...)
	_, err := ovsif.exec(OVS_VSCTL, args...)
	return err
}

func (ovsif *ovsExec) DumpFlows(flow string, args ...interface{}) ([]string, error) {
	if len(args) > 0 {
		flow = fmt.Sprintf(flow, args...)
	}
	out, err := ovsif.exec(OVS_OFCTL, "dump-flows", ovsif.bridge, flow)
	if err != nil {
		return nil, err
	}

	lines := strings.Split(out, "\n")
	flows := make([]string, 0, len(lines))
	for _, line := range lines {
		if strings.Contains(line, "cookie=") {
			flows = append(flows, line)
		}
	}
	return flows, nil
}

func (ovsif *ovsExec) NewTransaction() Transaction {
	return &ovsExecTx{ovsif: ovsif, flows: []string{}}
}

// bundle executes all given flows as a single atomic transaction
func (ovsif *ovsExec) bundle(flows []string) error {
	if len(flows) == 0 {
		return nil
	}

	_, err := ovsif.execWithStdin(OVS_OFCTL, flows, "bundle", ovsif.bridge, "-")
	return err
}

// ovsExecTx implements ovs.Transaction and maintains current flow context
type ovsExecTx struct {
	ovsif *ovsExec
	flows []string
}

func (tx *ovsExecTx) AddFlow(flow string, args ...interface{}) {
	if len(args) > 0 {
		flow = fmt.Sprintf(flow, args...)
	}
	tx.flows = append(tx.flows, fmt.Sprintf("flow add %s", flow))
}

func (tx *ovsExecTx) DeleteFlows(flow string, args ...interface{}) {
	if len(args) > 0 {
		flow = fmt.Sprintf(flow, args...)
	}
	tx.flows = append(tx.flows, fmt.Sprintf("flow delete %s", flow))
}

func (tx *ovsExecTx) Commit() error {
	err := tx.ovsif.bundle(tx.flows)

	// Reset flow context
	tx.flows = []string{}
	return err
}
<commit_msg>Log ovs dump-flows at 5, not 4<commit_after>package ovs

import (
	"bytes"
	"fmt"
	"strconv"
	"strings"

	"github.com/golang/glog"

	utilversion "k8s.io/kubernetes/pkg/util/version"
	"k8s.io/utils/exec"
)

// Interface represents an interface to OVS
type Interface interface {
	// AddBridge creates the bridge associated with the interface, optionally setting
	// properties on it (as with "ovs-vsctl set Bridge ..."). If the bridge already
	// exists this errors.
	AddBridge(properties ...string) error

	// DeleteBridge deletes the bridge associated with the interface. The boolean
	// that can be passed determines if a bridge not existing is an error. Passing
	// true will delete bridge --if-exists, passing false will error if the bridge
	// does not exist.
	DeleteBridge(ifExists bool) error

	// AddPort adds an interface to the bridge, requesting the indicated port
	// number, and optionally setting properties on it (as with "ovs-vsctl set
	// Interface ..."). Returns the allocated port number (or an error).
	AddPort(port string, ofportRequest int, properties ...string) (int, error)

	// DeletePort removes an interface from the bridge. (It is not an
	// error if the interface is not currently a bridge port.)
	DeletePort(port string) error

	// GetOFPort returns the OpenFlow port number of a given network interface
	// attached to a bridge.
	GetOFPort(port string) (int, error)

	// SetFrags sets the fragmented-packet-handling mode (as with
	// "ovs-ofctl set-frags")
	SetFrags(mode string) error

	// Create creates a record in the OVS database, as with "ovs-vsctl create" and
	// returns the UUID of the newly-created item.
	// NOTE: This only works for QoS; for all other tables the created object will
	// immediately be garbage-collected; we'd need an API that calls "create" and "set"
	// in the same "ovs-vsctl" call.
	Create(table string, values ...string) (string, error)

	// Destroy deletes the indicated record in the OVS database. It is not an error if
	// the record does not exist
	Destroy(table, record string) error

	// Get gets the indicated value from the OVS database. For multi-valued or
	// map-valued columns, the data is returned in the same format as "ovs-vsctl get".
	Get(table, record, column string) (string, error)

	// Set sets one or more columns on a record in the OVS database, as with
	// "ovs-vsctl set"
	Set(table, record string, values ...string) error

	// Clear unsets the indicated columns in the OVS database. It is not an error if
	// the value is already unset
	Clear(table, record string, columns ...string) error

	// Find finds records in the OVS database that match the given condition.
	// It returns the value of the given column of matching records.
	Find(table, column, condition string) ([]string, error)

	// DumpFlows dumps the flow table for the bridge and returns it as an array of
	// strings, one per flow. If flow is not "" then it describes the flows to dump.
	DumpFlows(flow string, args ...interface{}) ([]string, error)

	// NewTransaction begins a new OVS transaction.
	NewTransaction() Transaction
}

// Transaction manages a single set of OVS flow modifications
type Transaction interface {
	// AddFlow prepares adding a flow to the bridge.
	// Given flow is cached but not executed at this time.
	// The arguments are passed to fmt.Sprintf().
	AddFlow(flow string, args ...interface{})

	// DeleteFlows prepares deleting all matching flows from the bridge.
	// Given flow is cached but not executed at this time.
	// The arguments are passed to fmt.Sprintf().
	DeleteFlows(flow string, args ...interface{})

	// Commit executes all cached flows as a single atomic transaction and
	// returns any error that occurred during the transaction.
	Commit() error
}

const (
	OVS_OFCTL = "ovs-ofctl"
	OVS_VSCTL = "ovs-vsctl"
)

// ovsExec implements ovs.Interface via calls to ovs-ofctl and ovs-vsctl
type ovsExec struct {
	execer exec.Interface
	bridge string
}

// New returns a new ovs.Interface
func New(execer exec.Interface, bridge string, minVersion string) (Interface, error) {
	if _, err := execer.LookPath(OVS_OFCTL); err != nil {
		return nil, fmt.Errorf("OVS is not installed")
	}
	if _, err := execer.LookPath(OVS_VSCTL); err != nil {
		return nil, fmt.Errorf("OVS is not installed")
	}

	ovsif := &ovsExec{execer: execer, bridge: bridge}

	if minVersion != "" {
		minVer := utilversion.MustParseGeneric(minVersion)

		out, err := ovsif.exec(OVS_VSCTL, "--version")
		if err != nil {
			return nil, fmt.Errorf("could not check OVS version is %s or higher", minVersion)
		}
		// First output line should end with version
		lines := strings.Split(out, "\n")
		spc := strings.LastIndex(lines[0], " ")
		instVer, err := utilversion.ParseGeneric(lines[0][spc+1:])
		if err != nil {
			return nil, fmt.Errorf("could not find OVS version in %q", lines[0])
		}
		if !instVer.AtLeast(minVer) {
			return nil, fmt.Errorf("found OVS %v, need %s or later", instVer, minVersion)
		}
	}

	return ovsif, nil
}

func (ovsif *ovsExec) execWithStdin(cmd string, stdinArgs []string, args ...string) (string, error) {
	logLevel := glog.Level(4)
	switch cmd {
	case OVS_OFCTL:
		if args[0] == "dump-flows" {
			logLevel = glog.Level(5)
		}
		args = append([]string{"-O", "OpenFlow13"}, args...)
	case OVS_VSCTL:
		args = append([]string{"--timeout=30"}, args...)
	}

	kcmd := ovsif.execer.Command(cmd, args...)
	if stdinArgs != nil {
		stdinString := strings.Join(stdinArgs, "\n")
		stdin := bytes.NewBufferString(stdinString)
		kcmd.SetStdin(stdin)

		glog.V(logLevel).Infof("Executing: %s %s <<\n%s", cmd, strings.Join(args, " "), stdinString)
	} else {
		glog.V(logLevel).Infof("Executing: %s %s", cmd, strings.Join(args, " "))
	}

	output, err := kcmd.CombinedOutput()
	if err != nil {
		glog.V(2).Infof("Error executing %s: %s", cmd, string(output))
		return "", err
	}

	outStr := string(output)
	if outStr != "" {
		// If output is a single line, strip the trailing newline
		nl := strings.Index(outStr, "\n")
		if nl == len(outStr)-1 {
			outStr = outStr[:nl]
		}
	}
	return outStr, nil
}

func (ovsif *ovsExec) exec(cmd string, args ...string) (string, error) {
	return ovsif.execWithStdin(cmd, nil, args...)
}

func (ovsif *ovsExec) AddBridge(properties ...string) error {
	args := []string{"add-br", ovsif.bridge}
	if len(properties) > 0 {
		args = append(args, "--", "set", "Bridge", ovsif.bridge)
		args = append(args, properties...)
	}
	_, err := ovsif.exec(OVS_VSCTL, args...)
	return err
}

func (ovsif *ovsExec) DeleteBridge(ifExists bool) error {
	args := []string{"del-br", ovsif.bridge}

	if ifExists {
		args = append([]string{"--if-exists"}, args...)
	}
	_, err := ovsif.exec(OVS_VSCTL, args...)
	return err
}

func (ovsif *ovsExec) GetOFPort(port string) (int, error) {
	ofportStr, err := ovsif.exec(OVS_VSCTL, "get", "Interface", port, "ofport")
	if err != nil {
		return -1, fmt.Errorf("failed to get OVS port for %s: %v", port, err)
	}
	ofport, err := strconv.Atoi(ofportStr)
	if err != nil {
		return -1, fmt.Errorf("could not parse allocated ofport %q: %v", ofportStr, err)
	}
	if ofport == -1 {
		errStr, err := ovsif.exec(OVS_VSCTL, "get", "Interface", port, "error")
		if err != nil || errStr == "" {
			errStr = "unknown error"
		}
		return -1, fmt.Errorf("error on port %s: %s", port, errStr)
	}
	return ofport, nil
}

func (ovsif *ovsExec) AddPort(port string, ofportRequest int, properties ...string) (int, error) {
	args := []string{"--may-exist", "add-port", ovsif.bridge, port}
	if ofportRequest > 0 || len(properties) > 0 {
		args = append(args, "--", "set", "Interface", port)
		if ofportRequest > 0 {
			args = append(args, fmt.Sprintf("ofport_request=%d", ofportRequest))
		}
		if len(properties) > 0 {
			args = append(args, properties...)
		}
	}
	_, err := ovsif.exec(OVS_VSCTL, args...)
	if err != nil {
		return -1, err
	}
	ofport, err := ovsif.GetOFPort(port)
	if err != nil {
		return -1, err
	}
	if ofportRequest > 0 && ofportRequest != ofport {
		return -1, fmt.Errorf("allocated ofport (%d) did not match request (%d)", ofport, ofportRequest)
	}
	return ofport, nil
}

func (ovsif *ovsExec) DeletePort(port string) error {
	_, err := ovsif.exec(OVS_VSCTL, "--if-exists", "del-port", ovsif.bridge, port)
	return err
}

func (ovsif *ovsExec) SetFrags(mode string) error {
	_, err := ovsif.exec(OVS_OFCTL, "set-frags", ovsif.bridge, mode)
	return err
}

func (ovsif *ovsExec) Create(table string, values ...string) (string, error) {
	args := append([]string{"create", table}, values...)
	return ovsif.exec(OVS_VSCTL, args...)
}

func (ovsif *ovsExec) Destroy(table, record string) error {
	_, err := ovsif.exec(OVS_VSCTL, "--if-exists", "destroy", table, record)
	return err
}

func (ovsif *ovsExec) Get(table, record, column string) (string, error) {
	return ovsif.exec(OVS_VSCTL, "get", table, record, column)
}

func (ovsif *ovsExec) Set(table, record string, values ...string) error {
	args := append([]string{"set", table, record}, values...)
	_, err := ovsif.exec(OVS_VSCTL, args...)
	return err
}

// Returns the given column of records that match the condition
func (ovsif *ovsExec) Find(table, column, condition string) ([]string, error) {
	output, err := ovsif.exec(OVS_VSCTL, "--no-heading", "--columns="+column, "find", table, condition)
	if err != nil {
		return nil, err
	}
	values := strings.Split(output, "\n\n")
	// We want "bare" values for strings, but we can't pass --bare to ovs-vsctl because
	// it breaks more complicated types. So try passing each value through Unquote();
	// if it fails, that means the value wasn't a quoted string, so use it as-is.
	for i, val := range values {
		if unquoted, err := strconv.Unquote(val); err == nil {
			values[i] = unquoted
		}
	}
	return values, nil
}

func (ovsif *ovsExec) Clear(table, record string, columns ...string) error {
	args := append([]string{"--if-exists", "clear", table, record}, columns...)
	_, err := ovsif.exec(OVS_VSCTL, args...)
	return err
}

func (ovsif *ovsExec) DumpFlows(flow string, args ...interface{}) ([]string, error) {
	if len(args) > 0 {
		flow = fmt.Sprintf(flow, args...)
	}
	out, err := ovsif.exec(OVS_OFCTL, "dump-flows", ovsif.bridge, flow)
	if err != nil {
		return nil, err
	}

	lines := strings.Split(out, "\n")
	flows := make([]string, 0, len(lines))
	for _, line := range lines {
		if strings.Contains(line, "cookie=") {
			flows = append(flows, line)
		}
	}
	return flows, nil
}

func (ovsif *ovsExec) NewTransaction() Transaction {
	return &ovsExecTx{ovsif: ovsif, flows: []string{}}
}

// bundle executes all given flows as a single atomic transaction
func (ovsif *ovsExec) bundle(flows []string) error {
	if len(flows) == 0 {
		return nil
	}

	_, err := ovsif.execWithStdin(OVS_OFCTL, flows, "bundle", ovsif.bridge, "-")
	return err
}

// ovsExecTx implements ovs.Transaction and maintains current flow context
type ovsExecTx struct {
	ovsif *ovsExec
	flows []string
}

func (tx *ovsExecTx) AddFlow(flow string, args ...interface{}) {
	if len(args) > 0 {
		flow = fmt.Sprintf(flow, args...)
	}
	tx.flows = append(tx.flows, fmt.Sprintf("flow add %s", flow))
}

func (tx *ovsExecTx) DeleteFlows(flow string, args ...interface{}) {
	if len(args) > 0 {
		flow = fmt.Sprintf(flow, args...)
	}
	tx.flows = append(tx.flows, fmt.Sprintf("flow delete %s", flow))
}

func (tx *ovsExecTx) Commit() error {
	err := tx.ovsif.bundle(tx.flows)

	// Reset flow context
	tx.flows = []string{}
	return err
}
<|endoftext|>


<commit_before>package util

import (
	"fmt"
	"time"
)

// TimeoutError is error returned after timeout occured.
type TimeoutError struct {
	after time.Duration
}

// Error implements the Go error interface.
func (t *TimeoutError) Error() string {
	return fmt.Sprintf("calling the function timeout after %v", t.after)
}

// TimeoutAfter executes the provide function and return the TimeoutError in
// case when the execution time of the provided function is bigger than provided
// time duration.
func TimeoutAfter(t time.Duration, fn func() error) error {
	c := make(chan error, 1)
	go func() { defer close(c); c <- fn() }()
	select {
	case err := <-c:
		return err
	case <-time.After(t):
		return &TimeoutError{after: t}
	}
}

// IsTimeoutError checks if the provided error is timeout.
func IsTimeoutError(e error) bool {
	_, ok := e.(*TimeoutError)
	return ok
}
<commit_msg>Revert "Fix potential panic in TimeoutAfter"<commit_after>package util

import (
	"fmt"
	"time"
)

// TimeoutError is error returned after timeout occured.
type TimeoutError struct {
	after time.Duration
}

// Error implements the Go error interface.
func (t *TimeoutError) Error() string {
	return fmt.Sprintf("calling the function timeout after %v", t.after)
}

// TimeoutAfter executes the provide function and return the TimeoutError in
// case when the execution time of the provided function is bigger than provided
// time duration.
func TimeoutAfter(t time.Duration, fn func() error) error {
	c := make(chan error, 1)
	defer close(c)
	go func() { c <- fn() }()
	select {
	case err := <-c:
		return err
	case <-time.After(t):
		return &TimeoutError{after: t}
	}
}

// IsTimeoutError checks if the provided error is timeout.
func IsTimeoutError(e error) bool {
	_, ok := e.(*TimeoutError)
	return ok
}
<|endoftext|>


<commit_before>/*
	Go Language Raspberry Pi Interface
	(c) Copyright David Thorpe 2016
	All Rights Reserved

	For Licensing and Usage information, please see LICENSE.md
*/
package linux /* import "github.com/djthorpe/gopi/device/linux" */

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"
	"syscall"
	"unsafe"
)

import (
	gopi "github.com/djthorpe/gopi"
	hw "github.com/djthorpe/gopi/hw"
	util "github.com/djthorpe/gopi/util"
)

////////////////////////////////////////////////////////////////////////////////
// CGO INTERFACE

/*
 #include <linux/input.h>
 static int _EVIOCGNAME(int len)        { return EVIOCGNAME(len); }
 static int _EVIOCGPHYS(int len)        { return EVIOCGPHYS(len); }
 static int _EVIOCGUNIQ(int len)        { return EVIOCGUNIQ(len); }
 static int _EVIOCGPROP(int len)        { return EVIOCGPROP(len); }
 static int _EVIOCGKEY(int len)         { return EVIOCGKEY(len); }
 static int _EVIOCGLED(int len)         { return EVIOCGLED(len); }
 static int _EVIOCGSND(int len)         { return EVIOCGSND(len); }
 static int _EVIOCGSW(int len)          { return EVIOCGSW(len); }
 static int _EVIOCGBIT(int ev, int len) { return EVIOCGBIT(ev, len); }
 static int _EVIOCGABS(int abs)         { return EVIOCGABS(abs); }
 static int _EVIOCSABS(int abs)         { return EVIOCSABS(abs); }
*/
import "C"

////////////////////////////////////////////////////////////////////////////////
// TYPES

// Empty input configuration
type Input struct{}

// Driver of multiple input devices
type InputDriver struct {
	log     *util.LoggerDevice // logger
	devices []hw.InputDevice   // input devices
}

// A single input device
type InputDevice struct {
	// The name of the input device
	Name string

	// The device path to the input device
	Path string

	// The Id of the input device
	Id string

	// The type of device, or NONE
	Type hw.InputDeviceType

	// The bus which the device is attached to, or NONE
	Bus hw.InputDeviceBus

	// Product and version
	Vendor uint16
	Product uint16
	Version uint16

	// Capabilities
	Events []evType

	// Handle to the device
	handle *os.File
}

type evType uint16

////////////////////////////////////////////////////////////////////////////////
// CONSTANTS

// Internal constants
const (
	PATH_INPUT_DEVICES   = "/sys/class/input/event*"
	MAX_POLL_EVENTS      = 32
	MAX_EVENT_SIZE_BYTES = 1024
	MAX_IOCTL_SIZE_BYTES = 256
)

// Event types
// See https://www.kernel.org/doc/Documentation/input/event-codes.txt
const (
	EV_SYN       evType = 0x0000 // Used as markers to separate events
	EV_KEY       evType = 0x0001 // Used to describe state changes of keyboards, buttons
	EV_REL       evType = 0x0002 // Used to describe relative axis value changes
	EV_ABS       evType = 0x0003 // Used to describe absolute axis value changes
	EV_MSC       evType = 0x0004 // Miscellaneous uses that didn't fit anywhere else
	EV_SW        evType = 0x0005 // Used to describe binary state input switches
	EV_LED       evType = 0x0011 // Used to turn LEDs on devices on and off
	EV_SND       evType = 0x0012 // Sound output, such as buzzers
	EV_REP       evType = 0x0014 // Enables autorepeat of keys in the input core
	EV_FF        evType = 0x0015 // Sends force-feedback effects to a device
	EV_PWR       evType = 0x0016 // Power management events
	EV_FF_STATUS evType = 0x0017 // Device reporting of force-feedback effects back to the host
	EV_MAX       evType = 0x001F
)

var (
	EVIOCGNAME = uintptr(C._EVIOCGNAME(MAX_IOCTL_SIZE_BYTES)) // get device name
	EVIOCGPHYS = uintptr(C._EVIOCGPHYS(MAX_IOCTL_SIZE_BYTES)) // get physical location
	EVIOCGUNIQ = uintptr(C._EVIOCGUNIQ(MAX_IOCTL_SIZE_BYTES)) // get unique identifier
	EVIOCGPROP = uintptr(C._EVIOCGPROP(MAX_IOCTL_SIZE_BYTES)) // get device properties
	EVIOCGID   = uintptr(C.EVIOCGID)                          // get device ID
)

////////////////////////////////////////////////////////////////////////////////
// InputDriver OPEN AND CLOSE

// Create new Input object, returns error if not possible
func (config Input) Open(log *util.LoggerDevice) (gopi.Driver, error) {
	log.Debug("<linux.Input>Open")

	// create new GPIO driver
	this := new(InputDriver)

	// Set logging & device
	this.log = log

	// Find devices
	this.devices = make([]hw.InputDevice, 0)
	if err := evFind(func(device *InputDevice) {
		this.devices = append(this.devices, device)
	}); err != nil {
		return nil, err
	}

	// Get capabilities for devices
	for _, device := range this.devices {
		err := device.(*InputDevice).Open()
		defer device.(*InputDevice).Close()
		if err == nil {
			err = device.(*InputDevice).evSetCapabilities()
		}
		if err != nil {
			log.Warn("Device %v: %v",device.GetName(),err)
		}
	}

	// success
	return this, nil
}

// Close Input driver
func (this *InputDriver) Close() error {
	this.log.Debug("<linux.Input>Close")

	for _, device := range this.devices {
		if err := device.Close(); err != nil {
			return err
		}
	}

	return nil
}

func (t evType) String() string {
	switch(t) {
	case EV_SYN:
		return "EV_SYN"
	case EV_KEY:
		return "EV_KEY"
	case EV_REL:
		return "EV_REL"
	case EV_ABS:
		return "EV_ABS"
	case EV_MSC:
		return "EV_MSC"
	case EV_SW:
		return "EV_SW"
	case EV_LED:
		return "EV_LED"
	case EV_SND:
		return "EV_SND"
	case EV_REP:
		return "EV_REP"
	case EV_FF:
		return "EV_FF"
	case EV_PWR:
		return "EV_PWR"
	case EV_FF_STATUS:
		return "EV_FF_STATUS"
	default:
		return "[?? Unknown evType value]"
	}
}

////////////////////////////////////////////////////////////////////////////////
// InputDevice OPEN AND CLOSE

// Open driver
func (this *InputDevice) Open() error {
	if this.handle != nil {
		if err := this.Close(); err != nil {
			return err
		}
	}
	var err error
	if this.handle, err = os.OpenFile(this.Path, os.O_RDWR, 0); err != nil {
		this.handle = nil
		return err
	}
	// Success
	return nil
}

// Close driver
func (this *InputDevice) Close() error {
	var err error
	if this.handle != nil {
		err = this.handle.Close()
	}
	this.handle = nil
	return err
}

////////////////////////////////////////////////////////////////////////////////
// InputDevice implementation

func (this *InputDevice) GetName() string {
	return this.Name
}

func (this *InputDevice) GetType() hw.InputDeviceType {
	return this.Type
}

func (this *InputDevice) GetBus() hw.InputDeviceBus {
	return this.Bus
}

////////////////////////////////////////////////////////////////////////////////
// STRINGIFY

// Strinfigy InputDriver object
func (this *InputDriver) String() string {
	return fmt.Sprintf("<linux.Input>{ devices=%v }", this.devices)
}

// Strinfigy InputDevice object
func (this *InputDevice) String() string {
	return fmt.Sprintf("<linux.InputDevice>{ name=\"%s\" path=%s id=%v type=%v bus=%v product=0x%04X vendor=0x%04X version=0x%04X events=%v fd=%v }", this.Name, this.Path, this.Id, this.Type, this.Bus, this.Product, this.Vendor, this.Version, this.Events, this.handle)
}

////////////////////////////////////////////////////////////////////////////////
// PRIVATE METHODS

func (this *InputDevice) evSetCapabilities() error {
	name, err := evGetName(this.handle)
	if err != nil {
		return err
	}
	this.Name = name

	id, err := evGetPhys(this.handle)
	// Error is ignored
	if err == nil {
		this.Id = id
	}

	bus, vendor, product, version, err := evGetInfo(this.handle)
	if err == nil {
		// Error is ignored
		this.Bus = hw.InputDeviceBus(bus)
		this.Vendor = vendor
		this.Product = product
		this.Version = version
	}

	events, err := evGetEvents(this.handle)
	if err != nil {
		return err
	}
	this.Events = events

	return nil
}

// Find all input devices
func evFind(callback func(driver *InputDevice)) error {
	files, err := filepath.Glob(PATH_INPUT_DEVICES)
	if err != nil {
		return err
	}
	for _, file := range files {
		buf, err := ioutil.ReadFile(path.Join(file, "device", "name"))
		if err != nil {
			continue
		}
		device := &InputDevice{Name: strings.TrimSpace(string(buf)), Path: path.Join("/", "dev", "input", path.Base(file))}
		callback(device)
	}
	return nil
}

// Get name
func evGetName(handle *os.File) (string, error) {
	name := new([MAX_IOCTL_SIZE_BYTES]C.char)
	err := evIoctl(handle.Fd(), uintptr(EVIOCGNAME), unsafe.Pointer(name))
	if err != 0 {
		return "", err
	}
	return C.GoString(&name[0]), nil
}

// Get physical connection string
func evGetPhys(handle *os.File) (string, error) {
	name := new([MAX_IOCTL_SIZE_BYTES]C.char)
	err := evIoctl(handle.Fd(), uintptr(EVIOCGPHYS), unsafe.Pointer(name))
	if err != 0 {
		return "", err
	}
	return C.GoString(&name[0]), nil
}

// Get device information (bus, vendor, product, version)
func evGetInfo(handle *os.File) (uint16,uint16,uint16,uint16,error) {
	info := [4]uint16{ }
	err := evIoctl(handle.Fd(), uintptr(EVIOCGID), unsafe.Pointer(&info))
	if err != 0 {
		return uint16(0),uint16(0),uint16(0),uint16(0),err
	}
	return info[0],info[1],info[2],info[3],nil
}

// Get supported events
func evGetEvents(handle *os.File) ([]evType,error) {
	evbits := new([EV_MAX >> 3]byte)
	err := evIoctl(handle.Fd(),uintptr(C._EVIOCGBIT(C.int(0), C.int(EV_MAX))), unsafe.Pointer(evbits))
	if err != 0 {
		return nil,err
	}
	capabilities := make([]evType,0)
	evtype := evType(0)
	for i := 0; i < len(evbits); i++ {
		evbyte := evbits[i]
		for j := 0; j < 8; j++ {
			if evbyte & 0x01 != 0x00 {
				capabilities = append(capabilities,evtype)
			}
			evbyte = evbyte >> 1
			evtype++
		}
	}
	return capabilities,nil
}

// Call ioctl
func evIoctl(fd uintptr, name uintptr, data unsafe.Pointer) syscall.Errno {
	_, _, err := syscall.RawSyscall(syscall.SYS_IOCTL, fd, name, uintptr(data))
	return err
}

<commit_msg>Updated input drivers<commit_after>/*
	Go Language Raspberry Pi Interface
	(c) Copyright David Thorpe 2016
	All Rights Reserved

	For Licensing and Usage information, please see LICENSE.md
*/
package linux /* import "github.com/djthorpe/gopi/device/linux" */

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"
	"syscall"
	"unsafe"
)

import (
	gopi "github.com/djthorpe/gopi"
	hw "github.com/djthorpe/gopi/hw"
	util "github.com/djthorpe/gopi/util"
)

////////////////////////////////////////////////////////////////////////////////
// CGO INTERFACE

/*
 #include <linux/input.h>
 static int _EVIOCGNAME(int len)        { return EVIOCGNAME(len); }
 static int _EVIOCGPHYS(int len)        { return EVIOCGPHYS(len); }
 static int _EVIOCGUNIQ(int len)        { return EVIOCGUNIQ(len); }
 static int _EVIOCGPROP(int len)        { return EVIOCGPROP(len); }
 static int _EVIOCGKEY(int len)         { return EVIOCGKEY(len); }
 static int _EVIOCGLED(int len)         { return EVIOCGLED(len); }
 static int _EVIOCGSND(int len)         { return EVIOCGSND(len); }
 static int _EVIOCGSW(int len)          { return EVIOCGSW(len); }
 static int _EVIOCGBIT(int ev, int len) { return EVIOCGBIT(ev, len); }
 static int _EVIOCGABS(int abs)         { return EVIOCGABS(abs); }
 static int _EVIOCSABS(int abs)         { return EVIOCSABS(abs); }
*/
import "C"

////////////////////////////////////////////////////////////////////////////////
// TYPES

// Empty input configuration
type Input struct{}

// Driver of multiple input devices
type InputDriver struct {
	log     *util.LoggerDevice // logger
	devices []hw.InputDevice   // input devices
}

// A single input device
type InputDevice struct {
	// The name of the input device
	Name string

	// The device path to the input device
	Path string

	// The Id of the input device
	Id string

	// The type of device, or NONE
	Type hw.InputDeviceType

	// The bus which the device is attached to, or NONE
	Bus hw.InputDeviceBus

	// Product and version
	Vendor uint16
	Product uint16
	Version uint16

	// Capabilities
	Events []evType

	// Handle to the device
	handle *os.File
}

type evType uint16

////////////////////////////////////////////////////////////////////////////////
// CONSTANTS

// Internal constants
const (
	PATH_INPUT_DEVICES   = "/sys/class/input/event*"
	MAX_POLL_EVENTS      = 32
	MAX_EVENT_SIZE_BYTES = 1024
	MAX_IOCTL_SIZE_BYTES = 256
)

// Event types
// See https://www.kernel.org/doc/Documentation/input/event-codes.txt
const (
	EV_SYN       evType = 0x0000 // Used as markers to separate events
	EV_KEY       evType = 0x0001 // Used to describe state changes of keyboards, buttons
	EV_REL       evType = 0x0002 // Used to describe relative axis value changes
	EV_ABS       evType = 0x0003 // Used to describe absolute axis value changes
	EV_MSC       evType = 0x0004 // Miscellaneous uses that didn't fit anywhere else
	EV_SW        evType = 0x0005 // Used to describe binary state input switches
	EV_LED       evType = 0x0011 // Used to turn LEDs on devices on and off
	EV_SND       evType = 0x0012 // Sound output, such as buzzers
	EV_REP       evType = 0x0014 // Enables autorepeat of keys in the input core
	EV_FF        evType = 0x0015 // Sends force-feedback effects to a device
	EV_PWR       evType = 0x0016 // Power management events
	EV_FF_STATUS evType = 0x0017 // Device reporting of force-feedback effects back to the host
	EV_MAX       evType = 0x001F
)

var (
	EVIOCGNAME = uintptr(C._EVIOCGNAME(MAX_IOCTL_SIZE_BYTES)) // get device name
	EVIOCGPHYS = uintptr(C._EVIOCGPHYS(MAX_IOCTL_SIZE_BYTES)) // get physical location
	EVIOCGUNIQ = uintptr(C._EVIOCGUNIQ(MAX_IOCTL_SIZE_BYTES)) // get unique identifier
	EVIOCGPROP = uintptr(C._EVIOCGPROP(MAX_IOCTL_SIZE_BYTES)) // get device properties
	EVIOCGID   = uintptr(C.EVIOCGID)                          // get device ID
)

////////////////////////////////////////////////////////////////////////////////
// InputDriver OPEN AND CLOSE

// Create new Input object, returns error if not possible
func (config Input) Open(log *util.LoggerDevice) (gopi.Driver, error) {
	log.Debug("<linux.Input>Open")

	// create new GPIO driver
	this := new(InputDriver)

	// Set logging & device
	this.log = log

	// Find devices
	this.devices = make([]hw.InputDevice, 0)
	if err := evFind(func(device *InputDevice) {
		this.devices = append(this.devices, device)
	}); err != nil {
		return nil, err
	}

	// Get capabilities for devices
	for _, device := range this.devices {
		err := device.(*InputDevice).Open()
		defer device.(*InputDevice).Close()
		if err == nil {
			err = device.(*InputDevice).evSetCapabilities()
		}
		if err != nil {
			log.Warn("Device %v: %v",device.GetName(),err)
		}
	}

	// success
	return this, nil
}

// Close Input driver
func (this *InputDriver) Close() error {
	this.log.Debug("<linux.Input>Close")

	for _, device := range this.devices {
		if err := device.Close(); err != nil {
			return err
		}
	}

	return nil
}

func (t evType) String() string {
	switch(t) {
	case EV_SYN:
		return "EV_SYN"
	case EV_KEY:
		return "EV_KEY"
	case EV_REL:
		return "EV_REL"
	case EV_ABS:
		return "EV_ABS"
	case EV_MSC:
		return "EV_MSC"
	case EV_SW:
		return "EV_SW"
	case EV_LED:
		return "EV_LED"
	case EV_SND:
		return "EV_SND"
	case EV_REP:
		return "EV_REP"
	case EV_FF:
		return "EV_FF"
	case EV_PWR:
		return "EV_PWR"
	case EV_FF_STATUS:
		return "EV_FF_STATUS"
	default:
		return "[?? Unknown evType value]"
	}
}

////////////////////////////////////////////////////////////////////////////////
// InputDevice OPEN AND CLOSE

// Open driver
func (this *InputDevice) Open() error {
	if this.handle != nil {
		if err := this.Close(); err != nil {
			return err
		}
	}
	var err error
	if this.handle, err = os.OpenFile(this.Path, os.O_RDWR, 0); err != nil {
		this.handle = nil
		return err
	}
	// Success
	return nil
}

// Close driver
func (this *InputDevice) Close() error {
	var err error
	if this.handle != nil {
		err = this.handle.Close()
	}
	this.handle = nil
	return err
}

////////////////////////////////////////////////////////////////////////////////
// InputDevice implementation

func (this *InputDevice) GetName() string {
	return this.Name
}

func (this *InputDevice) GetType() hw.InputDeviceType {
	return this.Type
}

func (this *InputDevice) GetBus() hw.InputDeviceBus {
	return this.Bus
}

////////////////////////////////////////////////////////////////////////////////
// STRINGIFY

// Strinfigy InputDriver object
func (this *InputDriver) String() string {
	return fmt.Sprintf("<linux.Input>{ devices=%v }", this.devices)
}

// Strinfigy InputDevice object
func (this *InputDevice) String() string {
	return fmt.Sprintf("<linux.InputDevice>{ name=\"%s\" path=%s id=%v type=%v bus=%v product=0x%04X vendor=0x%04X version=0x%04X events=%v fd=%v }", this.Name, this.Path, this.Id, this.Type, this.Bus, this.Product, this.Vendor, this.Version, this.Events, this.handle)
}

////////////////////////////////////////////////////////////////////////////////
// PRIVATE METHODS

func (this *InputDevice) evSetCapabilities() error {
	name, err := evGetName(this.handle)
	if err != nil {
		return err
	}
	this.Name = name

	id, err := evGetPhys(this.handle)
	// Error is ignored
	if err == nil {
		this.Id = id
	}

	bus, vendor, product, version, err := evGetInfo(this.handle)
	if err == nil {
		// Error is ignored
		this.Bus = hw.InputDeviceBus(bus)
		this.Vendor = vendor
		this.Product = product
		this.Version = version
	}

	events, err := evGetEvents(this.handle)
	if err != nil {
		return err
	}
	this.Events = events

	return nil
}

// Find all input devices
func evFind(callback func(driver *InputDevice)) error {
	files, err := filepath.Glob(PATH_INPUT_DEVICES)
	if err != nil {
		return err
	}
	for _, file := range files {
		buf, err := ioutil.ReadFile(path.Join(file, "device", "name"))
		if err != nil {
			continue
		}
		device := &InputDevice{Name: strings.TrimSpace(string(buf)), Path: path.Join("/", "dev", "input", path.Base(file))}
		callback(device)
	}
	return nil
}

// Get name
func evGetName(handle *os.File) (string, error) {
	name := new([MAX_IOCTL_SIZE_BYTES]C.char)
	err := evIoctl(handle.Fd(), uintptr(EVIOCGNAME), unsafe.Pointer(name))
	if err != 0 {
		return "", err
	}
	return C.GoString(&name[0]), nil
}

// Get physical connection string
func evGetPhys(handle *os.File) (string, error) {
	name := new([MAX_IOCTL_SIZE_BYTES]C.char)
	err := evIoctl(handle.Fd(), uintptr(EVIOCGPHYS), unsafe.Pointer(name))
	if err != 0 {
		return "", err
	}
	return C.GoString(&name[0]), nil
}

// Get device information (bus, vendor, product, version)
func evGetInfo(handle *os.File) (uint16,uint16,uint16,uint16,error) {
	info := [4]uint16{ }
	err := evIoctl(handle.Fd(), uintptr(EVIOCGID), unsafe.Pointer(&info))
	if err != 0 {
		return uint16(0),uint16(0),uint16(0),uint16(0),err
	}
	return info[0],info[1],info[2],info[3],nil
}

// Get supported events
func evGetEvents(handle *os.File) ([]evType,error) {
	evbits := new([EV_MAX >> 3]byte)
	err := evIoctl(handle.Fd(),uintptr(C._EVIOCGBIT(C.int(0), C.int(EV_MAX))), unsafe.Pointer(evbits))
	if err != 0 {
		return nil,err
	}
	capabilities := make([]evType,0)
	evtype := evType(0)
	for i := 0; i < len(evbits); i++ {
		evbyte := evbits[i]
		for j := 0; j < 8; j++ {
			if evbyte & 0x01 != 0x00 {
				capabilities = append(capabilities,evtype)
			}
			evbyte = evbyte >> 1
			evtype++
		}
	}
	return capabilities,nil
}

// Call ioctl
func evIoctl(fd uintptr, name uintptr, data unsafe.Pointer) syscall.Errno {
	_, _, err := syscall.RawSyscall(syscall.SYS_IOCTL, fd, name, uintptr(data))
	return err
}

<|endoftext|>


<commit_before>package playtak

import (
	"errors"
	"strings"
)

type Commands struct {
	User string
	Client
}

func (c *Commands) SendClient(name string) {
	c.SendCommand("client", name)
}

func (c *Commands) Login(user, pass string) error {
	for line := range c.Recv() {
		if strings.HasPrefix(line, "Login ") {
			break
		}
	}
	if pass == "" {
		c.SendCommand("Login", user)
	} else {
		c.SendCommand("Login", user, pass)
	}
	for line := range c.Recv() {
		if line == "Authentication failure" {
			return errors.New("bad username or password")
		}
		if strings.HasPrefix(line, "Welcome ") {
			c.User = user
			return nil
		}
	}
	return errors.New("login failed")
}

func (c *Commands) LoginGuest() error {
	return c.Login("Guest", "")
}

func (c *Commands) Shout(room, msg string) {
	if room == "" {
		c.SendCommand("Shout", msg)
	} else {
		c.SendCommand("ShoutRoom", room, msg)
	}
}

func (c *Commands) Tell(who, msg string) {
	c.SendCommand("Tell", who, msg)
}
<commit_msg>fix the Client command<commit_after>package playtak

import (
	"errors"
	"strings"
)

type Commands struct {
	User string
	Client
}

func (c *Commands) SendClient(name string) {
	c.SendCommand("Client", name)
}

func (c *Commands) Login(user, pass string) error {
	for line := range c.Recv() {
		if strings.HasPrefix(line, "Login ") {
			break
		}
	}
	if pass == "" {
		c.SendCommand("Login", user)
	} else {
		c.SendCommand("Login", user, pass)
	}
	for line := range c.Recv() {
		if line == "Authentication failure" {
			return errors.New("bad username or password")
		}
		if strings.HasPrefix(line, "Welcome ") {
			c.User = user
			return nil
		}
	}
	return errors.New("login failed")
}

func (c *Commands) LoginGuest() error {
	return c.Login("Guest", "")
}

func (c *Commands) Shout(room, msg string) {
	if room == "" {
		c.SendCommand("Shout", msg)
	} else {
		c.SendCommand("ShoutRoom", room, msg)
	}
}

func (c *Commands) Tell(who, msg string) {
	c.SendCommand("Tell", who, msg)
}
<|endoftext|>