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:
Loc Nguyen
2018-06-04 15:41:32 -07:00
committed by Ria Bhatia
parent 98a111e8b7
commit 513cebe7b7
6296 changed files with 1123685 additions and 8 deletions

155
vendor/github.com/vmware/vic/lib/dns/cache.go generated vendored Normal file
View File

@@ -0,0 +1,155 @@
// 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 dns
import (
"fmt"
"sync"
"sync/atomic"
"time"
mdns "github.com/miekg/dns"
)
// Item represents an item in the cache
type Item struct {
Expiration time.Time
Msg *mdns.Msg
}
// CacheOptions represents the cache options
type CacheOptions struct {
// Max capacity of cache, after this limit cache starts to evict random elements
capacity int
// Default ttl used by items
ttl time.Duration
}
// Cache stores dns.Msgs and their expiration time
type Cache struct {
CacheOptions
// Protects following map
sync.RWMutex
m map[string]*Item
// atomic cache hits & misses counters
// ^ cause we update them while holding the read lock
hits uint64
misses uint64
}
// NewCache returns a new cache
func NewCache(options CacheOptions) *Cache {
return &Cache{
CacheOptions: options,
m: make(map[string]*Item, options.capacity),
}
}
// Capacity returns the capacity of the cache
func (c *Cache) Capacity() int {
return c.capacity
}
// Count returns the element count of the cache
func (c *Cache) Count() int {
c.RLock()
defer c.RUnlock()
return len(c.m)
}
func generateKey(q mdns.Question) string {
return fmt.Sprintf("%s:%s", q.Name, mdns.TypeToString[q.Qtype])
}
// Add adds dns.Msg to the cache
func (c *Cache) Add(msg *mdns.Msg) {
c.Lock()
defer c.Unlock()
if len(c.m) >= c.capacity {
// pick a random key and remove it
for k := range c.m {
delete(c.m, k)
break
}
}
key := generateKey(msg.Question[0])
if _, ok := c.m[key]; !ok {
c.m[key] = &Item{
Expiration: time.Now().UTC().Add(c.ttl),
Msg: msg.Copy(),
}
}
}
// Remove removes the dns.Msg from the cache
func (c *Cache) Remove(msg *mdns.Msg) {
c.Lock()
defer c.Unlock()
if len(c.m) <= 0 {
return
}
key := generateKey(msg.Question[0])
delete(c.m, key)
}
// Get returns the dns.Msg from the cache
func (c *Cache) Get(msg *mdns.Msg) *mdns.Msg {
key := generateKey(msg.Question[0])
c.RLock()
e, ok := c.m[key]
c.RUnlock()
if ok {
atomic.AddUint64(&c.hits, 1)
if time.Since(e.Expiration) < 0 {
return e.Msg.Copy()
}
// Expired msg, remove it from the cache
c.Remove(msg)
} else {
atomic.AddUint64(&c.misses, 1)
}
return nil
}
// Hits returns the number of cache hits
func (c *Cache) Hits() uint64 {
return atomic.LoadUint64(&c.hits)
}
// Misses returns the number of cache misses
func (c *Cache) Misses() uint64 {
return atomic.LoadUint64(&c.misses)
}
// Reset resets the cache
func (c *Cache) Reset() {
c.Lock()
defer c.Unlock()
// drop the old map for GC and reset counters
c.m = make(map[string]*Item, c.capacity)
atomic.StoreUint64(&c.hits, 0)
atomic.StoreUint64(&c.misses, 0)
}

217
vendor/github.com/vmware/vic/lib/dns/cache_test.go generated vendored Normal file
View File

@@ -0,0 +1,217 @@
// 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 dns
import (
"math/rand"
"sync"
"testing"
"time"
mdns "github.com/miekg/dns"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
func RandStringRunes(n int) string {
runes := []rune("abcdefghijklmnopqrstuvwxyz")
b := make([]rune, n)
for i := range b {
b[i] = runes[rand.Intn(len(runes))]
}
return string(b)
}
func RandDNSType() uint16 {
types := []uint16{
mdns.TypeA,
mdns.TypeAAAA,
}
return types[rand.Intn(len(types))]
}
func NewMsg() *mdns.Msg {
m := &mdns.Msg{}
name := RandStringRunes(16) + ".vmware.local."
qtype := RandDNSType()
m.SetQuestion(name, qtype)
return m
}
func TestCache(t *testing.T) {
o := CacheOptions{
capacity: 10,
ttl: 10 * time.Second,
}
c := NewCache(o)
var msgs []*mdns.Msg
for i := 0; i < 10; i++ {
msgs = append(msgs, NewMsg())
}
for _, msg := range msgs {
c.Add(msg)
}
if c.Count() != len(msgs) {
t.Fatalf("Add failed")
}
for _, msg := range msgs {
m := c.Get(msg)
if m.Question[0] != msg.Question[0] {
t.Fatalf("Get failed")
}
}
for _, msg := range msgs {
c.Remove(msg)
}
if c.Count() != 0 {
t.Fatalf("Remove failed")
}
}
func TestCapacity(t *testing.T) {
o := CacheOptions{
capacity: 10,
ttl: 10 * time.Second,
}
c := NewCache(o)
var msgs []*mdns.Msg
for i := 0; i < 100; i++ {
msgs = append(msgs, NewMsg())
}
for _, msg := range msgs {
c.Add(msg)
}
if c.Count() != c.Capacity() {
t.Fatalf("Add failed")
}
}
func TestReset(t *testing.T) {
o := CacheOptions{
capacity: 10,
ttl: 10 * time.Second,
}
c := NewCache(o)
var msgs []*mdns.Msg
for i := 0; i < 10; i++ {
msgs = append(msgs, NewMsg())
}
for _, msg := range msgs {
c.Add(msg)
}
if c.Count() != len(msgs) {
t.Fatalf("Add failed")
}
c.Reset()
if c.Count() != 0 {
t.Fatalf("Reset failed")
}
}
func TestExpiration(t *testing.T) {
o := CacheOptions{
capacity: 100,
ttl: time.Nanosecond,
}
c := NewCache(o)
var msgs []*mdns.Msg
for i := 0; i < 100; i++ {
msgs = append(msgs, NewMsg())
}
for _, msg := range msgs {
c.Add(msg)
}
for _, msg := range msgs {
// All of them should be expired
if c.Get(msg) != nil {
t.Fatalf("Get failed")
}
}
}
// For best result run with -race
func TestConcurrency(t *testing.T) {
var wg sync.WaitGroup
samplesize := 1 << 10
o := CacheOptions{
capacity: samplesize,
ttl: 10 * time.Minute,
}
c := NewCache(o)
// create a map so that we can iterate on it randomly
msgs := make(map[int]*mdns.Msg)
for i := 0; i < samplesize; i++ {
msgs[i] = NewMsg()
}
writer := func() {
for _, msg := range msgs {
c.Add(msg)
}
wg.Done()
}
reader := func() {
for _, msg := range msgs {
c.Get(msg)
}
wg.Done()
}
remover := func() {
for _, msg := range msgs {
c.Remove(msg)
}
wg.Done()
}
// 3 writer
for i := 0; i < 3; i++ {
wg.Add(1)
go writer()
}
// 5 reader
for i := 0; i < 5; i++ {
wg.Add(1)
go reader()
}
// 2 remover
for i := 0; i < 2; i++ {
wg.Add(1)
go remover()
}
wg.Wait()
}

641
vendor/github.com/vmware/vic/lib/dns/dns.go generated vendored Normal file
View File

@@ -0,0 +1,641 @@
// Copyright 2016-2017 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 dns
import (
"bufio"
"fmt"
"math/rand"
"net"
"os"
"strings"
"sync"
"time"
log "github.com/Sirupsen/logrus"
"github.com/vmware/vic/lib/portlayer/network"
"github.com/vmware/vic/pkg/trace"
mdns "github.com/miekg/dns"
)
const (
DefaultIP = "127.0.0.1"
DefaultPort = 53
DefaultTTL = 600 * time.Second
DefaultCacheSize = 1024
DefaultTimeout = 4 * time.Second
)
var (
options = ServerOptions{}
random *rand.Rand
)
func init() {
random = rand.New(rand.NewSource(time.Now().UnixNano()))
}
// ServerOptions represents the server options
type ServerOptions struct {
IP string
Port int
Interface string
Nameservers flagMultipleVar
Timeout time.Duration
TTL time.Duration
CacheSize int
Debug bool
}
// Server represents udp/tcp server and clients
type Server struct {
ServerOptions
// used for serving dns
udpserver *mdns.Server
udpconn *net.UDPConn
tcpserver *mdns.Server
tcplisten *net.TCPListener
// used for forwarding queries
udpclient *mdns.Client
tcpclient *mdns.Client
// used for speeding up external lookups
cache *Cache
wg *sync.WaitGroup
}
type flagMultipleVar []string
func (i *flagMultipleVar) String() string {
return fmt.Sprint(*i)
}
func (i *flagMultipleVar) Set(value string) error {
*i = append(*i, value)
return nil
}
// NewServer returns a new Server
func NewServer(options ServerOptions) *Server {
var err error
// Default TTL
if options.TTL == 0 {
options.TTL = DefaultTTL
}
// Default port
if options.Port == 0 {
options.Port = DefaultPort
}
// Default nameservers
if len(options.Nameservers) == 0 {
options.Nameservers = resolvconf()
}
// Default cache size
if options.CacheSize == 0 {
options.CacheSize = DefaultCacheSize
}
// Default timeout
if options.Timeout == 0 {
options.Timeout = DefaultTimeout
}
server := &Server{
ServerOptions: options,
cache: NewCache(CacheOptions{options.CacheSize, options.TTL}),
wg: new(sync.WaitGroup),
}
udpaddr := &net.UDPAddr{
IP: net.ParseIP(server.IP),
Port: server.Port,
}
server.udpconn, err = net.ListenUDP("udp", udpaddr)
if err != nil {
log.Errorf("ListenUDP failed %s", err)
return nil
}
tcpaddr := &net.TCPAddr{
IP: net.ParseIP(server.IP),
Port: server.Port,
}
server.tcplisten, err = net.ListenTCP("tcp", tcpaddr)
if err != nil {
log.Errorf("ListenTCP failed %s", err)
return nil
}
server.udpclient = &mdns.Client{
Net: "udp",
ReadTimeout: server.Timeout,
WriteTimeout: server.Timeout,
SingleInflight: true,
}
server.tcpclient = &mdns.Client{
Net: "tcp",
ReadTimeout: server.Timeout,
WriteTimeout: server.Timeout,
SingleInflight: true,
}
return server
}
// Addr returns the ip:port of the server
func (s *Server) Addr() string {
return fmt.Sprintf("%s:%d", s.IP, s.Port)
}
func respServerFailure(w mdns.ResponseWriter, r *mdns.Msg) error {
m := new(mdns.Msg)
m.SetRcode(r, mdns.RcodeServerFailure)
// Does not matter if this write fails
return w.WriteMsg(m)
}
func respNotImplemented(w mdns.ResponseWriter, r *mdns.Msg) error {
m := &mdns.Msg{
MsgHdr: mdns.MsgHdr{
Authoritative: false,
RecursionDesired: false,
RecursionAvailable: false,
Rcode: mdns.RcodeNotImplemented,
},
Compress: true,
}
m.SetReply(r)
if err := w.WriteMsg(m); err != nil {
log.Errorf("Error writing RcodeNotImplemented response, %s", err)
return err
}
return nil
}
func resolvconf() []string {
var servers []string
file, err := os.Open("/etc/resolv.conf")
if err != nil {
return nil
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
// skip comments
if len(line) > 0 && (line[0] == ';' || line[0] == '#') {
continue
}
f := strings.SplitN(line, " ", 2)
if len(f) < 1 {
continue
}
if f[0] == "nameserver" {
if len(f) > 1 && len(servers) < 3 { // small, but the standard limit
// One more check: make sure server name is
// just an IP address. Otherwise we need DNS
// to look it up.
if net.ParseIP(f[1]) != nil {
servers = append(servers, f[1])
}
}
}
}
if err := scanner.Err(); err != nil {
return nil
}
return servers
}
// SeenBefore returns the cached response
func (s *Server) SeenBefore(w mdns.ResponseWriter, r *mdns.Msg) (bool, error) {
defer trace.End(trace.Begin(r.String()))
// Do we have it in the cache
if m := s.cache.Get(r); m != nil {
log.Debugf("Cache hit for %q", r.String())
// Overwrite the ID with the request's ID
m.Id = r.Id
m.Compress = true
m.Truncated = false
if err := w.WriteMsg(m); err != nil {
log.Errorf("Error writing response: %q", err)
return true, err
}
return true, nil
}
return false, nil
}
// HandleForwarding forwards a request to the nameservers and returns the response
func (s *Server) HandleForwarding(w mdns.ResponseWriter, r *mdns.Msg) (bool, error) {
defer trace.End(trace.Begin(r.String()))
var m *mdns.Msg
var err error
var try int
if len(s.Nameservers) == 0 {
log.Errorf("No nameservers defined, can not forward")
return false, respServerFailure(w, r)
}
// which protocol are they talking
tcp := false
if _, ok := w.RemoteAddr().(*net.TCPAddr); ok {
tcp = true
}
// Use request ID for "random" nameserver selection.
nsid := int(r.Id) % len(s.Nameservers)
Redo:
nameserver := s.Nameservers[nsid]
if i := strings.Index(nameserver, ":"); i < 0 {
nameserver += ":53"
}
if tcp {
m, _, err = s.tcpclient.Exchange(r, nameserver)
} else {
m, _, err = s.udpclient.Exchange(r, nameserver)
}
if err != nil {
// Seen an error, this can only mean, "server not reached", try again but only if we have not exausted our nameservers.
if try < len(s.Nameservers) {
try++
nsid = (nsid + 1) % len(s.Nameservers)
goto Redo
}
log.Errorf("Failure to forward request: %q", err)
return false, respServerFailure(w, r)
}
// We have a response so cache it
s.cache.Add(m)
m.Compress = true
if err := w.WriteMsg(m); err != nil {
log.Errorf("Error writing response: %q", err)
return true, err
}
return true, nil
}
// lookupByAlias looks up a container by alias, given the requesting container
// and the network of the incoming request. It first does a container-scoped
// alias search, followed by a network-scoped aliased search for alias. The
// result is a collection of endpoints for the matching container that are
// only on the same network as the requesting container.
func lookupByAlias(netCtx *network.Context, scope *network.Scope, reqc *network.Container, alias string) []*network.Endpoint {
// container specific alias search
cons := netCtx.ContainersByAlias(network.ScopedAliasName(scope.Name(), reqc.Name(), alias))
if len(cons) == 0 {
// scope-wide alias search
cons = netCtx.ContainersByAlias(network.ScopedAliasName(scope.Name(), "", alias))
}
if len(cons) == 0 {
return nil
}
var eps []*network.Endpoint
for _, c := range cons {
if e := c.Endpoint(scope); e != nil {
eps = append(eps, e)
}
}
return eps
}
// lookupByName looks up a container by name given the requesting container. It returns a collection
// of endpoints on networks that both the requesting and matching container share.
func lookupByName(netCtx *network.Context, reqc *network.Container, name string) []*network.Endpoint {
var eps []*network.Endpoint
if m := netCtx.Container(name); m != nil {
// look if networks overlap for the requesting container and the
// matched container
for _, ec := range reqc.Endpoints() {
if em := m.Endpoint(ec.Scope()); em != nil {
eps = append(eps, em)
}
}
}
return eps
}
// HandleVIC returns a response to a container name/id request
func (s *Server) HandleVIC(w mdns.ResponseWriter, r *mdns.Msg) (bool, error) {
defer trace.End(trace.Begin(r.String()))
question := r.Question[0]
netCtx := network.DefaultContext
if netCtx == nil {
log.Errorf("DefaultContext is not initialized")
return false, fmt.Errorf("DefaultContext is not initialized")
}
clientIP, _, err := net.SplitHostPort(w.RemoteAddr().String())
if err != nil {
log.Errorf("SplitHostPort failed: %q", err)
return false, err
}
log.Debugf("RemoteAddr: %s", clientIP)
ip := net.ParseIP(clientIP)
var name string
var domain string
name = strings.TrimSuffix(question.Name, ".")
// Do we have a domain?
i := strings.IndexRune(name, '.')
if i >= 0 {
name, domain = name[:i], name[i+1:]
}
// get the requesting container's endpoint
e := netCtx.ContainerByAddr(ip)
if e == nil {
return false, fmt.Errorf("Could not find requesting container with ip %s", ip)
}
if domain != "" && e.Scope().Name() != domain {
return false, fmt.Errorf("Intra-scope request for container %s in %s from %s", name, domain, e.Scope().Name())
}
eps := lookupByAlias(netCtx, e.Scope(), e.Container(), name)
if len(eps) == 0 {
// lookup container by name
eps = lookupByName(netCtx, e.Container(), name)
}
if len(eps) == 0 {
log.Debugf("Can't find the container: %q", name)
return false, fmt.Errorf("Can't find the container: %q", name)
}
// FIXME: Add AAAA when we support it
answer := make([]mdns.RR, len(eps))
// shuffle eps (FisherYates shuffle)
for i := len(eps) - 1; i > 0; i-- {
j := random.Intn(i + 1)
eps[i], eps[j] = eps[j], eps[i]
}
for i, e := range eps {
if e.IP().IsUnspecified() {
return false, fmt.Errorf("No ip for container %q", name)
}
answer[i] = &mdns.A{
Hdr: mdns.RR_Header{
Name: question.Name,
Rrtype: mdns.TypeA,
Class: mdns.ClassINET,
Ttl: uint32(DefaultTTL.Seconds()),
},
A: e.IP(),
}
}
// Start crafting reply msg
m := &mdns.Msg{
MsgHdr: mdns.MsgHdr{
Authoritative: true,
RecursionAvailable: true,
},
Compress: true,
}
m.SetReply(r)
m.Answer = append(m.Answer, answer...)
// Which protocol we are talking
tcp := false
if _, ok := w.LocalAddr().(*net.TCPAddr); ok {
tcp = true
}
// 512 byte payload guarantees that DNS packets can be reassembled if fragmented in transit.
bufsize := 512
// With EDNS0 in use a larger payload size can be specified.
if o := r.IsEdns0(); o != nil {
bufsize = int(o.UDPSize())
}
// Make sure we are not smaller than 512
if bufsize < 512 {
bufsize = 512
}
// With TCP we can send up to 64K
if tcp {
bufsize = mdns.MaxMsgSize - 1
}
// Trim the answer RRs one by one till the whole message fits within the reply size
if m.Len() > bufsize {
if tcp {
m.Truncated = true
}
for m.Len() > bufsize {
m.Answer = m.Answer[:len(m.Answer)-1]
}
}
if err := w.WriteMsg(m); err != nil {
log.Errorf("Error writing response, %s", err)
return true, err
}
w.Close()
return true, nil
}
// ServeDNS implements the handler interface
func (s *Server) ServeDNS(w mdns.ResponseWriter, r *mdns.Msg) {
defer trace.End(trace.Begin(r.String()))
if r == nil || len(r.Question) == 0 {
return
}
// Reject multi-question query
if len(r.Question) != 1 {
log.Errorf("Rejected multi-question query")
respServerFailure(w, r)
return
}
q := r.Question[0]
// Reject non-INET type query
if q.Qclass != mdns.ClassINET {
log.Errorf("Rejected non-inet query")
respNotImplemented(w, r)
return
}
// Reject ANY type query
if q.Qtype == mdns.TypeANY {
log.Errorf("Rejected ANY query")
respNotImplemented(w, r)
return
}
// Check VIC first
// Currently VIC can only answer ipv4 "A" queries
if q.Qtype == mdns.TypeA {
ok, err := s.HandleVIC(w, r)
if ok {
if err != nil {
log.Errorf("HandleVIC returned: %q", err)
}
return
}
}
// Do we have the response in our cache?
ok, err := s.SeenBefore(w, r)
if ok {
if err != nil {
log.Errorf("SeenBefore returned: %q", err)
}
return
}
// Then forward
ok, err = s.HandleForwarding(w, r)
if ok {
if err != nil {
log.Errorf("HandleForwarding returned: %q", err)
}
return
}
}
// Start starts the DNS server
func (s *Server) Start() {
// Call BindToDevice if IP is empty and Interface is set
if s.IP == "" && s.Interface != "" {
uf, err := s.udpconn.File()
if err != nil {
log.Errorf("Getting the fd failed with: %s", err)
} else {
// BindToDevice binds the socket associated with fd to device.
if err := BindToDevice(int(uf.Fd()), s.Interface); err != nil {
log.Errorf("Calling BindToDevice failed with: %s", err)
}
}
}
udpserver := &mdns.Server{
Handler: s,
PacketConn: s.udpconn,
}
s.udpserver = udpserver
s.wg.Add(1)
go func() {
defer s.wg.Done()
udpserver.ActivateAndServe()
log.Debugf("UDP server exited")
}()
log.Infof("Ready for queries on udp://%s", s.Addr())
// Call BindToDevice if IP is empty and Interface is set
if s.IP == "" && s.Interface != "" {
tf, err := s.tcplisten.File()
if err != nil {
log.Errorf("Getting the fd failed with: %s", err)
} else {
// BindToDevice binds the socket associated with fd to device.
if err := BindToDevice(int(tf.Fd()), s.Interface); err != nil {
log.Errorf("Calling BindToDevice failed with: %s", err)
}
}
}
tcpserver := &mdns.Server{Handler: s, Listener: s.tcplisten}
s.tcpserver = tcpserver
s.wg.Add(1)
go func() {
defer s.wg.Done()
tcpserver.ActivateAndServe()
log.Debugf("TCP server exited")
}()
log.Infof("Ready for queries on tcp://%s", s.Addr())
}
// Stop stops the DNS server gracefully
func (s *Server) Stop() {
if s.udpserver != nil {
log.Debugf("Shutting down udpserver")
s.udpserver.Shutdown()
}
s.udpconn = nil
s.udpserver = nil
if s.tcpserver != nil {
log.Debugf("Shutting down tcpserver")
s.tcpserver.Shutdown()
}
s.tcplisten = nil
s.tcpserver = nil
}
// Wait block until wg returns
func (s *Server) Wait() {
s.wg.Wait()
}

174
vendor/github.com/vmware/vic/lib/dns/dns_test.go generated vendored Normal file
View File

@@ -0,0 +1,174 @@
// 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 dns
import (
"net"
"testing"
log "github.com/Sirupsen/logrus"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/types"
"github.com/vmware/vic/lib/config"
"github.com/vmware/vic/lib/config/executor"
"github.com/vmware/vic/lib/constants"
"github.com/vmware/vic/lib/portlayer/exec"
"github.com/vmware/vic/lib/portlayer/network"
"github.com/vmware/vic/pkg/trace"
"context"
mdns "github.com/miekg/dns"
)
var (
Rtypes = []uint16{
mdns.TypeA,
mdns.TypeTXT,
mdns.TypeAAAA,
}
Dnames = []string{
"facebook.com.",
"google.com.",
}
)
func TestForwarding(t *testing.T) {
t.Skipf("Failing with CI")
log.SetLevel(log.PanicLevel)
options.IP = "127.0.0.1"
options.Port = 5354
server := NewServer(options)
if server != nil {
server.Start()
}
c := new(mdns.Client)
size := 1024
for i := 0; i < size; i++ {
for _, Δ := range Rtypes {
for _, Θ := range Dnames {
m := new(mdns.Msg)
m.SetQuestion(Θ, Δ)
r, _, err := c.Exchange(m, server.Addr())
if err != nil || len(r.Answer) == 0 {
t.Fatalf("Exchange failed: %s", err)
}
}
}
}
n := len(Rtypes) * len(Dnames)
if server.cache.Hits() != uint64(n*size-n) && server.cache.Misses() != uint64(size) {
t.Fatalf("Cache hits %d misses %d", server.cache.Hits(), server.cache.Misses())
}
server.Stop()
server.Wait()
}
func TestVIC(t *testing.T) {
t.Skipf("Failing with CI")
op := trace.NewOperation(context.Background(), "TestVIC")
log.SetLevel(log.PanicLevel)
options.IP = "127.0.0.1"
options.Port = 5354
// BEGIN - Context initialization
var bridgeNetwork object.NetworkReference
n := object.NewNetwork(nil, types.ManagedObjectReference{})
n.InventoryPath = "testBridge"
bridgeNetwork = n
conf := &network.Configuration{
Network: config.Network{
BridgeNetwork: "lo",
ContainerNetworks: map[string]*executor.ContainerNetwork{
"lo": {
Common: executor.Common{
Name: "testBridge",
},
Type: constants.BridgeScopeType,
},
},
},
PortGroups: map[string]object.NetworkReference{
"lo": bridgeNetwork,
},
}
// initialize the context
ctx, err := network.NewContext(conf, nil)
if err != nil {
t.Fatalf("%s", err)
}
// create the container
con := exec.TestHandle("foo")
ip := net.IPv4(172, 16, 0, 2)
ctxOptions := &network.AddContainerOptions{
Scope: "bridge",
IP: ip,
}
// add it
err = ctx.AddContainer(con, ctxOptions)
if err != nil {
t.Fatalf("%s", err)
}
// bind it
_, err = ctx.BindContainer(op, con)
if err != nil {
t.Fatalf("%s", err)
}
server := NewServer(options)
if server != nil {
server.Start()
}
// END - Context initialization
m := new(mdns.Msg)
m.SetQuestion("foo.", mdns.TypeA)
c := new(mdns.Client)
r, _, err := c.Exchange(m, server.Addr())
if err != nil || len(r.Answer) == 0 {
t.Fatalf("Exchange failed: %s", err)
}
m = new(mdns.Msg)
m.SetQuestion("foo.bridge.", mdns.TypeA)
r, _, err = c.Exchange(m, server.Addr())
if err != nil || len(r.Answer) == 0 {
t.Fatalf("Exchange failed: %s", err)
}
server.Stop()
server.Wait()
}

20
vendor/github.com/vmware/vic/lib/dns/syscall_darwin.go generated vendored Normal file
View File

@@ -0,0 +1,20 @@
// 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 dns
// BindToDevice binds the socket associated with fd to device.
func BindToDevice(fd int, device string) error {
return nil
}

22
vendor/github.com/vmware/vic/lib/dns/syscall_linux.go generated vendored Normal file
View File

@@ -0,0 +1,22 @@
// 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 dns
import "syscall"
// BindToDevice binds the socket associated with fd to device.
func BindToDevice(fd int, device string) error {
return syscall.BindToDevice(fd, device)
}

View File

@@ -0,0 +1,20 @@
// 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 dns
// BindToDevice binds the socket associated with fd to device.
func BindToDevice(fd int, device string) error {
return nil
}