Coveralls logob
Coveralls logo
  • Home
  • Features
  • Pricing
  • Docs
  • Sign In

weaveworks / weave / #4371

9 Nov 2015 - 15:51 coverage increased (+0.1%) to 75.78%
#4371

Pull #1648

circleci

2f1e5f233f2b7283a9bf3277e75bf30a?size=18&default=identiconrade
refactor: move NetworkRouterStatus into its own file
Pull Request #1648: separate the control and data planes

134 of 198 new or added lines in 11 files covered. (67.68%)

56 existing lines in 6 files now uncovered.

6483 of 8555 relevant lines covered (75.78%)

192419.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.24
/prog/weaver/main.go
1
package main
2

3
import (
4
        "fmt"
5
        "net"
6
        "net/http"
7
        _ "net/http/pprof"
8
        "os"
9
        "runtime"
10
        "strings"
11
        "time"
12

13
        "github.com/davecheney/profile"
14
        "github.com/docker/docker/pkg/mflag"
15
        "github.com/gorilla/mux"
16

17
        . "github.com/weaveworks/weave/common"
18
        "github.com/weaveworks/weave/common/docker"
19
        "github.com/weaveworks/weave/ipam"
20
        "github.com/weaveworks/weave/nameserver"
21
        weavenet "github.com/weaveworks/weave/net"
22
        "github.com/weaveworks/weave/net/address"
23
        weave "github.com/weaveworks/weave/router"
24
)
25

26
var version = "(unreleased version)"
27

28
func main() {
49×
29
        procs := runtime.NumCPU()
49×
30
        // packet sniffing can block an OS thread, so we need one thread
49×
31
        // for that plus at least one more.
49×
32
        if procs < 2 {
49×
33
                procs = 2
49×
34
        }
49×
35
        runtime.GOMAXPROCS(procs)
49×
36

49×
37
        var (
49×
38
                // flags that cause immediate exit
49×
39
                justVersion          bool
49×
40
                createDatapath       bool
49×
41
                deleteDatapath       bool
49×
42
                addDatapathInterface string
49×
43

49×
44
                config                    weave.Config
49×
45
                networkConfig             weave.NetworkConfig
49×
46
                protocolMinVersion        int
49×
47
                ifaceName                 string
49×
48
                routerName                string
49×
49
                nickName                  string
49×
50
                password                  string
49×
51
                pktdebug                  bool
49×
52
                logLevel                  string
49×
53
                prof                      string
49×
54
                bufSzMB                   int
49×
55
                noDiscovery               bool
49×
56
                httpAddr                  string
49×
57
                iprangeCIDR               string
49×
58
                ipsubnetCIDR              string
49×
59
                peerCount                 int
49×
60
                dockerAPI                 string
49×
61
                peers                     []string
49×
62
                noDNS                     bool
49×
63
                dnsDomain                 string
49×
64
                dnsListenAddress          string
49×
65
                dnsTTL                    int
49×
66
                dnsClientTimeout          time.Duration
49×
67
                dnsEffectiveListenAddress string
49×
68
                iface                     *net.Interface
49×
69
                datapathName              string
49×
70
        )
49×
71

49×
72
        mflag.BoolVar(&justVersion, []string{"#version", "-version"}, false, "print version and exit")
49×
73
        mflag.BoolVar(&createDatapath, []string{"-create-datapath"}, false, "create ODP datapath and exit")
49×
74
        mflag.BoolVar(&deleteDatapath, []string{"-delete-datapath"}, false, "delete ODP datapath and exit")
49×
75
        mflag.StringVar(&addDatapathInterface, []string{"-add-datapath-iface"}, "", "add a network interface to the ODP datapath and exit")
49×
76

49×
77
        mflag.IntVar(&config.Port, []string{"#port", "-port"}, weave.Port, "router port")
49×
78
        mflag.IntVar(&protocolMinVersion, []string{"-min-protocol-version"}, weave.ProtocolMinVersion, "minimum weave protocol version")
49×
79
        mflag.StringVar(&ifaceName, []string{"#iface", "-iface"}, "", "name of interface to capture/inject from (disabled if blank)")
49×
80
        mflag.StringVar(&routerName, []string{"#name", "-name"}, "", "name of router (defaults to MAC of interface)")
49×
81
        mflag.StringVar(&nickName, []string{"#nickname", "-nickname"}, "", "nickname of peer (defaults to hostname)")
49×
82
        mflag.StringVar(&password, []string{"#password", "-password"}, "", "network password")
49×
83
        mflag.StringVar(&logLevel, []string{"-log-level"}, "info", "logging level (debug, info, warning, error)")
49×
84
        mflag.BoolVar(&pktdebug, []string{"#pktdebug", "#-pktdebug", "-pkt-debug"}, false, "enable per-packet debug logging")
49×
85
        mflag.StringVar(&prof, []string{"#profile", "-profile"}, "", "enable profiling and write profiles to given path")
49×
86
        mflag.IntVar(&config.ConnLimit, []string{"#connlimit", "#-connlimit", "-conn-limit"}, 30, "connection limit (0 for unlimited)")
49×
87
        mflag.BoolVar(&noDiscovery, []string{"#nodiscovery", "#-nodiscovery", "-no-discovery"}, false, "disable peer discovery")
49×
88
        mflag.IntVar(&bufSzMB, []string{"#bufsz", "-bufsz"}, 8, "capture buffer size in MB")
49×
89
        mflag.StringVar(&httpAddr, []string{"#httpaddr", "#-httpaddr", "-http-addr"}, "", "address to bind HTTP interface to (disabled if blank, absolute path indicates unix domain socket)")
49×
90
        mflag.StringVar(&iprangeCIDR, []string{"#iprange", "#-iprange", "-ipalloc-range"}, "", "IP address range reserved for automatic allocation, in CIDR notation")
49×
91
        mflag.StringVar(&ipsubnetCIDR, []string{"#ipsubnet", "#-ipsubnet", "-ipalloc-default-subnet"}, "", "subnet to allocate within by default, in CIDR notation")
49×
92
        mflag.IntVar(&peerCount, []string{"#initpeercount", "#-initpeercount", "-init-peer-count"}, 0, "number of peers in network (for IP address allocation)")
49×
93
        mflag.StringVar(&dockerAPI, []string{"#api", "#-api", "-docker-api"}, "", "Docker API endpoint, e.g. unix:///var/run/docker.sock")
49×
94
        mflag.BoolVar(&noDNS, []string{"-no-dns"}, false, "disable DNS server")
49×
95
        mflag.StringVar(&dnsDomain, []string{"-dns-domain"}, nameserver.DefaultDomain, "local domain to server requests for")
49×
96
        mflag.StringVar(&dnsListenAddress, []string{"-dns-listen-address"}, nameserver.DefaultListenAddress, "address to listen on for DNS requests")
49×
97
        mflag.IntVar(&dnsTTL, []string{"-dns-ttl"}, nameserver.DefaultTTL, "TTL for DNS request from our domain")
49×
98
        mflag.DurationVar(&dnsClientTimeout, []string{"-dns-fallback-timeout"}, nameserver.DefaultClientTimeout, "timeout for fallback DNS requests")
49×
99
        mflag.StringVar(&dnsEffectiveListenAddress, []string{"-dns-effective-listen-address"}, "", "address DNS will actually be listening, after Docker port mapping")
49×
100
        mflag.StringVar(&datapathName, []string{"-datapath"}, "", "ODP datapath name")
49×
101

49×
102
        // crude way of detecting that we probably have been started in a
49×
103
        // container, with `weave launch` --> suppress misleading paths in
49×
104
        // mflags error messages.
49×
105
        if os.Args[0] == "/home/weave/weaver" { // matches the Dockerfile ENTRYPOINT
49×
106
                os.Args[0] = "weave"
49×
107
                mflag.CommandLine.Init("weave", mflag.ExitOnError)
49×
108
        }
49×
109

110
        mflag.Parse()
49×
111

49×
112
        peers = mflag.Args()
49×
113

49×
114
        SetLogLevel(logLevel)
49×
115

49×
116
        switch {
49×
117
        case justVersion:
!
118
                fmt.Printf("weave router %s\n", version)
!
119
                os.Exit(0)
!
120

121
        case createDatapath:
!
122
                err, odp_supported := weave.CreateDatapath(datapathName)
!
123
                if !odp_supported {
!
124
                        if err != nil {
!
125
                                Log.Error(err)
!
126
                        }
!
127

128
                        // When the kernel lacks ODP support, exit
129
                        // with a special status to distinguish it for
130
                        // the weave script.
131
                        os.Exit(17)
!
132
                }
133

134
                checkFatal(err)
!
135
                os.Exit(0)
!
136

137
        case deleteDatapath:
!
138
                checkFatal(weave.DeleteDatapath(datapathName))
!
139
                os.Exit(0)
!
140

141
        case addDatapathInterface != "":
!
142
                checkFatal(weave.AddDatapathInterface(datapathName, addDatapathInterface))
!
143
                os.Exit(0)
!
144
        }
145

146
        Log.Println("Command line options:", options())
49×
147
        Log.Println("Command line peers:", peers)
49×
148

49×
149
        if protocolMinVersion < weave.ProtocolMinVersion || protocolMinVersion > weave.ProtocolMaxVersion {
!
150
                Log.Fatalf("--min-protocol-version must be in range [%d,%d]", weave.ProtocolMinVersion, weave.ProtocolMaxVersion)
!
151
        }
!
152
        config.ProtocolMinVersion = byte(protocolMinVersion)
49×
153

49×
154
        var fastDPOverlay weave.NetworkOverlay
49×
155
        if datapathName != "" {
47×
156
                // A datapath name implies that "Bridge" and "Overlay"
47×
157
                // packet handling use fast datapath, although other
47×
158
                // options can override that below.  Even if both
47×
159
                // things are overridden, we might need bridging on
47×
160
                // the datapath.
47×
161
                fastdp, err := weave.NewFastDatapath(weave.FastDatapathConfig{
47×
162
                        DatapathName: datapathName,
47×
163
                        Port:         config.Port,
47×
164
                })
47×
165

47×
166
                checkFatal(err)
47×
167
                networkConfig.Bridge = fastdp.Bridge()
47×
168
                fastDPOverlay = fastdp.Overlay()
47×
169
        }
47×
170

171
        if ifaceName != "" {
4×
172
                // -iface can coexist with -datapath, because
4×
173
                // pcap-based packet capture is a bit more efficient
4×
174
                // than capture via ODP misses, even when using an
4×
175
                // ODP-based bridge.  So when using weave encyption,
4×
176
                // it's preferable to use -iface.
4×
177
                var err error
4×
178
                iface, err = weavenet.EnsureInterface(ifaceName)
4×
179
                checkFatal(err)
4×
180

4×
181
                // bufsz flag is in MB
4×
182
                networkConfig.Bridge, err = weave.NewPcap(iface, bufSzMB*1024*1024)
4×
183
                checkFatal(err)
4×
184
        }
4×
185

186
        if password == "" {
49×
187
                password = os.Getenv("WEAVE_PASSWORD")
49×
188
        }
49×
189

190
        if password == "" {
47×
191
                Log.Println("Communication between peers is unencrypted.")
47×
192
        } else {
2×
193
                config.Password = []byte(password)
2×
194
                Log.Println("Communication between peers is encrypted.")
2×
195

2×
196
                // fastdp doesn't support encryption
2×
197
                fastDPOverlay = nil
2×
198
        }
2×
199

200
        overlays := weave.NewOverlaySwitch()
49×
201
        if fastDPOverlay != nil {
45×
202
                overlays.Add("fastdp", fastDPOverlay)
45×
203
        }
45×
204
        sleeve := weave.NewSleeveOverlay(config.Port)
49×
205
        overlays.Add("sleeve", sleeve)
49×
206
        overlays.SetCompatOverlay(sleeve)
49×
207

49×
208
        if routerName == "" {
!
209
                if iface == nil {
!
210
                        Log.Fatal("Either an interface must be specified with --iface or a name with -name")
!
211
                }
!
212
                routerName = iface.HardwareAddr.String()
!
213
        }
214

215
        name, err := weave.PeerNameFromUserInput(routerName)
49×
216
        checkFatal(err)
49×
217

49×
218
        if nickName == "" {
!
219
                nickName, err = os.Hostname()
!
220
                checkFatal(err)
!
221
        }
!
222

223
        if prof != "" {
!
224
                p := *profile.CPUProfile
!
225
                p.ProfilePath = prof
!
226
                p.NoShutdownHook = true
!
227
                defer profile.Start(&p).Stop()
!
228
        }
!
229

230
        config.PeerDiscovery = !noDiscovery
49×
231

49×
232
        if pktdebug {
!
NEW
233
                networkConfig.PacketLogging = packetLogging{}
!
234
        } else {
49×
235
                networkConfig.PacketLogging = nopPacketLogging{}
49×
236
        }
49×
237

238
        router := weave.NewNetworkRouter(config, networkConfig, name, nickName, overlays)
49×
239
        Log.Println("Our name is", router.Ourself)
49×
240

49×
241
        var dockerCli *docker.Client
49×
242
        if dockerAPI != "" {
49×
243
                dc, err := docker.NewClient(dockerAPI)
49×
244
                if err != nil {
!
245
                        Log.Fatal("Unable to start docker client: ", err)
!
246
                }
!
247
                dockerCli = dc
49×
248
        }
249
        observeContainers := func(o docker.ContainerObserver) {
95×
250
                if dockerCli != nil {
95×
251
                        if err = dockerCli.AddObserver(o); err != nil {
!
252
                                Log.Fatal("Unable to start watcher", err)
!
253
                        }
!
254
                }
255
        }
256
        isKnownPeer := func(name weave.PeerName) bool {
242×
257
                return router.Peers.Fetch(name) != nil
242×
258
        }
242×
259
        var allocator *ipam.Allocator
49×
260
        var defaultSubnet address.CIDR
49×
261
        if iprangeCIDR != "" {
46×
262
                allocator, defaultSubnet = createAllocator(router.Router, iprangeCIDR, ipsubnetCIDR, determineQuorum(peerCount, peers), isKnownPeer)
46×
263
                observeContainers(allocator)
46×
264
        } else if peerCount > 0 {
!
265
                Log.Fatal("--init-peer-count flag specified without --ipalloc-range")
!
266
        }
!
267

268
        var (
49×
269
                ns        *nameserver.Nameserver
49×
270
                dnsserver *nameserver.DNSServer
49×
271
        )
49×
272
        if !noDNS {
49×
273
                ns = nameserver.New(router.Ourself.Peer.Name, dnsDomain, isKnownPeer)
49×
274
                router.Peers.OnGC(func(peer *weave.Peer) { ns.PeerGone(peer.Name) })
18×
275
                ns.SetGossip(router.NewGossip("nameserver", ns))
49×
276
                observeContainers(ns)
49×
277
                ns.Start()
49×
278
                defer ns.Stop()
49×
279
                dnsserver, err = nameserver.NewDNSServer(ns, dnsDomain, dnsListenAddress,
49×
280
                        dnsEffectiveListenAddress, uint32(dnsTTL), dnsClientTimeout)
49×
281
                if err != nil {
!
282
                        Log.Fatal("Unable to start dns server: ", err)
!
283
                }
!
284
                listenAddr := dnsListenAddress
49×
285
                if dnsEffectiveListenAddress != "" {
49×
286
                        listenAddr = dnsEffectiveListenAddress
49×
287
                }
49×
288
                Log.Println("Listening for DNS queries on", listenAddr)
49×
289
                dnsserver.ActivateAndServe()
49×
290
                defer dnsserver.Stop()
49×
291
        }
292

293
        router.Start()
49×
294
        if errors := router.ConnectionMaker.InitiateConnections(peers, false); len(errors) > 0 {
!
295
                Log.Fatal(ErrorMessages(errors))
!
296
        }
!
297

298
        // The weave script always waits for a status call to succeed,
299
        // so there is no point in doing "weave launch --http-addr ''".
300
        // This is here to support stand-alone use of weaver.
301
        if httpAddr != "" {
49×
302
                muxRouter := mux.NewRouter()
49×
303
                if allocator != nil {
46×
304
                        allocator.HandleHTTP(muxRouter, defaultSubnet, dockerCli)
46×
305
                }
46×
306
                if ns != nil {
49×
307
                        ns.HandleHTTP(muxRouter, dockerCli)
49×
308
                }
49×
309
                router.HandleHTTP(muxRouter)
49×
310
                HandleHTTP(muxRouter, version, router, allocator, defaultSubnet, ns, dnsserver)
49×
311
                http.Handle("/", muxRouter)
49×
312
                Log.Println("Listening for HTTP control messages on", httpAddr)
49×
313
                go listenAndServeHTTP(httpAddr, muxRouter)
49×
314
        }
315

316
        SignalHandlerLoop(router)
49×
317
}
318

319
func options() map[string]string {
49×
320
        options := make(map[string]string)
49×
321
        mflag.Visit(func(f *mflag.Flag) {
450×
322
                value := f.Value.String()
450×
323
                name := canonicalName(f)
450×
324
                if name == "password" {
!
325
                        value = "<elided>"
!
326
                }
!
327
                options[name] = value
450×
328
        })
329
        return options
49×
330
}
331

332
func canonicalName(f *mflag.Flag) string {
450×
333
        for _, n := range f.Names {
907×
334
                if n[0] != '#' {
450×
335
                        return strings.TrimLeft(n, "#-")
450×
336
                }
450×
337
        }
338
        return ""
!
339
}
340

341
type packetLogging struct{}
342

343
func (packetLogging) LogPacket(msg string, key weave.PacketKey) {
!
344
        Log.Println(msg, key.SrcMAC, "->", key.DstMAC)
!
345
}
!
346

347
func (packetLogging) LogForwardPacket(msg string, key weave.ForwardPacketKey) {
!
348
        Log.Println(msg, key.SrcPeer, key.SrcMAC, "->", key.DstPeer, key.DstMAC)
!
349
}
!
350

351
type nopPacketLogging struct{}
352

353
func (nopPacketLogging) LogPacket(string, weave.PacketKey) {
1,382×
354
}
1,382×
355

356
func (nopPacketLogging) LogForwardPacket(string, weave.ForwardPacketKey) {
1,407×
357
}
1,407×
358

359
func parseAndCheckCIDR(cidrStr string) address.CIDR {
48×
360
        _, cidr, err := address.ParseCIDR(cidrStr)
48×
361
        checkFatal(err)
48×
362

48×
363
        if cidr.Size() < ipam.MinSubnetSize {
!
364
                Log.Fatalf("Allocation range smaller than minimum size %d: %s", ipam.MinSubnetSize, cidrStr)
!
365
        }
!
366
        return cidr
48×
367
}
368

369
func createAllocator(router *weave.Router, ipRangeStr string, defaultSubnetStr string, quorum uint, isKnownPeer func(weave.PeerName) bool) (*ipam.Allocator, address.CIDR) {
46×
370
        ipRange := parseAndCheckCIDR(ipRangeStr)
46×
371
        defaultSubnet := ipRange
46×
372
        if defaultSubnetStr != "" {
2×
373
                defaultSubnet = parseAndCheckCIDR(defaultSubnetStr)
2×
374
                if !ipRange.Range().Overlaps(defaultSubnet.Range()) {
!
375
                        Log.Fatalf("IP address allocation default subnet %s does not overlap with allocation range %s", defaultSubnet, ipRange)
!
376
                }
!
377
        }
378
        allocator := ipam.NewAllocator(router.Ourself.Peer.Name, router.Ourself.Peer.UID, router.Ourself.Peer.NickName, ipRange.Range(), quorum, isKnownPeer)
46×
379

46×
380
        allocator.SetInterfaces(router.NewGossip("IPallocation", allocator))
46×
381
        allocator.Start()
46×
382

46×
383
        return allocator, defaultSubnet
46×
384
}
385

386
// Pick a quorum size heuristically based on the number of peer
387
// addresses passed.
388
func determineQuorum(initPeerCountFlag int, peers []string) uint {
46×
389
        if initPeerCountFlag > 0 {
!
390
                return uint(initPeerCountFlag/2 + 1)
!
391
        }
!
392

393
        // Guess a suitable quorum size based on the list of peer
394
        // addresses.  The peer list might or might not contain an
395
        // address for this peer, so the conservative assumption is
396
        // that it doesn't.  The list might contain multiple addresses
397
        // that resolve to the same peer, in which case the quorum
398
        // might be larger than it needs to be.  But the user can
399
        // specify it explicitly if that becomes a problem.
400
        clusterSize := uint(len(peers) + 1)
46×
401
        quorum := clusterSize/2 + 1
46×
402
        Log.Println("Assuming quorum size of", quorum)
46×
403
        return quorum
46×
404
}
405

406
func listenAndServeHTTP(httpAddr string, muxRouter *mux.Router) {
49×
407
        protocol := "tcp"
49×
408
        if strings.HasPrefix(httpAddr, "/") {
!
409
                os.Remove(httpAddr) // in case it's there from last time
!
410
                protocol = "unix"
!
411
        }
!
412
        l, err := net.Listen(protocol, httpAddr)
49×
413
        if err != nil {
!
414
                Log.Fatal("Unable to create http listener socket: ", err)
!
415
        }
!
416
        err = http.Serve(l, nil)
49×
417
        if err != nil {
!
418
                Log.Fatal("Unable to create http server", err)
!
419
        }
!
420
}
421

422
func checkFatal(e error) {
152×
423
        if e != nil {
!
424
                Log.Fatal(e)
!
425
        }
!
426
}
Troubleshooting · Open an Issue · Sales · Support · ENTERPRISE · CAREERS · STATUS
BLOG · TWITTER · Legal & Privacy · Supported CI Services · What's a CI service? · Automated Testing

© 2022 Coveralls, Inc