Fix all golint warnings, mostly by making exported types internal.
Signed-off-by: Arnaud Porterie <arnaud.porterie@docker.com>
| ... | ... |
@@ -7,10 +7,11 @@ import ( |
| 7 | 7 |
) |
| 8 | 8 |
|
| 9 | 9 |
const ( |
| 10 |
- NetworkType = "simplebridge" |
|
| 11 |
- VethPrefix = "veth" |
|
| 10 |
+ networkType = "simplebridge" |
|
| 11 |
+ vethPrefix = "veth" |
|
| 12 | 12 |
) |
| 13 | 13 |
|
| 14 |
+// Configuration info for the "simplebridge" driver. |
|
| 14 | 15 |
type Configuration struct {
|
| 15 | 16 |
BridgeName string |
| 16 | 17 |
AddressIPv4 *net.IPNet |
| ... | ... |
@@ -22,58 +23,59 @@ type Configuration struct {
|
| 22 | 22 |
} |
| 23 | 23 |
|
| 24 | 24 |
func init() {
|
| 25 |
- libnetwork.RegisterNetworkType(NetworkType, Create, &Configuration{})
|
|
| 25 |
+ libnetwork.RegisterNetworkType(networkType, Create, &Configuration{})
|
|
| 26 | 26 |
} |
| 27 | 27 |
|
| 28 |
+// Create a new Network managed by the "simplebridge" driver. |
|
| 28 | 29 |
func Create(name string, config *Configuration) (libnetwork.Network, error) {
|
| 29 |
- bridgeIntfc := NewInterface(config) |
|
| 30 |
- bridgeSetup := NewBridgeSetup(bridgeIntfc) |
|
| 30 |
+ bridgeIntfc := newInterface(config) |
|
| 31 |
+ bridgeSetup := newBridgeSetup(bridgeIntfc) |
|
| 31 | 32 |
|
| 32 | 33 |
// If the bridge interface doesn't exist, we need to start the setup steps |
| 33 | 34 |
// by creating a new device and assigning it an IPv4 address. |
| 34 |
- bridgeAlreadyExists := bridgeIntfc.Exists() |
|
| 35 |
+ bridgeAlreadyExists := bridgeIntfc.exists() |
|
| 35 | 36 |
if !bridgeAlreadyExists {
|
| 36 |
- bridgeSetup.QueueStep(SetupDevice) |
|
| 37 |
- bridgeSetup.QueueStep(SetupBridgeIPv4) |
|
| 37 |
+ bridgeSetup.queueStep(setupDevice) |
|
| 38 |
+ bridgeSetup.queueStep(setupBridgeIPv4) |
|
| 38 | 39 |
} |
| 39 | 40 |
|
| 40 | 41 |
// Conditionnally queue setup steps depending on configuration values. |
| 41 | 42 |
for _, step := range []struct {
|
| 42 | 43 |
Condition bool |
| 43 |
- Fn SetupStep |
|
| 44 |
+ Fn setupStep |
|
| 44 | 45 |
}{
|
| 45 | 46 |
// Enable IPv6 on the bridge if required. We do this even for a |
| 46 | 47 |
// previously existing bridge, as it may be here from a previous |
| 47 | 48 |
// installation where IPv6 wasn't supported yet and needs to be |
| 48 | 49 |
// assigned an IPv6 link-local address. |
| 49 |
- {config.EnableIPv6, SetupBridgeIPv6},
|
|
| 50 |
+ {config.EnableIPv6, setupBridgeIPv6},
|
|
| 50 | 51 |
|
| 51 | 52 |
// We ensure that the bridge has the expectedIPv4 and IPv6 addresses in |
| 52 | 53 |
// the case of a previously existing device. |
| 53 |
- {bridgeAlreadyExists, SetupVerifyConfiguredAddresses},
|
|
| 54 |
+ {bridgeAlreadyExists, setupVerifyConfiguredAddresses},
|
|
| 54 | 55 |
|
| 55 | 56 |
// Setup the bridge to allocate containers IPv4 addresses in the |
| 56 | 57 |
// specified subnet. |
| 57 |
- {config.FixedCIDR != nil, SetupFixedCIDRv4},
|
|
| 58 |
+ {config.FixedCIDR != nil, setupFixedCIDRv4},
|
|
| 58 | 59 |
|
| 59 | 60 |
// Setup the bridge to allocate containers global IPv6 addresses in the |
| 60 | 61 |
// specified subnet. |
| 61 |
- {config.FixedCIDRv6 != nil, SetupFixedCIDRv6},
|
|
| 62 |
+ {config.FixedCIDRv6 != nil, setupFixedCIDRv6},
|
|
| 62 | 63 |
|
| 63 | 64 |
// Setup IPTables. |
| 64 |
- {config.EnableIPTables, SetupIPTables},
|
|
| 65 |
+ {config.EnableIPTables, setupIPTables},
|
|
| 65 | 66 |
|
| 66 | 67 |
// Setup IP forwarding. |
| 67 |
- {config.EnableIPForwarding, SetupIPForwarding},
|
|
| 68 |
+ {config.EnableIPForwarding, setupIPForwarding},
|
|
| 68 | 69 |
} {
|
| 69 | 70 |
if step.Condition {
|
| 70 |
- bridgeSetup.QueueStep(step.Fn) |
|
| 71 |
+ bridgeSetup.queueStep(step.Fn) |
|
| 71 | 72 |
} |
| 72 | 73 |
} |
| 73 | 74 |
|
| 74 | 75 |
// Apply the prepared list of steps, and abort at the first error. |
| 75 |
- bridgeSetup.QueueStep(SetupDeviceUp) |
|
| 76 |
- if err := bridgeSetup.Apply(); err != nil {
|
|
| 76 |
+ bridgeSetup.queueStep(setupDeviceUp) |
|
| 77 |
+ if err := bridgeSetup.apply(); err != nil {
|
|
| 77 | 78 |
return nil, err |
| 78 | 79 |
} |
| 79 | 80 |
|
| ... | ... |
@@ -16,7 +16,7 @@ func TestCreate(t *testing.T) {
|
| 16 | 16 |
t.Fatalf("Failed to create bridge: %v", err)
|
| 17 | 17 |
} |
| 18 | 18 |
|
| 19 |
- if expected := NetworkType; netw.Type() != NetworkType {
|
|
| 19 |
+ if expected := networkType; netw.Type() != expected {
|
|
| 20 | 20 |
t.Fatalf("Expected networkType %q, got %q", expected, netw.Type())
|
| 21 | 21 |
} |
| 22 | 22 |
} |
| ... | ... |
@@ -47,7 +47,7 @@ func TestCreateFullOptions(t *testing.T) {
|
| 47 | 47 |
t.Fatalf("Failed to create bridge: %v", err)
|
| 48 | 48 |
} |
| 49 | 49 |
|
| 50 |
- if expected := NetworkType; netw.Type() != NetworkType {
|
|
| 50 |
+ if expected := networkType; netw.Type() != expected {
|
|
| 51 | 51 |
t.Fatalf("Expected networkType %q, got %q", expected, netw.Type())
|
| 52 | 52 |
} |
| 53 | 53 |
} |
| ... | ... |
@@ -3,16 +3,23 @@ package bridge |
| 3 | 3 |
import "github.com/vishvananda/netlink" |
| 4 | 4 |
|
| 5 | 5 |
const ( |
| 6 |
+ // DefaultBridgeName is the default name for the bridge interface managed |
|
| 7 |
+ // by the driver when unspecified by the caller. |
|
| 6 | 8 |
DefaultBridgeName = "docker0" |
| 7 | 9 |
) |
| 8 | 10 |
|
| 9 |
-type Interface struct {
|
|
| 11 |
+// Interface models the bridge network device. |
|
| 12 |
+type bridgeInterface struct {
|
|
| 10 | 13 |
Config *Configuration |
| 11 | 14 |
Link netlink.Link |
| 12 | 15 |
} |
| 13 | 16 |
|
| 14 |
-func NewInterface(config *Configuration) *Interface {
|
|
| 15 |
- i := &Interface{
|
|
| 17 |
+// NewInterface creates a new bridge interface structure. It attempts to find |
|
| 18 |
+// an already existing device identified by the Configuration BridgeName field, |
|
| 19 |
+// or the default bridge name when unspecified), but doesn't attempt to create |
|
| 20 |
+// on when missing |
|
| 21 |
+func newInterface(config *Configuration) *bridgeInterface {
|
|
| 22 |
+ i := &bridgeInterface{
|
|
| 16 | 23 |
Config: config, |
| 17 | 24 |
} |
| 18 | 25 |
|
| ... | ... |
@@ -27,13 +34,13 @@ func NewInterface(config *Configuration) *Interface {
|
| 27 | 27 |
} |
| 28 | 28 |
|
| 29 | 29 |
// Exists indicates if the existing bridge interface exists on the system. |
| 30 |
-func (i *Interface) Exists() bool {
|
|
| 30 |
+func (i *bridgeInterface) exists() bool {
|
|
| 31 | 31 |
return i.Link != nil |
| 32 | 32 |
} |
| 33 | 33 |
|
| 34 | 34 |
// Addresses returns a single IPv4 address and all IPv6 addresses for the |
| 35 | 35 |
// bridge interface. |
| 36 |
-func (i *Interface) Addresses() (netlink.Addr, []netlink.Addr, error) {
|
|
| 36 |
+func (i *bridgeInterface) addresses() (netlink.Addr, []netlink.Addr, error) {
|
|
| 37 | 37 |
v4addr, err := netlink.AddrList(i.Link, netlink.FAMILY_V4) |
| 38 | 38 |
if err != nil {
|
| 39 | 39 |
return netlink.Addr{}, nil, err
|
| ... | ... |
@@ -10,7 +10,7 @@ import ( |
| 10 | 10 |
func TestInterfaceDefaultName(t *testing.T) {
|
| 11 | 11 |
defer libnetwork.SetupTestNetNS(t)() |
| 12 | 12 |
|
| 13 |
- if inf := NewInterface(&Configuration{}); inf.Config.BridgeName != DefaultBridgeName {
|
|
| 13 |
+ if inf := newInterface(&Configuration{}); inf.Config.BridgeName != DefaultBridgeName {
|
|
| 14 | 14 |
t.Fatalf("Expected default interface name %q, got %q", DefaultBridgeName, inf.Config.BridgeName)
|
| 15 | 15 |
} |
| 16 | 16 |
} |
| ... | ... |
@@ -18,8 +18,8 @@ func TestInterfaceDefaultName(t *testing.T) {
|
| 18 | 18 |
func TestAddressesEmptyInterface(t *testing.T) {
|
| 19 | 19 |
defer libnetwork.SetupTestNetNS(t)() |
| 20 | 20 |
|
| 21 |
- inf := NewInterface(&Configuration{})
|
|
| 22 |
- addrv4, addrsv6, err := inf.Addresses() |
|
| 21 |
+ inf := newInterface(&Configuration{})
|
|
| 22 |
+ addrv4, addrsv6, err := inf.addresses() |
|
| 23 | 23 |
if err != nil {
|
| 24 | 24 |
t.Fatalf("Failed to get addresses of default interface: %v", err)
|
| 25 | 25 |
} |
| ... | ... |
@@ -1,17 +1,17 @@ |
| 1 | 1 |
package bridge |
| 2 | 2 |
|
| 3 |
-type SetupStep func(*Interface) error |
|
| 3 |
+type setupStep func(*bridgeInterface) error |
|
| 4 | 4 |
|
| 5 |
-type BridgeSetup struct {
|
|
| 6 |
- bridge *Interface |
|
| 7 |
- steps []SetupStep |
|
| 5 |
+type bridgeSetup struct {
|
|
| 6 |
+ bridge *bridgeInterface |
|
| 7 |
+ steps []setupStep |
|
| 8 | 8 |
} |
| 9 | 9 |
|
| 10 |
-func NewBridgeSetup(i *Interface) *BridgeSetup {
|
|
| 11 |
- return &BridgeSetup{bridge: i}
|
|
| 10 |
+func newBridgeSetup(i *bridgeInterface) *bridgeSetup {
|
|
| 11 |
+ return &bridgeSetup{bridge: i}
|
|
| 12 | 12 |
} |
| 13 | 13 |
|
| 14 |
-func (b *BridgeSetup) Apply() error {
|
|
| 14 |
+func (b *bridgeSetup) apply() error {
|
|
| 15 | 15 |
for _, fn := range b.steps {
|
| 16 | 16 |
if err := fn(b.bridge); err != nil {
|
| 17 | 17 |
return err |
| ... | ... |
@@ -20,12 +20,12 @@ func (b *BridgeSetup) Apply() error {
|
| 20 | 20 |
return nil |
| 21 | 21 |
} |
| 22 | 22 |
|
| 23 |
-func (b *BridgeSetup) QueueStep(step SetupStep) {
|
|
| 23 |
+func (b *bridgeSetup) queueStep(step setupStep) {
|
|
| 24 | 24 |
b.steps = append(b.steps, step) |
| 25 | 25 |
} |
| 26 | 26 |
|
| 27 | 27 |
//---------------------------------------------------------------------------// |
| 28 | 28 |
|
| 29 |
-func SetupIPTables(i *Interface) error {
|
|
| 29 |
+func setupIPTables(i *bridgeInterface) error {
|
|
| 30 | 30 |
return nil |
| 31 | 31 |
} |
| ... | ... |
@@ -11,14 +11,14 @@ import ( |
| 11 | 11 |
) |
| 12 | 12 |
|
| 13 | 13 |
// SetupDevice create a new bridge interface/ |
| 14 |
-func SetupDevice(i *Interface) error {
|
|
| 14 |
+func setupDevice(i *bridgeInterface) error {
|
|
| 15 | 15 |
// We only attempt to create the bridge when the requested device name is |
| 16 | 16 |
// the default one. |
| 17 | 17 |
if i.Config.BridgeName != DefaultBridgeName {
|
| 18 | 18 |
return fmt.Errorf("bridge device with non default name %q must be created manually", i.Config.BridgeName)
|
| 19 | 19 |
} |
| 20 | 20 |
|
| 21 |
- // Set the Interface netlink.Bridge. |
|
| 21 |
+ // Set the bridgeInterface netlink.Bridge. |
|
| 22 | 22 |
i.Link = &netlink.Bridge{
|
| 23 | 23 |
LinkAttrs: netlink.LinkAttrs{
|
| 24 | 24 |
Name: i.Config.BridgeName, |
| ... | ... |
@@ -38,7 +38,7 @@ func SetupDevice(i *Interface) error {
|
| 38 | 38 |
} |
| 39 | 39 |
|
| 40 | 40 |
// SetupDeviceUp ups the given bridge interface. |
| 41 |
-func SetupDeviceUp(i *Interface) error {
|
|
| 41 |
+func setupDeviceUp(i *bridgeInterface) error {
|
|
| 42 | 42 |
err := netlink.LinkSetUp(i.Link) |
| 43 | 43 |
if err != nil {
|
| 44 | 44 |
return err |
| ... | ... |
@@ -13,34 +13,34 @@ import ( |
| 13 | 13 |
func TestSetupNewBridge(t *testing.T) {
|
| 14 | 14 |
defer libnetwork.SetupTestNetNS(t)() |
| 15 | 15 |
|
| 16 |
- br := &Interface{
|
|
| 16 |
+ br := &bridgeInterface{
|
|
| 17 | 17 |
Config: &Configuration{
|
| 18 | 18 |
BridgeName: DefaultBridgeName, |
| 19 | 19 |
}, |
| 20 | 20 |
} |
| 21 |
- if err := SetupDevice(br); err != nil {
|
|
| 21 |
+ if err := setupDevice(br); err != nil {
|
|
| 22 | 22 |
t.Fatalf("Bridge creation failed: %v", err)
|
| 23 | 23 |
} |
| 24 | 24 |
if br.Link == nil {
|
| 25 |
- t.Fatal("Interface link is nil (expected valid link)")
|
|
| 25 |
+ t.Fatal("bridgeInterface link is nil (expected valid link)")
|
|
| 26 | 26 |
} |
| 27 | 27 |
if _, err := netlink.LinkByName(DefaultBridgeName); err != nil {
|
| 28 | 28 |
t.Fatalf("Failed to retrieve bridge device: %v", err)
|
| 29 | 29 |
} |
| 30 | 30 |
if br.Link.Attrs().Flags&net.FlagUp == net.FlagUp {
|
| 31 |
- t.Fatalf("Interface should be created down")
|
|
| 31 |
+ t.Fatalf("bridgeInterface should be created down")
|
|
| 32 | 32 |
} |
| 33 | 33 |
} |
| 34 | 34 |
|
| 35 | 35 |
func TestSetupNewNonDefaultBridge(t *testing.T) {
|
| 36 | 36 |
defer libnetwork.SetupTestNetNS(t)() |
| 37 | 37 |
|
| 38 |
- br := &Interface{
|
|
| 38 |
+ br := &bridgeInterface{
|
|
| 39 | 39 |
Config: &Configuration{
|
| 40 | 40 |
BridgeName: "test0", |
| 41 | 41 |
}, |
| 42 | 42 |
} |
| 43 |
- if err := SetupDevice(br); err == nil || !strings.Contains(err.Error(), "non default name") {
|
|
| 43 |
+ if err := setupDevice(br); err == nil || !strings.Contains(err.Error(), "non default name") {
|
|
| 44 | 44 |
t.Fatalf("Expected bridge creation failure with \"non default name\", got: %v", err)
|
| 45 | 45 |
} |
| 46 | 46 |
} |
| ... | ... |
@@ -48,21 +48,21 @@ func TestSetupNewNonDefaultBridge(t *testing.T) {
|
| 48 | 48 |
func TestSetupDeviceUp(t *testing.T) {
|
| 49 | 49 |
defer libnetwork.SetupTestNetNS(t)() |
| 50 | 50 |
|
| 51 |
- br := &Interface{
|
|
| 51 |
+ br := &bridgeInterface{
|
|
| 52 | 52 |
Config: &Configuration{
|
| 53 | 53 |
BridgeName: DefaultBridgeName, |
| 54 | 54 |
}, |
| 55 | 55 |
} |
| 56 |
- if err := SetupDevice(br); err != nil {
|
|
| 56 |
+ if err := setupDevice(br); err != nil {
|
|
| 57 | 57 |
t.Fatalf("Bridge creation failed: %v", err)
|
| 58 | 58 |
} |
| 59 |
- if err := SetupDeviceUp(br); err != nil {
|
|
| 59 |
+ if err := setupDeviceUp(br); err != nil {
|
|
| 60 | 60 |
t.Fatalf("Failed to up bridge device: %v", err)
|
| 61 | 61 |
} |
| 62 | 62 |
|
| 63 | 63 |
lnk, _ := netlink.LinkByName(DefaultBridgeName) |
| 64 | 64 |
if lnk.Attrs().Flags&net.FlagUp != net.FlagUp {
|
| 65 |
- t.Fatalf("Interface should be up")
|
|
| 65 |
+ t.Fatalf("bridgeInterface should be up")
|
|
| 66 | 66 |
} |
| 67 | 67 |
} |
| 68 | 68 |
|
| ... | ... |
@@ -7,8 +7,8 @@ import ( |
| 7 | 7 |
"github.com/docker/docker/daemon/networkdriver/ipallocator" |
| 8 | 8 |
) |
| 9 | 9 |
|
| 10 |
-func SetupFixedCIDRv4(i *Interface) error {
|
|
| 11 |
- addrv4, _, err := i.Addresses() |
|
| 10 |
+func setupFixedCIDRv4(i *bridgeInterface) error {
|
|
| 11 |
+ addrv4, _, err := i.addresses() |
|
| 12 | 12 |
if err != nil {
|
| 13 | 13 |
return err |
| 14 | 14 |
} |
| ... | ... |
@@ -11,21 +11,21 @@ import ( |
| 11 | 11 |
func TestSetupFixedCIDRv4(t *testing.T) {
|
| 12 | 12 |
defer libnetwork.SetupTestNetNS(t)() |
| 13 | 13 |
|
| 14 |
- br := &Interface{
|
|
| 14 |
+ br := &bridgeInterface{
|
|
| 15 | 15 |
Config: &Configuration{
|
| 16 | 16 |
BridgeName: DefaultBridgeName, |
| 17 | 17 |
AddressIPv4: &net.IPNet{IP: net.ParseIP("192.168.1.1"), Mask: net.CIDRMask(16, 32)},
|
| 18 | 18 |
FixedCIDR: &net.IPNet{IP: net.ParseIP("192.168.2.0"), Mask: net.CIDRMask(24, 32)},
|
| 19 | 19 |
}, |
| 20 | 20 |
} |
| 21 |
- if err := SetupDevice(br); err != nil {
|
|
| 21 |
+ if err := setupDevice(br); err != nil {
|
|
| 22 | 22 |
t.Fatalf("Bridge creation failed: %v", err)
|
| 23 | 23 |
} |
| 24 |
- if err := SetupBridgeIPv4(br); err != nil {
|
|
| 24 |
+ if err := setupBridgeIPv4(br); err != nil {
|
|
| 25 | 25 |
t.Fatalf("Assign IPv4 to bridge failed: %v", err)
|
| 26 | 26 |
} |
| 27 | 27 |
|
| 28 |
- if err := SetupFixedCIDRv4(br); err != nil {
|
|
| 28 |
+ if err := setupFixedCIDRv4(br); err != nil {
|
|
| 29 | 29 |
t.Fatalf("Failed to setup bridge FixedCIDRv4: %v", err)
|
| 30 | 30 |
} |
| 31 | 31 |
|
| ... | ... |
@@ -39,21 +39,21 @@ func TestSetupFixedCIDRv4(t *testing.T) {
|
| 39 | 39 |
func TestSetupBadFixedCIDRv4(t *testing.T) {
|
| 40 | 40 |
defer libnetwork.SetupTestNetNS(t)() |
| 41 | 41 |
|
| 42 |
- br := &Interface{
|
|
| 42 |
+ br := &bridgeInterface{
|
|
| 43 | 43 |
Config: &Configuration{
|
| 44 | 44 |
BridgeName: DefaultBridgeName, |
| 45 | 45 |
AddressIPv4: &net.IPNet{IP: net.ParseIP("192.168.1.1"), Mask: net.CIDRMask(24, 32)},
|
| 46 | 46 |
FixedCIDR: &net.IPNet{IP: net.ParseIP("192.168.2.0"), Mask: net.CIDRMask(24, 32)},
|
| 47 | 47 |
}, |
| 48 | 48 |
} |
| 49 |
- if err := SetupDevice(br); err != nil {
|
|
| 49 |
+ if err := setupDevice(br); err != nil {
|
|
| 50 | 50 |
t.Fatalf("Bridge creation failed: %v", err)
|
| 51 | 51 |
} |
| 52 |
- if err := SetupBridgeIPv4(br); err != nil {
|
|
| 52 |
+ if err := setupBridgeIPv4(br); err != nil {
|
|
| 53 | 53 |
t.Fatalf("Assign IPv4 to bridge failed: %v", err)
|
| 54 | 54 |
} |
| 55 | 55 |
|
| 56 |
- if err := SetupFixedCIDRv4(br); err == nil {
|
|
| 56 |
+ if err := setupFixedCIDRv4(br); err == nil {
|
|
| 57 | 57 |
t.Fatal("Setup bridge FixedCIDRv4 should have failed")
|
| 58 | 58 |
} |
| 59 | 59 |
} |
| ... | ... |
@@ -7,7 +7,7 @@ import ( |
| 7 | 7 |
"github.com/docker/docker/daemon/networkdriver/ipallocator" |
| 8 | 8 |
) |
| 9 | 9 |
|
| 10 |
-func SetupFixedCIDRv6(i *Interface) error {
|
|
| 10 |
+func setupFixedCIDRv6(i *bridgeInterface) error {
|
|
| 11 | 11 |
log.Debugf("Using IPv6 subnet: %v", i.Config.FixedCIDRv6)
|
| 12 | 12 |
if err := ipallocator.RegisterSubnet(i.Config.FixedCIDRv6, i.Config.FixedCIDRv6); err != nil {
|
| 13 | 13 |
return fmt.Errorf("Setup FixedCIDRv6 failed for subnet %s in %s: %v", i.Config.FixedCIDRv6, i.Config.FixedCIDRv6, err)
|
| ... | ... |
@@ -11,21 +11,21 @@ import ( |
| 11 | 11 |
func TestSetupFixedCIDRv6(t *testing.T) {
|
| 12 | 12 |
defer libnetwork.SetupTestNetNS(t)() |
| 13 | 13 |
|
| 14 |
- br := NewInterface(&Configuration{})
|
|
| 14 |
+ br := newInterface(&Configuration{})
|
|
| 15 | 15 |
|
| 16 | 16 |
_, br.Config.FixedCIDRv6, _ = net.ParseCIDR("2002:db8::/48")
|
| 17 |
- if err := SetupDevice(br); err != nil {
|
|
| 17 |
+ if err := setupDevice(br); err != nil {
|
|
| 18 | 18 |
t.Fatalf("Bridge creation failed: %v", err)
|
| 19 | 19 |
} |
| 20 |
- if err := SetupBridgeIPv4(br); err != nil {
|
|
| 20 |
+ if err := setupBridgeIPv4(br); err != nil {
|
|
| 21 | 21 |
t.Fatalf("Assign IPv4 to bridge failed: %v", err)
|
| 22 | 22 |
} |
| 23 | 23 |
|
| 24 |
- if err := SetupBridgeIPv6(br); err != nil {
|
|
| 24 |
+ if err := setupBridgeIPv6(br); err != nil {
|
|
| 25 | 25 |
t.Fatalf("Assign IPv4 to bridge failed: %v", err)
|
| 26 | 26 |
} |
| 27 | 27 |
|
| 28 |
- if err := SetupFixedCIDRv6(br); err != nil {
|
|
| 28 |
+ if err := setupFixedCIDRv6(br); err != nil {
|
|
| 29 | 29 |
t.Fatalf("Failed to setup bridge FixedCIDRv6: %v", err)
|
| 30 | 30 |
} |
| 31 | 31 |
|
| ... | ... |
@@ -6,18 +6,18 @@ import ( |
| 6 | 6 |
) |
| 7 | 7 |
|
| 8 | 8 |
const ( |
| 9 |
- IPV4_FORW_CONF_FILE = "/proc/sys/net/ipv4/ip_forward" |
|
| 10 |
- PERM = 0644 |
|
| 9 |
+ ipv4ForwardConf = "/proc/sys/net/ipv4/ip_forward" |
|
| 10 |
+ ipv4ForwardConfPerm = 0644 |
|
| 11 | 11 |
) |
| 12 | 12 |
|
| 13 |
-func SetupIPForwarding(i *Interface) error {
|
|
| 13 |
+func setupIPForwarding(i *bridgeInterface) error {
|
|
| 14 | 14 |
// Sanity Check |
| 15 | 15 |
if i.Config.EnableIPForwarding == false {
|
| 16 | 16 |
return fmt.Errorf("Unexpected request to enable IP Forwarding for: %v", *i)
|
| 17 | 17 |
} |
| 18 | 18 |
|
| 19 | 19 |
// Enable IPv4 forwarding |
| 20 |
- if err := ioutil.WriteFile(IPV4_FORW_CONF_FILE, []byte{'1', '\n'}, PERM); err != nil {
|
|
| 20 |
+ if err := ioutil.WriteFile(ipv4ForwardConf, []byte{'1', '\n'}, ipv4ForwardConfPerm); err != nil {
|
|
| 21 | 21 |
return fmt.Errorf("Setup IP forwarding failed: %v", err)
|
| 22 | 22 |
} |
| 23 | 23 |
|
| ... | ... |
@@ -18,7 +18,7 @@ func TestSetupIPForwarding(t *testing.T) {
|
| 18 | 18 |
} |
| 19 | 19 |
|
| 20 | 20 |
// Create test interface with ip forwarding setting enabled |
| 21 |
- br := &Interface{
|
|
| 21 |
+ br := &bridgeInterface{
|
|
| 22 | 22 |
Config: &Configuration{
|
| 23 | 23 |
BridgeName: DefaultBridgeName, |
| 24 | 24 |
EnableIPForwarding: true, |
| ... | ... |
@@ -26,7 +26,7 @@ func TestSetupIPForwarding(t *testing.T) {
|
| 26 | 26 |
} |
| 27 | 27 |
|
| 28 | 28 |
// Set IP Forwarding |
| 29 |
- if err := SetupIPForwarding(br); err != nil {
|
|
| 29 |
+ if err := setupIPForwarding(br); err != nil {
|
|
| 30 | 30 |
t.Fatalf("Failed to setup IP forwarding: %v", err)
|
| 31 | 31 |
} |
| 32 | 32 |
|
| ... | ... |
@@ -43,7 +43,7 @@ func TestUnexpectedSetupIPForwarding(t *testing.T) {
|
| 43 | 43 |
defer reconcileIPForwardingSetting(t, procSetting) |
| 44 | 44 |
|
| 45 | 45 |
// Create test interface without ip forwarding setting enabled |
| 46 |
- br := &Interface{
|
|
| 46 |
+ br := &bridgeInterface{
|
|
| 47 | 47 |
Config: &Configuration{
|
| 48 | 48 |
BridgeName: DefaultBridgeName, |
| 49 | 49 |
EnableIPForwarding: false, |
| ... | ... |
@@ -51,7 +51,7 @@ func TestUnexpectedSetupIPForwarding(t *testing.T) {
|
| 51 | 51 |
} |
| 52 | 52 |
|
| 53 | 53 |
// Attempt Set IP Forwarding |
| 54 |
- if err := SetupIPForwarding(br); err == nil {
|
|
| 54 |
+ if err := setupIPForwarding(br); err == nil {
|
|
| 55 | 55 |
t.Fatal("Setup IP forwarding was expected to fail")
|
| 56 | 56 |
} else if !strings.Contains(err.Error(), "Unexpected request") {
|
| 57 | 57 |
t.Fatalf("Setup IP forwarding failed with unexpected error: %v", err)
|
| ... | ... |
@@ -59,7 +59,7 @@ func TestUnexpectedSetupIPForwarding(t *testing.T) {
|
| 59 | 59 |
} |
| 60 | 60 |
|
| 61 | 61 |
func readCurrentIPForwardingSetting(t *testing.T) []byte {
|
| 62 |
- procSetting, err := ioutil.ReadFile(IPV4_FORW_CONF_FILE) |
|
| 62 |
+ procSetting, err := ioutil.ReadFile(ipv4ForwardConf) |
|
| 63 | 63 |
if err != nil {
|
| 64 | 64 |
t.Fatalf("Can't execute test: Failed to read current IP forwarding setting: %v", err)
|
| 65 | 65 |
} |
| ... | ... |
@@ -67,7 +67,7 @@ func readCurrentIPForwardingSetting(t *testing.T) []byte {
|
| 67 | 67 |
} |
| 68 | 68 |
|
| 69 | 69 |
func writeIPForwardingSetting(t *testing.T, chars []byte) {
|
| 70 |
- err := ioutil.WriteFile(IPV4_FORW_CONF_FILE, chars, PERM) |
|
| 70 |
+ err := ioutil.WriteFile(ipv4ForwardConf, chars, ipv4ForwardConfPerm) |
|
| 71 | 71 |
if err != nil {
|
| 72 | 72 |
t.Fatalf("Can't execute or cleanup after test: Failed to reset IP forwarding: %v", err)
|
| 73 | 73 |
} |
| ... | ... |
@@ -8,13 +8,13 @@ import ( |
| 8 | 8 |
"github.com/vishvananda/netlink" |
| 9 | 9 |
) |
| 10 | 10 |
|
| 11 |
-func setupTestInterface(t *testing.T) *Interface {
|
|
| 12 |
- br := &Interface{
|
|
| 11 |
+func setupTestInterface(t *testing.T) *bridgeInterface {
|
|
| 12 |
+ br := &bridgeInterface{
|
|
| 13 | 13 |
Config: &Configuration{
|
| 14 | 14 |
BridgeName: DefaultBridgeName, |
| 15 | 15 |
}, |
| 16 | 16 |
} |
| 17 |
- if err := SetupDevice(br); err != nil {
|
|
| 17 |
+ if err := setupDevice(br); err != nil {
|
|
| 18 | 18 |
t.Fatalf("Bridge creation failed: %v", err)
|
| 19 | 19 |
} |
| 20 | 20 |
return br |
| ... | ... |
@@ -30,7 +30,7 @@ func TestSetupBridgeIPv4Fixed(t *testing.T) {
|
| 30 | 30 |
|
| 31 | 31 |
br := setupTestInterface(t) |
| 32 | 32 |
br.Config.AddressIPv4 = &net.IPNet{IP: ip, Mask: netw.Mask}
|
| 33 |
- if err := SetupBridgeIPv4(br); err != nil {
|
|
| 33 |
+ if err := setupBridgeIPv4(br); err != nil {
|
|
| 34 | 34 |
t.Fatalf("Failed to setup bridge IPv4: %v", err)
|
| 35 | 35 |
} |
| 36 | 36 |
|
| ... | ... |
@@ -56,7 +56,7 @@ func TestSetupBridgeIPv4Auto(t *testing.T) {
|
| 56 | 56 |
defer libnetwork.SetupTestNetNS(t)() |
| 57 | 57 |
|
| 58 | 58 |
br := setupTestInterface(t) |
| 59 |
- if err := SetupBridgeIPv4(br); err != nil {
|
|
| 59 |
+ if err := setupBridgeIPv4(br); err != nil {
|
|
| 60 | 60 |
t.Fatalf("Failed to setup bridge IPv4: %v", err)
|
| 61 | 61 |
} |
| 62 | 62 |
|
| ... | ... |
@@ -8,29 +8,29 @@ import ( |
| 8 | 8 |
"github.com/vishvananda/netlink" |
| 9 | 9 |
) |
| 10 | 10 |
|
| 11 |
-var BridgeIPv6 *net.IPNet |
|
| 11 |
+var bridgeIPv6 *net.IPNet |
|
| 12 | 12 |
|
| 13 |
-const BridgeIPv6Str = "fe80::1/64" |
|
| 13 |
+const bridgeIPv6Str = "fe80::1/64" |
|
| 14 | 14 |
|
| 15 | 15 |
func init() {
|
| 16 | 16 |
// We allow ourselves to panic in this special case because we indicate a |
| 17 | 17 |
// failure to parse a compile-time define constant. |
| 18 |
- if ip, netw, err := net.ParseCIDR(BridgeIPv6Str); err == nil {
|
|
| 19 |
- BridgeIPv6 = &net.IPNet{IP: ip, Mask: netw.Mask}
|
|
| 18 |
+ if ip, netw, err := net.ParseCIDR(bridgeIPv6Str); err == nil {
|
|
| 19 |
+ bridgeIPv6 = &net.IPNet{IP: ip, Mask: netw.Mask}
|
|
| 20 | 20 |
} else {
|
| 21 |
- panic(fmt.Sprintf("Cannot parse default bridge IPv6 address %q: %v", BridgeIPv6Str, err))
|
|
| 21 |
+ panic(fmt.Sprintf("Cannot parse default bridge IPv6 address %q: %v", bridgeIPv6Str, err))
|
|
| 22 | 22 |
} |
| 23 | 23 |
} |
| 24 | 24 |
|
| 25 |
-func SetupBridgeIPv6(i *Interface) error {
|
|
| 25 |
+func setupBridgeIPv6(i *bridgeInterface) error {
|
|
| 26 | 26 |
// Enable IPv6 on the bridge |
| 27 | 27 |
procFile := "/proc/sys/net/ipv6/conf/" + i.Config.BridgeName + "/disable_ipv6" |
| 28 | 28 |
if err := ioutil.WriteFile(procFile, []byte{'0', '\n'}, 0644); err != nil {
|
| 29 | 29 |
return fmt.Errorf("Unable to enable IPv6 addresses on bridge: %v", err)
|
| 30 | 30 |
} |
| 31 | 31 |
|
| 32 |
- if err := netlink.AddrAdd(i.Link, &netlink.Addr{BridgeIPv6, ""}); err != nil {
|
|
| 33 |
- return fmt.Errorf("Failed to add IPv6 address %s to bridge: %v", BridgeIPv6, err)
|
|
| 32 |
+ if err := netlink.AddrAdd(i.Link, &netlink.Addr{bridgeIPv6, ""}); err != nil {
|
|
| 33 |
+ return fmt.Errorf("Failed to add IPv6 address %s to bridge: %v", bridgeIPv6, err)
|
|
| 34 | 34 |
} |
| 35 | 35 |
|
| 36 | 36 |
return nil |
| ... | ... |
@@ -14,7 +14,7 @@ func TestSetupIPv6(t *testing.T) {
|
| 14 | 14 |
defer libnetwork.SetupTestNetNS(t)() |
| 15 | 15 |
|
| 16 | 16 |
br := setupTestInterface(t) |
| 17 |
- if err := SetupBridgeIPv6(br); err != nil {
|
|
| 17 |
+ if err := setupBridgeIPv6(br); err != nil {
|
|
| 18 | 18 |
t.Fatalf("Failed to setup bridge IPv6: %v", err)
|
| 19 | 19 |
} |
| 20 | 20 |
|
| ... | ... |
@@ -34,14 +34,14 @@ func TestSetupIPv6(t *testing.T) {
|
| 34 | 34 |
|
| 35 | 35 |
var found bool |
| 36 | 36 |
for _, addr := range addrsv6 {
|
| 37 |
- if BridgeIPv6Str == addr.IPNet.String() {
|
|
| 37 |
+ if bridgeIPv6Str == addr.IPNet.String() {
|
|
| 38 | 38 |
found = true |
| 39 | 39 |
break |
| 40 | 40 |
} |
| 41 | 41 |
} |
| 42 | 42 |
|
| 43 | 43 |
if !found {
|
| 44 |
- t.Fatalf("Bridge device does not have requested IPv6 address %v", BridgeIPv6Str)
|
|
| 44 |
+ t.Fatalf("Bridge device does not have requested IPv6 address %v", bridgeIPv6Str)
|
|
| 45 | 45 |
} |
| 46 | 46 |
|
| 47 | 47 |
} |
| ... | ... |
@@ -6,9 +6,9 @@ import ( |
| 6 | 6 |
"github.com/vishvananda/netlink" |
| 7 | 7 |
) |
| 8 | 8 |
|
| 9 |
-func SetupVerifyConfiguredAddresses(i *Interface) error {
|
|
| 9 |
+func setupVerifyConfiguredAddresses(i *bridgeInterface) error {
|
|
| 10 | 10 |
// Fetch a single IPv4 and a slice of IPv6 addresses from the bridge. |
| 11 |
- addrv4, addrsv6, err := i.Addresses() |
|
| 11 |
+ addrv4, addrsv6, err := i.addresses() |
|
| 12 | 12 |
if err != nil {
|
| 13 | 13 |
return err |
| 14 | 14 |
} |
| ... | ... |
@@ -25,8 +25,8 @@ func SetupVerifyConfiguredAddresses(i *Interface) error {
|
| 25 | 25 |
|
| 26 | 26 |
// Verify that one of the bridge IPv6 addresses matches the requested |
| 27 | 27 |
// configuration. |
| 28 |
- if i.Config.EnableIPv6 && !findIPv6Address(netlink.Addr{IPNet: BridgeIPv6}, addrsv6) {
|
|
| 29 |
- return fmt.Errorf("Bridge IPv6 addresses do not match the expected bridge configuration %s", BridgeIPv6)
|
|
| 28 |
+ if i.Config.EnableIPv6 && !findIPv6Address(netlink.Addr{IPNet: bridgeIPv6}, addrsv6) {
|
|
| 29 |
+ return fmt.Errorf("Bridge IPv6 addresses do not match the expected bridge configuration %s", bridgeIPv6)
|
|
| 30 | 30 |
} |
| 31 | 31 |
|
| 32 | 32 |
return nil |
| ... | ... |
@@ -8,8 +8,8 @@ import ( |
| 8 | 8 |
"github.com/vishvananda/netlink" |
| 9 | 9 |
) |
| 10 | 10 |
|
| 11 |
-func setupVerifyTest(t *testing.T) *Interface {
|
|
| 12 |
- inf := &Interface{Config: &Configuration{}}
|
|
| 11 |
+func setupVerifyTest(t *testing.T) *bridgeInterface {
|
|
| 12 |
+ inf := &bridgeInterface{Config: &Configuration{}}
|
|
| 13 | 13 |
|
| 14 | 14 |
br := netlink.Bridge{}
|
| 15 | 15 |
br.LinkAttrs.Name = "default0" |
| ... | ... |
@@ -33,7 +33,7 @@ func TestSetupVerify(t *testing.T) {
|
| 33 | 33 |
t.Fatalf("Failed to assign IPv4 %s to interface: %v", inf.Config.AddressIPv4, err)
|
| 34 | 34 |
} |
| 35 | 35 |
|
| 36 |
- if err := SetupVerifyConfiguredAddresses(inf); err != nil {
|
|
| 36 |
+ if err := setupVerifyConfiguredAddresses(inf); err != nil {
|
|
| 37 | 37 |
t.Fatalf("Address verification failed: %v", err)
|
| 38 | 38 |
} |
| 39 | 39 |
} |
| ... | ... |
@@ -50,7 +50,7 @@ func TestSetupVerifyBad(t *testing.T) {
|
| 50 | 50 |
t.Fatalf("Failed to assign IPv4 %s to interface: %v", ipnet, err)
|
| 51 | 51 |
} |
| 52 | 52 |
|
| 53 |
- if err := SetupVerifyConfiguredAddresses(inf); err == nil {
|
|
| 53 |
+ if err := setupVerifyConfiguredAddresses(inf); err == nil {
|
|
| 54 | 54 |
t.Fatal("Address verification was expected to fail")
|
| 55 | 55 |
} |
| 56 | 56 |
} |
| ... | ... |
@@ -62,7 +62,7 @@ func TestSetupVerifyMissing(t *testing.T) {
|
| 62 | 62 |
inf := setupVerifyTest(t) |
| 63 | 63 |
inf.Config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
|
| 64 | 64 |
|
| 65 |
- if err := SetupVerifyConfiguredAddresses(inf); err == nil {
|
|
| 65 |
+ if err := setupVerifyConfiguredAddresses(inf); err == nil {
|
|
| 66 | 66 |
t.Fatal("Address verification was expected to fail")
|
| 67 | 67 |
} |
| 68 | 68 |
} |
| ... | ... |
@@ -75,14 +75,14 @@ func TestSetupVerifyIPv6(t *testing.T) {
|
| 75 | 75 |
inf.Config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
|
| 76 | 76 |
inf.Config.EnableIPv6 = true |
| 77 | 77 |
|
| 78 |
- if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: BridgeIPv6}); err != nil {
|
|
| 79 |
- t.Fatalf("Failed to assign IPv6 %s to interface: %v", BridgeIPv6, err)
|
|
| 78 |
+ if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: bridgeIPv6}); err != nil {
|
|
| 79 |
+ t.Fatalf("Failed to assign IPv6 %s to interface: %v", bridgeIPv6, err)
|
|
| 80 | 80 |
} |
| 81 | 81 |
if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: inf.Config.AddressIPv4}); err != nil {
|
| 82 | 82 |
t.Fatalf("Failed to assign IPv4 %s to interface: %v", inf.Config.AddressIPv4, err)
|
| 83 | 83 |
} |
| 84 | 84 |
|
| 85 |
- if err := SetupVerifyConfiguredAddresses(inf); err != nil {
|
|
| 85 |
+ if err := setupVerifyConfiguredAddresses(inf); err != nil {
|
|
| 86 | 86 |
t.Fatalf("Address verification failed: %v", err)
|
| 87 | 87 |
} |
| 88 | 88 |
} |
| ... | ... |
@@ -99,7 +99,7 @@ func TestSetupVerifyIPv6Missing(t *testing.T) {
|
| 99 | 99 |
t.Fatalf("Failed to assign IPv4 %s to interface: %v", inf.Config.AddressIPv4, err)
|
| 100 | 100 |
} |
| 101 | 101 |
|
| 102 |
- if err := SetupVerifyConfiguredAddresses(inf); err == nil {
|
|
| 102 |
+ if err := setupVerifyConfiguredAddresses(inf); err == nil {
|
|
| 103 | 103 |
t.Fatal("Address verification was expected to fail")
|
| 104 | 104 |
} |
| 105 | 105 |
} |
| ... | ... |
@@ -96,13 +96,14 @@ type Namespace interface {
|
| 96 | 96 |
AddInterface(*Interface) error |
| 97 | 97 |
} |
| 98 | 98 |
|
| 99 |
-// Create a new network of the specified networkType. The options are driver |
|
| 100 |
-// specific and modeled in a generic way. |
|
| 99 |
+// NewNetwork creates a new network of the specified networkType. The options |
|
| 100 |
+// are driver specific and modeled in a generic way. |
|
| 101 | 101 |
func NewNetwork(networkType, name string, options DriverParams) (Network, error) {
|
| 102 | 102 |
return createNetwork(networkType, name, options) |
| 103 | 103 |
} |
| 104 | 104 |
|
| 105 |
-// Create a new network namespace mounted on the specified path. |
|
| 105 |
+// NewNetworkNamespace creates a new network namespace mounted on the specified |
|
| 106 |
+// path. |
|
| 106 | 107 |
func NewNetworkNamespace(path string) (Namespace, error) {
|
| 107 | 108 |
return createNetworkNamespace(path) |
| 108 | 109 |
} |
| ... | ... |
@@ -1,4 +1,4 @@ |
| 1 |
-// The options package provides a way to pass unstructured sets of options to a |
|
| 1 |
+// Package options provides a way to pass unstructured sets of options to a |
|
| 2 | 2 |
// component expecting a strongly-typed configuration structure. |
| 3 | 3 |
package options |
| 4 | 4 |
|
| ... | ... |
@@ -7,6 +7,8 @@ import ( |
| 7 | 7 |
"reflect" |
| 8 | 8 |
) |
| 9 | 9 |
|
| 10 |
+// NoSuchFieldError is the error returned when the generic parameters hold a |
|
| 11 |
+// value for a field absent from the destination structure. |
|
| 10 | 12 |
type NoSuchFieldError struct {
|
| 11 | 13 |
Field string |
| 12 | 14 |
Type string |
| ... | ... |
@@ -16,6 +18,8 @@ func (e NoSuchFieldError) Error() string {
|
| 16 | 16 |
return fmt.Sprintf("no field %q in type %q", e.Field, e.Type)
|
| 17 | 17 |
} |
| 18 | 18 |
|
| 19 |
+// CannotSetFieldError is the error returned when the generic parameters hold a |
|
| 20 |
+// value for a field that cannot be set in the destination structure. |
|
| 19 | 21 |
type CannotSetFieldError struct {
|
| 20 | 22 |
Field string |
| 21 | 23 |
Type string |
| ... | ... |
@@ -25,12 +29,20 @@ func (e CannotSetFieldError) Error() string {
|
| 25 | 25 |
return fmt.Sprintf("cannot set field %q of type %q", e.Field, e.Type)
|
| 26 | 26 |
} |
| 27 | 27 |
|
| 28 |
+// Generic is an basic type to store arbitrary settings. |
|
| 28 | 29 |
type Generic map[string]interface{}
|
| 29 | 30 |
|
| 31 |
+// NewGeneric returns a new Generic instance. |
|
| 30 | 32 |
func NewGeneric() Generic {
|
| 31 | 33 |
return make(Generic) |
| 32 | 34 |
} |
| 33 | 35 |
|
| 36 |
+// GenerateFromModel takes the generic options, and tries to build a new |
|
| 37 |
+// instance of the model's type by matching keys from the generic options to |
|
| 38 |
+// fields in the model. |
|
| 39 |
+// |
|
| 40 |
+// The return value is of the same type than the model (including a potential |
|
| 41 |
+// pointer qualifier). |
|
| 34 | 42 |
func GenerateFromModel(options Generic, model interface{}) (interface{}, error) {
|
| 35 | 43 |
modType := reflect.TypeOf(model) |
| 36 | 44 |
|
| ... | ... |
@@ -64,7 +64,7 @@ func setupInNS(nsPath string, settings *Interface) error {
|
| 64 | 64 |
|
| 65 | 65 |
// Move the executing code to the destination namespace so we can start |
| 66 | 66 |
// configure the interface. |
| 67 |
- if err := Setns(nsFD, syscall.CLONE_NEWNET); err != nil {
|
|
| 67 |
+ if err := setns(nsFD, syscall.CLONE_NEWNET); err != nil {
|
|
| 68 | 68 |
return err |
| 69 | 69 |
} |
| 70 | 70 |
|
| ... | ... |
@@ -19,7 +19,7 @@ var setNsMap = map[string]uintptr{
|
| 19 | 19 |
"linux/s390x": 339, |
| 20 | 20 |
} |
| 21 | 21 |
|
| 22 |
-func Setns(fd uintptr, flags uintptr) error {
|
|
| 22 |
+func setns(fd uintptr, flags uintptr) error {
|
|
| 23 | 23 |
ns, exists := setNsMap[fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)]
|
| 24 | 24 |
if !exists {
|
| 25 | 25 |
return fmt.Errorf("unsupported platform %s/%s", runtime.GOOS, runtime.GOARCH)
|