VMware vSphere Integrated Containers provider (#206)
* Add Virtual Kubelet provider for VIC Initial virtual kubelet provider for VMware VIC. This provider currently handles creating and starting of a pod VM via the VIC portlayer and persona server. Image store handling via the VIC persona server. This provider currently requires the feature/wolfpack branch of VIC. * Added pod stop and delete. Also added node capacity. Added the ability to stop and delete pod VMs via VIC. Also retrieve node capacity information from the VCH. * Cleanup and readme file Some file clean up and added a Readme.md markdown file for the VIC provider. * Cleaned up errors, added function comments, moved operation code 1. Cleaned up error handling. Set standard for creating errors. 2. Added method prototype comments for all interface functions. 3. Moved PodCreator, PodStarter, PodStopper, and PodDeleter to a new folder. * Add mocking code and unit tests for podcache, podcreator, and podstarter Used the unit test framework used in VIC to handle assertions in the provider's unit test. Mocking code generated using OSS project mockery, which is compatible with the testify assertion framework. * Vendored packages for the VIC provider Requires feature/wolfpack branch of VIC and a few specific commit sha of projects used within VIC. * Implementation of POD Stopper and Deleter unit tests (#4) * Updated files for initial PR
This commit is contained in:
30
vendor/github.com/vmware/vic/pkg/serial/debug.go
generated
vendored
Normal file
30
vendor/github.com/vmware/vic/pkg/serial/debug.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2016 VMware, Inc. All Rights Reserved.
|
||||
//
|
||||
// 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 serial
|
||||
|
||||
var (
|
||||
verbose = false
|
||||
tracing = false
|
||||
)
|
||||
|
||||
// EnableTracing enables trace output for the serial package
|
||||
func EnableTracing() {
|
||||
tracing = true
|
||||
}
|
||||
|
||||
// DisableTracing disables trace output for the serial package
|
||||
func DisableTracing() {
|
||||
tracing = false
|
||||
}
|
||||
221
vendor/github.com/vmware/vic/pkg/serial/handshake.go
generated
vendored
Normal file
221
vendor/github.com/vmware/vic/pkg/serial/handshake.go
generated
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
// Copyright 2016 VMware, Inc. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
// Client:
|
||||
// generate a random uint8 (#)
|
||||
// send 2 bytes Syn|#
|
||||
//
|
||||
// Server:
|
||||
// generate a random uint8 (&)
|
||||
// read at least 2 bytes and make sure Syn|# is received
|
||||
// send 3 bytes Ack|#+1|& (or Nak)
|
||||
//
|
||||
// Client:
|
||||
// read at least 3 bytes and make sure Ack|#+1|& is received
|
||||
// send 2 bytes Ack|&+1
|
||||
//
|
||||
// Server:
|
||||
// read at least 2 bytes and make sure Ack|&+1 is received
|
||||
// send 1 byte Ack (or Nak)
|
||||
// Client:
|
||||
// read at leat 1 byte and make sure Ack is received
|
||||
|
||||
package serial
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
)
|
||||
|
||||
const (
|
||||
flagSyn byte = 0x16
|
||||
flagAck = 0x06
|
||||
flagNak = 0x15
|
||||
)
|
||||
|
||||
// HandshakeError should only occure if the protocol between HandshakeServer and HandshakeClient was violated.
|
||||
type HandshakeError struct {
|
||||
msg string
|
||||
}
|
||||
|
||||
func (he *HandshakeError) Error() string {
|
||||
return he.msg
|
||||
}
|
||||
func init() {
|
||||
rand.Seed(time.Now().UTC().UnixNano())
|
||||
}
|
||||
|
||||
// ReadAtLeastN reads at least l bytes and returns those l bytes or errors
|
||||
// We get lots of garbage data when we get the initial connection which handshake supposed to clear them and leave the connection in a known state so that the real ssh handshake can start.
|
||||
// Client and server is looping with different frequencies so client could send multiple requests before server even had a chance to read.
|
||||
// By getting the last l bytes we are saying that we are not interested with garbage data and also eliminating duplicated flags by only using the last one
|
||||
func ReadAtLeastN(conn io.ReadWriter, buffer []byte, l int) ([]byte, error) {
|
||||
n, err := io.ReadAtLeast(conn, buffer, l)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// however if we read more than l, it means buffer is not empty
|
||||
if n != l {
|
||||
buffer = buffer[n-l:]
|
||||
}
|
||||
|
||||
return buffer, nil
|
||||
}
|
||||
|
||||
// HandshakeClient establishes connection with the server making sure
|
||||
// they both are in sync.
|
||||
func HandshakeClient(conn io.ReadWriter) error {
|
||||
if tracing {
|
||||
defer trace.End(trace.Begin(""))
|
||||
}
|
||||
|
||||
// generate a random pos between [0, math.MaxUint8)
|
||||
pos := uint8(rand.Intn(math.MaxUint8))
|
||||
buffer := make([]byte, 32*1024)
|
||||
|
||||
// send syn with pos
|
||||
log.Debugf("HandshakeClient: Sending syn with pos %d", pos)
|
||||
if _, err := conn.Write([]byte{flagSyn, pos}); err != nil {
|
||||
log.Errorf("syn: write failed")
|
||||
return err
|
||||
}
|
||||
|
||||
// read ack with pos+1 and token
|
||||
buffer, err := ReadAtLeastN(conn, buffer, 3)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// extract pos and the token from it
|
||||
flag, posack, token := uint8(buffer[0]), uint8(buffer[1]), uint8(buffer[2])
|
||||
if flag == flagNak {
|
||||
return &HandshakeError{
|
||||
msg: "HandshakeClient: Server declined handshake request",
|
||||
}
|
||||
}
|
||||
if flag != flagAck {
|
||||
return &HandshakeError{
|
||||
msg: fmt.Sprintf("HandshakeClient: Unexpected server response: %#v", flag),
|
||||
}
|
||||
}
|
||||
|
||||
if posack != pos+1 {
|
||||
return &HandshakeError{
|
||||
msg: fmt.Sprintf("HandshakeClient: Unexpected ack position: %d, expected %d", posack, pos+1),
|
||||
}
|
||||
}
|
||||
|
||||
log.Debugf("HandshakeClient: Sending ack with %d", token+1)
|
||||
|
||||
if _, err := conn.Write([]byte{flagAck, token + 1}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// last ack packet is 1 byte and could be followed by SSH handshake so read only 1 byteand leave the rest in the net.Conn buffer
|
||||
buffer = buffer[:1]
|
||||
if _, err := conn.Read(buffer); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if buffer[0] != flagAck {
|
||||
return &HandshakeError{
|
||||
msg: fmt.Sprintf("HandshakeClient: Unexpected server response: %#v", flag),
|
||||
}
|
||||
}
|
||||
|
||||
log.Debug("HandshakeClient: Connection established.")
|
||||
return nil
|
||||
}
|
||||
|
||||
// HandshakeServer establishes connection with the client making sure
|
||||
// they both are in sync.
|
||||
func HandshakeServer(conn io.ReadWriter) error {
|
||||
if tracing {
|
||||
defer trace.End(trace.Begin(""))
|
||||
}
|
||||
|
||||
// generate a random pos between [0, math.MaxUint8)
|
||||
pos := uint8(rand.Intn(math.MaxUint8))
|
||||
buffer := make([]byte, 32*1024)
|
||||
|
||||
log.Debug("HandshakeServer: Waiting for incoming syn request...")
|
||||
|
||||
// Sync packet is 2 bytes, however if we read more than 2 it means buffer is not empty and data is not trusted for this sync.
|
||||
buffer, err := ReadAtLeastN(conn, buffer, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read 2 bytes, extract flag and the token from it
|
||||
flag, token := uint8(buffer[0]), uint8(buffer[1])
|
||||
if flag != flagSyn {
|
||||
if _, err := conn.Write([]byte{flagNak}); err != nil {
|
||||
return err
|
||||
}
|
||||
return &HandshakeError{
|
||||
msg: fmt.Sprintf("Unexpected syn packet: %x", flag),
|
||||
}
|
||||
}
|
||||
log.Debugf("HandshakeServer: Received syn with pos %d. Writing syn-ack with %d and %d", token, token+1, pos)
|
||||
|
||||
// token contains position token that needs to be incremented by one to send it back.
|
||||
if _, err := conn.Write([]byte{flagAck, token + 1, pos}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// ACK packet is 2 bytes, however if we read more than 2 it means buffer is not empty and data is not trusted for this sync.
|
||||
buffer, err = ReadAtLeastN(conn, buffer, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read 2 bytes, extract flag and the token from it
|
||||
flag, token = uint8(buffer[0]), uint8(buffer[1])
|
||||
if flag != flagAck {
|
||||
if _, err := conn.Write([]byte{flagNak}); err != nil {
|
||||
return err
|
||||
}
|
||||
return &HandshakeError{
|
||||
msg: fmt.Sprintf("Unexpected syn packet: %x", flag),
|
||||
}
|
||||
}
|
||||
|
||||
// token should contain incremented pos
|
||||
if token != pos+1 {
|
||||
if _, err := conn.Write([]byte{flagNak}); err != nil {
|
||||
return err
|
||||
}
|
||||
return &HandshakeError{
|
||||
msg: fmt.Sprintf("HandshakeServer: Unexpected position %x, expected: %x", token, pos+1),
|
||||
}
|
||||
}
|
||||
log.Debugf("HandshakeServer: Received ACK with %d.", token)
|
||||
|
||||
// send the last ACK
|
||||
if _, err := conn.Write([]byte{flagAck}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debug("HandshakeServer: Connection established.")
|
||||
return nil
|
||||
}
|
||||
429
vendor/github.com/vmware/vic/pkg/serial/handshake_test.go
generated
vendored
Normal file
429
vendor/github.com/vmware/vic/pkg/serial/handshake_test.go
generated
vendored
Normal file
@@ -0,0 +1,429 @@
|
||||
// Copyright 2016 VMware, Inc. All Rights Reserved.
|
||||
//
|
||||
// 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 serial
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
timeout = 10 * time.Second
|
||||
)
|
||||
|
||||
type readErr struct {
|
||||
err error
|
||||
n int
|
||||
}
|
||||
|
||||
type BlockingSendReceiver struct {
|
||||
c chan byte
|
||||
deadline chan struct{}
|
||||
}
|
||||
|
||||
func NewBlockingSendReceiver() *BlockingSendReceiver {
|
||||
return &BlockingSendReceiver{
|
||||
c: make(chan byte, 10240),
|
||||
deadline: make(chan struct{}, 1),
|
||||
}
|
||||
}
|
||||
|
||||
func (f *BlockingSendReceiver) Send(b []byte) (int, error) {
|
||||
for i := 0; i < len(b); i++ {
|
||||
f.c <- b[i]
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (f *BlockingSendReceiver) Timeout(d time.Duration) *BlockingSendReceiver {
|
||||
go func() {
|
||||
time.Sleep(d)
|
||||
f.deadline <- struct{}{}
|
||||
}()
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *BlockingSendReceiver) Receive(b []byte) (int, error) {
|
||||
select {
|
||||
case <-f.deadline:
|
||||
return 0, errors.New("Timeout error")
|
||||
default:
|
||||
}
|
||||
count := 0
|
||||
for count < len(b) {
|
||||
select {
|
||||
case v := <-f.c:
|
||||
b[count] = v
|
||||
count++
|
||||
case _, ok := <-f.deadline:
|
||||
if ok {
|
||||
close(f.deadline)
|
||||
}
|
||||
return 0, errors.New("Timeout error")
|
||||
default:
|
||||
if count == 0 {
|
||||
time.Sleep(time.Millisecond)
|
||||
} else {
|
||||
return count, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
type BiChannel struct {
|
||||
L *BlockingSendReceiver
|
||||
R *BlockingSendReceiver
|
||||
}
|
||||
|
||||
func (bc *BiChannel) Write(b []byte) (int, error) {
|
||||
return bc.L.Send(b)
|
||||
}
|
||||
|
||||
func (bc *BiChannel) Read(b []byte) (int, error) {
|
||||
return bc.R.Receive(b)
|
||||
}
|
||||
|
||||
func NewFakeConnection(t time.Duration) (*BiChannel, *BiChannel) {
|
||||
l := NewBlockingSendReceiver().Timeout(t)
|
||||
r := NewBlockingSendReceiver().Timeout(t)
|
||||
return &BiChannel{L: l, R: r}, &BiChannel{L: r, R: l}
|
||||
}
|
||||
|
||||
func TestHandshakeServerNormalCaseScenario(t *testing.T) {
|
||||
log.SetLevel(log.InfoLevel)
|
||||
if testing.Verbose() {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
}
|
||||
clientConn, serverConn := NewFakeConnection(timeout)
|
||||
|
||||
go func() {
|
||||
buf := make([]byte, 10)
|
||||
clientConn.Write([]byte{flagSyn, 200})
|
||||
|
||||
if n, e := clientConn.Read(buf); e != nil || n != 3 {
|
||||
t.Errorf("Only 3 bytes are expected: %x, received: %d", buf[:n], n)
|
||||
return
|
||||
}
|
||||
|
||||
if buf[0] != flagAck || buf[1] != 201 {
|
||||
t.Errorf("Error, unexpected data: %v", buf[:3])
|
||||
return
|
||||
}
|
||||
clientConn.Write([]byte{flagAck, buf[2] + 1})
|
||||
}()
|
||||
|
||||
if e := HandshakeServer(serverConn); e != nil {
|
||||
t.Errorf("Unexpected error: %v", e)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandshakeServerLotsOfTrashOnTheLine(t *testing.T) {
|
||||
log.SetLevel(log.InfoLevel)
|
||||
if testing.Verbose() {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
}
|
||||
clientConn, serverConn := NewFakeConnection(timeout)
|
||||
|
||||
go func() {
|
||||
buf := make([]byte, 10)
|
||||
|
||||
// Do not send too many bytes, otherwise "write" will block on server side due too many flagNak.
|
||||
x := "sdfkgn sdflkjsfdfdgis dfgs"
|
||||
for i := 0; i < 5; i++ {
|
||||
x += x
|
||||
}
|
||||
clientConn.Write([]byte(x))
|
||||
clientConn.Write([]byte{flagSyn, 200})
|
||||
|
||||
n, e := clientConn.Read(buf)
|
||||
if e != nil {
|
||||
t.Errorf("Unexpected server error: %v", e)
|
||||
return
|
||||
}
|
||||
|
||||
if n < 3 {
|
||||
t.Errorf("Unexpected server error: %v", e)
|
||||
return
|
||||
}
|
||||
|
||||
if buf[0] == flagNak {
|
||||
t.Errorf("Unexpected server error: %v", e)
|
||||
return
|
||||
}
|
||||
|
||||
if buf[0] != flagAck || buf[1] != 201 {
|
||||
t.Errorf("Error, unexpected data: %x", buf[:3])
|
||||
return
|
||||
}
|
||||
clientConn.Write([]byte{flagAck, buf[2] + 1})
|
||||
}()
|
||||
|
||||
e := HandshakeServer(serverConn)
|
||||
if e != nil {
|
||||
if _, ok := e.(*HandshakeError); !ok {
|
||||
t.Errorf("Unexpected error: %v", e)
|
||||
return
|
||||
}
|
||||
}
|
||||
if e != nil {
|
||||
e = HandshakeServer(serverConn)
|
||||
if _, ok := e.(*HandshakeError); !ok {
|
||||
t.Errorf("Unexpected error: %v", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandshakeServerComportSync(t *testing.T) {
|
||||
log.SetLevel(log.InfoLevel)
|
||||
if testing.Verbose() {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
}
|
||||
clientConn, serverConn := NewFakeConnection(timeout)
|
||||
|
||||
go func() {
|
||||
buf := make([]byte, 10)
|
||||
// this is the sequence we see from Linux serial driver on the real world
|
||||
clientConn.Write([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22})
|
||||
|
||||
for {
|
||||
clientConn.Write([]byte{flagSyn, 200})
|
||||
|
||||
n, e := clientConn.Read(buf)
|
||||
if e != nil {
|
||||
t.Errorf("Unexpected server error: %v", e)
|
||||
return
|
||||
}
|
||||
|
||||
if n < 3 {
|
||||
continue
|
||||
}
|
||||
|
||||
data := buf[n-3:]
|
||||
if data[0] == flagNak {
|
||||
continue
|
||||
}
|
||||
|
||||
if data[0] != flagAck || data[1] != 201 {
|
||||
t.Errorf("Error, unexpected data: %x", data[:3])
|
||||
return
|
||||
}
|
||||
clientConn.Write([]byte{flagAck, data[2] + 1})
|
||||
break
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
if e := HandshakeServer(serverConn); e == nil {
|
||||
break
|
||||
} else {
|
||||
if _, ok := e.(*HandshakeError); !ok {
|
||||
t.Errorf("Unexpected error: %v", e)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandshakeServerAckNakResponse(t *testing.T) {
|
||||
log.SetLevel(log.InfoLevel)
|
||||
if testing.Verbose() {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
}
|
||||
clientConn, serverConn := NewFakeConnection(timeout)
|
||||
|
||||
go func() {
|
||||
buf := make([]byte, 10)
|
||||
|
||||
// Do not send too many bytes, otherwise "write" will block on server side due too many flagNak.
|
||||
clientConn.Write([]byte{flagSyn, 200})
|
||||
|
||||
n, e := clientConn.Read(buf)
|
||||
if e != nil {
|
||||
t.Errorf("Unexpected server error: %v", e)
|
||||
return
|
||||
}
|
||||
|
||||
data := buf[n-3:]
|
||||
if data[0] != flagAck || data[1] != 201 {
|
||||
t.Errorf("Error, unexpected data: %x", data[:3])
|
||||
return
|
||||
}
|
||||
// intentional error. data[2] has to be incremented.
|
||||
clientConn.Write([]byte{flagAck, data[2]})
|
||||
if n, err := clientConn.Read(buf); n != 1 || err != nil || buf[0] != flagNak {
|
||||
t.Errorf("Unexpected data or error %d, %v", n, err)
|
||||
return
|
||||
}
|
||||
|
||||
clientConn.Write([]byte{flagSyn, 200})
|
||||
|
||||
n, e = clientConn.Read(buf)
|
||||
if e != nil {
|
||||
t.Errorf("Unexpected server error: %v", e)
|
||||
return
|
||||
}
|
||||
|
||||
data = buf[n-3:]
|
||||
if data[0] != flagAck || data[1] != 201 {
|
||||
t.Errorf("Error, unexpected data: %x", data[:3])
|
||||
return
|
||||
}
|
||||
|
||||
// intentional error. 99 in a wrong code.
|
||||
clientConn.Write([]byte{99, data[2] + 1})
|
||||
if n, err := clientConn.Read(buf); n != 1 || err != nil || buf[0] != flagNak {
|
||||
t.Errorf("Unexpected data or error %d, %v", n, err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
e := HandshakeServer(serverConn)
|
||||
if e != nil {
|
||||
if _, ok := e.(*HandshakeError); !ok {
|
||||
t.Errorf("Unexpected error: %v", e)
|
||||
return
|
||||
}
|
||||
}
|
||||
if e != nil {
|
||||
e = HandshakeServer(serverConn)
|
||||
if _, ok := e.(*HandshakeError); !ok {
|
||||
t.Errorf("Unexpected error: %v", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandshakeClientNormalConnection(t *testing.T) {
|
||||
log.SetLevel(log.InfoLevel)
|
||||
if testing.Verbose() {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
}
|
||||
|
||||
clientConn, serverConn := NewFakeConnection(timeout)
|
||||
|
||||
go func() {
|
||||
pos := byte(200)
|
||||
buf := make([]byte, 1024)
|
||||
if n, err := serverConn.Read(buf); n != 2 || err != nil || buf[0] != flagSyn {
|
||||
t.Errorf("Unexpected data or error %d, %v", n, err)
|
||||
return
|
||||
}
|
||||
serverConn.Write([]byte{flagAck, buf[1] + 1, pos})
|
||||
|
||||
if n, err := serverConn.Read(buf); n != 2 || err != nil || buf[0] != flagAck || buf[1] != pos+1 {
|
||||
t.Errorf("Unexpected data or error %d, %v", n, err)
|
||||
return
|
||||
}
|
||||
|
||||
serverConn.Write([]byte{flagAck})
|
||||
}()
|
||||
|
||||
e := HandshakeClient(clientConn)
|
||||
if e != nil {
|
||||
t.Errorf("Unexpected error: %v", e)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandshakeClientWrongServerAckPos(t *testing.T) {
|
||||
log.SetLevel(log.InfoLevel)
|
||||
if testing.Verbose() {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
}
|
||||
clientConn, serverConn := NewFakeConnection(timeout)
|
||||
|
||||
go func() {
|
||||
pos := byte(200)
|
||||
buf := make([]byte, 1024)
|
||||
if n, err := serverConn.Read(buf); n != 2 || err != nil || buf[0] != flagSyn {
|
||||
t.Errorf("Unexpected data or error %d, %v", n, err)
|
||||
return
|
||||
}
|
||||
|
||||
// writing the wrong buf[1] that supposed to be incremented.
|
||||
serverConn.Write([]byte{flagAck, buf[1], pos})
|
||||
|
||||
if n, err := serverConn.Read(buf); n != 2 || err != nil || buf[0] != flagAck || buf[1] != pos+1 {
|
||||
t.Errorf("Unexpected data or error %d, %v", n, err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
err, ok := HandshakeClient(clientConn).(*HandshakeError)
|
||||
if !ok {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandshakeClientWrongServerAck(t *testing.T) {
|
||||
log.SetLevel(log.InfoLevel)
|
||||
if testing.Verbose() {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
}
|
||||
clientConn, serverConn := NewFakeConnection(timeout)
|
||||
|
||||
go func() {
|
||||
pos := byte(200)
|
||||
buf := make([]byte, 1024)
|
||||
if n, err := serverConn.Read(buf); n != 2 || err != nil || buf[0] != flagSyn {
|
||||
t.Errorf("Unexpected data or error %d, %v", n, err)
|
||||
return
|
||||
}
|
||||
|
||||
// writing 90 instead of flagAck
|
||||
serverConn.Write([]byte{90, buf[1] + 1, pos})
|
||||
|
||||
if n, err := serverConn.Read(buf); n != 2 || err != nil || buf[0] != flagAck || buf[1] != pos+1 {
|
||||
t.Errorf("Unexpected data or error %d, %v", n, err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
err, ok := HandshakeClient(clientConn).(*HandshakeError)
|
||||
if !ok {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandshakeServerVsClient(t *testing.T) {
|
||||
log.SetLevel(log.InfoLevel)
|
||||
if testing.Verbose() {
|
||||
log.SetLevel(log.DebugLevel)
|
||||
}
|
||||
clientConn, serverConn := NewFakeConnection(timeout)
|
||||
w := sync.WaitGroup{}
|
||||
w.Add(2)
|
||||
|
||||
go func() {
|
||||
defer w.Done()
|
||||
err := HandshakeClient(clientConn)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer w.Done()
|
||||
err := HandshakeServer(serverConn)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
w.Wait()
|
||||
}
|
||||
47
vendor/github.com/vmware/vic/pkg/serial/rawaddr.go
generated
vendored
Normal file
47
vendor/github.com/vmware/vic/pkg/serial/rawaddr.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright 2016 VMware, Inc. All Rights Reserved.
|
||||
//
|
||||
// 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 serial
|
||||
|
||||
import "github.com/vmware/vic/pkg/trace"
|
||||
|
||||
type RawAddr struct {
|
||||
Net string
|
||||
Addr string
|
||||
}
|
||||
|
||||
func (addr RawAddr) Network() string {
|
||||
if tracing {
|
||||
defer trace.End(trace.Begin(""))
|
||||
}
|
||||
return addr.Net
|
||||
}
|
||||
|
||||
func (addr RawAddr) String() string {
|
||||
if tracing {
|
||||
|
||||
defer trace.End(trace.Begin(""))
|
||||
}
|
||||
return addr.Network() + "://" + addr.Addr
|
||||
}
|
||||
|
||||
func NewRawAddr(net string, addr string) *RawAddr {
|
||||
if tracing {
|
||||
defer trace.End(trace.Begin(""))
|
||||
}
|
||||
return &RawAddr{
|
||||
Net: net,
|
||||
Addr: addr,
|
||||
}
|
||||
}
|
||||
231
vendor/github.com/vmware/vic/pkg/serial/rawconn.go
generated
vendored
Normal file
231
vendor/github.com/vmware/vic/pkg/serial/rawconn.go
generated
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
// Copyright 2016 VMware, Inc. All Rights Reserved.
|
||||
//
|
||||
// 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 serial
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
)
|
||||
|
||||
type NamedReadChannel interface {
|
||||
io.ReadCloser
|
||||
Name() string
|
||||
Fd() uintptr
|
||||
}
|
||||
|
||||
type NamedWriteChannel interface {
|
||||
io.WriteCloser
|
||||
Name() string
|
||||
Fd() uintptr
|
||||
}
|
||||
|
||||
type RawConn struct {
|
||||
rchannel NamedReadChannel
|
||||
wchannel NamedWriteChannel
|
||||
localAddr net.Addr
|
||||
remoteAddr net.Addr
|
||||
err chan error
|
||||
mutex sync.Mutex
|
||||
closed bool
|
||||
}
|
||||
|
||||
func NewTypedConn(r NamedReadChannel, w NamedWriteChannel, net string) (*RawConn, error) {
|
||||
if tracing {
|
||||
defer trace.End(trace.Begin(""))
|
||||
}
|
||||
conn := &RawConn{
|
||||
rchannel: r,
|
||||
wchannel: w,
|
||||
|
||||
localAddr: *NewRawAddr(net, r.Name()),
|
||||
remoteAddr: *NewRawAddr(net, w.Name()),
|
||||
err: make(chan error, 1),
|
||||
closed: false,
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// NewFileConn creates a connection of the provided file - assumes file is a
|
||||
// full duplex comm mechanism
|
||||
func NewFileConn(file *os.File) (*RawConn, error) {
|
||||
if tracing {
|
||||
defer trace.End(trace.Begin(""))
|
||||
}
|
||||
return NewTypedConn(file, file, "file")
|
||||
}
|
||||
|
||||
// NewRawConn creates a connection via the provided file descriptor - assumes file is a
|
||||
// full duplex comm mechanism
|
||||
func NewRawConn(fd uintptr, name string, net string) (*RawConn, error) {
|
||||
if tracing {
|
||||
defer trace.End(trace.Begin(""))
|
||||
}
|
||||
file := os.NewFile(fd, name)
|
||||
return NewTypedConn(file, file, net)
|
||||
}
|
||||
|
||||
// NewHalfDuplexFileConn creates a connection via the provided files - this assumes that
|
||||
// each file is a half-duplex mechanism, such as a linux fifo pipe
|
||||
func NewHalfDuplexFileConn(read *os.File, write *os.File, name string, net string) (*RawConn, error) {
|
||||
if tracing {
|
||||
defer trace.End(trace.Begin(""))
|
||||
}
|
||||
return NewTypedConn(read, write, net)
|
||||
}
|
||||
|
||||
// Read reads data from the connection.
|
||||
func (conn *RawConn) Read(b []byte) (int, error) {
|
||||
if tracing {
|
||||
defer trace.End(trace.Begin(""))
|
||||
}
|
||||
|
||||
var n int
|
||||
var err error
|
||||
|
||||
if verbose {
|
||||
defer func() {
|
||||
log.Debugf("Returning error and bytes from read (%s:%s): %d, %s", conn.rchannel.Name(), conn.wchannel.Name(), n, err)
|
||||
}()
|
||||
}
|
||||
|
||||
// TODO: this is horrific from a performance perspective - really need a better
|
||||
// way to interrupt that file.Read call
|
||||
bytes := make(chan int, 1)
|
||||
|
||||
go func() {
|
||||
n, err = conn.rchannel.Read(b)
|
||||
|
||||
// if we've got any bytes we need to pass them back so we cannot return
|
||||
// the error via conn.err
|
||||
bytes <- n
|
||||
close(bytes)
|
||||
}()
|
||||
|
||||
conn.mutex.Lock()
|
||||
closed := conn.closed
|
||||
conn.mutex.Unlock()
|
||||
|
||||
select {
|
||||
case n = <-bytes:
|
||||
if err != nil && closed {
|
||||
err = io.EOF
|
||||
}
|
||||
return n, err
|
||||
case e := <-conn.err:
|
||||
log.Debugf("Returning error from read: %s", e)
|
||||
// only one close will send an error and we have that, so this won't block
|
||||
// we do need to interrupt all reads
|
||||
conn.err <- e
|
||||
return n, e
|
||||
}
|
||||
}
|
||||
|
||||
// Write writes data to the connection
|
||||
func (conn *RawConn) Write(b []byte) (int, error) {
|
||||
if tracing {
|
||||
defer trace.End(trace.Begin(""))
|
||||
}
|
||||
return conn.wchannel.Write(b)
|
||||
}
|
||||
|
||||
// Close closes the connection.
|
||||
func (conn *RawConn) Close() error {
|
||||
if tracing {
|
||||
defer trace.End(trace.Begin(""))
|
||||
}
|
||||
var closed bool
|
||||
|
||||
conn.mutex.Lock()
|
||||
closed = conn.closed
|
||||
conn.closed = true
|
||||
conn.mutex.Unlock()
|
||||
|
||||
if closed {
|
||||
log.Debugf("Close called again on RawConn (%s:%s) - dropping", conn.rchannel.Name(), conn.wchannel.Name())
|
||||
return nil
|
||||
}
|
||||
|
||||
// process the close
|
||||
log.Debugf("Closing the RawConn (%s:%s)", conn.rchannel.Name(), conn.wchannel.Name())
|
||||
errR := conn.rchannel.Close()
|
||||
errW := conn.wchannel.Close()
|
||||
|
||||
if verbose {
|
||||
buf := make([]byte, 4096)
|
||||
bytes := runtime.Stack(buf, false)
|
||||
log.Debugf("Close called on RawConn (%s:%s):\n%s", conn.rchannel.Name(), conn.wchannel.Name(), string(buf[:bytes]))
|
||||
}
|
||||
|
||||
log.Debugf("Pushing EOF to any blocked readers on the raw connection (%s:%s)", conn.rchannel.Name(), conn.wchannel.Name())
|
||||
conn.err <- io.EOF
|
||||
|
||||
if errR != nil {
|
||||
return errR
|
||||
}
|
||||
return errW
|
||||
}
|
||||
|
||||
// LocalAddr returns the local network address.
|
||||
func (conn *RawConn) LocalAddr() net.Addr {
|
||||
if tracing {
|
||||
defer trace.End(trace.Begin(""))
|
||||
}
|
||||
return conn.localAddr
|
||||
}
|
||||
|
||||
// RemoteAddr returns the remote network address.
|
||||
func (conn *RawConn) RemoteAddr() net.Addr {
|
||||
if tracing {
|
||||
defer trace.End(trace.Begin(""))
|
||||
}
|
||||
return conn.remoteAddr
|
||||
}
|
||||
|
||||
// SetDeadline sets the read and write deadlines associated
|
||||
// with the connection
|
||||
func (conn *RawConn) SetDeadline(t time.Time) error {
|
||||
if tracing {
|
||||
defer trace.End(trace.Begin(t.String()))
|
||||
}
|
||||
// https://golang.org/src/net/fd_poll_runtime.go#L133
|
||||
// consider implementing this by making RawConn a netFD
|
||||
// if we can find a way around the lack of export
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetReadDeadline sets the deadline for future Read calls.
|
||||
func (conn *RawConn) SetReadDeadline(t time.Time) error {
|
||||
if tracing {
|
||||
defer trace.End(trace.Begin(t.String()))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetWriteDeadline sets the deadline for future Write calls.
|
||||
func (conn *RawConn) SetWriteDeadline(t time.Time) error {
|
||||
if tracing {
|
||||
defer trace.End(trace.Begin(t.String()))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user