Skip to content

Commit

Permalink
Updates default network readiness to use apimachinery wait.Exponentia…
Browse files Browse the repository at this point in the history
…lBackoff
  • Loading branch information
dougbtv committed Aug 16, 2018
1 parent 7d3e968 commit 6cb2e8c
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 115 deletions.
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -499,12 +499,11 @@ For example, if you use Flannel as a default network, the recommended method for

In this manner, you may prevent pods from crash looping, and instead wait for that default network to be ready.

Two options are available to configure this functionality:
Only one option is necessary to configure this functionality:

* `defaultnetworkfile`: The path to a file whose existance denotes that the default network is ready.
* `defaultnetworkwaitseconds`: The number of seconds to wait for that file to become available. Defaults to 120 seconds.
* `readinessindicatorfile`: The path to a file whose existance denotes that the default network is ready.

*NOTE*: If `defaultnetworkfile` is unset, or is an empty string, this functionality will be disabled, and is disabled by default.
*NOTE*: If `readinessindicatorfile` is unset, or is an empty string, this functionality will be disabled, and is disabled by default.

## Testing Multus CNI

Expand Down
50 changes: 18 additions & 32 deletions multus/multus.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"k8s.io/client-go/util/retry"
"time"

"github.com/containernetworking/cni/libcni"
"github.com/containernetworking/cni/pkg/invoke"
Expand All @@ -35,8 +35,16 @@ import (
k8s "github.com/intel/multus-cni/k8sclient"
"github.com/intel/multus-cni/types"
"github.com/vishvananda/netlink"
"k8s.io/apimachinery/pkg/util/wait"
)

var defaultReadinessBackoff = wait.Backoff{
Steps: 4,
Duration: 250 * time.Millisecond,
Factor: 4.0,
Jitter: 0.1,
}

func saveScratchNetConf(containerID, dataDir string, netconf []byte) error {
if err := os.MkdirAll(dataDir, 0700); err != nil {
return fmt.Errorf("failed to create the multus data directory(%q): %v", dataDir, err)
Expand Down Expand Up @@ -205,34 +213,6 @@ func delPlugins(exec invoke.Exec, argIfname string, delegates []*types.DelegateN
return nil
}

// Sits in a wait loop until a file indicating the readiness of the "default network"
// is present (or until a user-defined timeout is reached)
func waitForDefaultNetwork(indicatorFile string, waitSeconds int) error {
// If there's no file to wait for, then, this is essentially disabled.
if len(indicatorFile) > 0 {
attempts := 0
found := false
// Sleep in a loop until we find that file.
for attempts < waitSeconds {
attempts++
if _, err := os.Stat(indicatorFile); err == nil {
found = true
attempts = waitSeconds
} else {
time.Sleep(1 * time.Second)
}
}

if !found {
return fmt.Errorf("Multus: Timeout (%v seconds) finding default network file: %v", waitSeconds, indicatorFile)
}
return nil

}

return nil
}

func cmdAdd(args *skel.CmdArgs, exec invoke.Exec, kubeClient k8s.KubeClient) (cnitypes.Result, error) {
n, err := types.LoadNetConf(args.StdinData)
if err != nil {
Expand All @@ -244,9 +224,15 @@ func cmdAdd(args *skel.CmdArgs, exec invoke.Exec, kubeClient k8s.KubeClient) (cn
return nil, fmt.Errorf("Multus: Err in getting k8s args: %v", err)
}

if err = waitForDefaultNetwork(n.DefaultNetworkFile, n.DefaultNetworkWaitSeconds); err != nil {
return nil, err
}
wait.ExponentialBackoff(defaultReadinessBackoff, func() (bool, error) {
_, err := os.Stat(n.ReadinessIndicatorFile)
switch {
case err == nil:
return true, nil
default:
return false, nil
}
})

numK8sDelegates, kc, err := k8s.TryLoadK8sDelegates(k8sArgs, n, kubeClient)
if err != nil {
Expand Down
50 changes: 1 addition & 49 deletions multus/multus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,7 @@ var _ = Describe("multus operations", func() {
StdinData: []byte(`{
"name": "node-cni-network",
"type": "multus",
"defaultnetworkfile": "/tmp/foo.multus.conf",
"defaultnetworkwaitseconds": 3,
"readinessindicatorfile": "/tmp/foo.multus.conf",
"delegates": [{
"name": "weave1",
"cniVersion": "0.2.0",
Expand Down Expand Up @@ -320,51 +319,4 @@ var _ = Describe("multus operations", func() {
Expect(reflect.DeepEqual(r, expectedResult1)).To(BeTrue())
})

It("times out waiting for default networks", func() {
args := &skel.CmdArgs{
ContainerID: "123456789",
Netns: testNS.Path(),
IfName: "eth0",
StdinData: []byte(`{
"name": "defaultnetwork",
"type": "multus",
"defaultnetworkfile": "/tmp/foo.multus.conf",
"defaultnetworkwaitseconds": 1,
"delegates": [{
"name": "weave1",
"cniVersion": "0.2.0",
"type": "weave-net"
}]
}`),
}

// Always remove the defaultnetworkfile
configPath := "/tmp/foo.multus.conf"
if _, errStat := os.Stat(configPath); errStat == nil {
errRemove := os.Remove(configPath)
Expect(errRemove).NotTo(HaveOccurred())
}

fExec := &fakeExec{}
expectedResult1 := &types020.Result{
CNIVersion: "0.2.0",
IP4: &types020.IPConfig{
IP: *testhelpers.EnsureCIDR("1.1.1.2/24"),
},
}
expectedConf1 := `{
"name": "weave1",
"cniVersion": "0.2.0",
"type": "weave-net"
}`
fExec.addPlugin(nil, "eth0", expectedConf1, expectedResult1, nil)

os.Setenv("CNI_COMMAND", "ADD")
os.Setenv("CNI_IFNAME", "eth0")
_, err := cmdAdd(args, fExec, nil)

Expect(err).To(HaveOccurred())
Expect(err).To(MatchError("Multus: Timeout (1 seconds) finding default network file: /tmp/foo.multus.conf"))

})
})
17 changes: 6 additions & 11 deletions types/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,10 @@ import (
)

const (
defaultCNIDir = "/var/lib/cni/multus"
defaultConfDir = "/etc/cni/multus/net.d"
defaultBinDir = "/opt/cni/bin"
defaultDefaultNetworkFile = ""
defaultDefaultNetworkWaitSeconds = 120
defaultCNIDir = "/var/lib/cni/multus"
defaultConfDir = "/etc/cni/multus/net.d"
defaultBinDir = "/opt/cni/bin"
defaultReadinessIndicatorFile = ""
)

func LoadDelegateNetConfList(bytes []byte, delegateConf *DelegateNetConf) error {
Expand Down Expand Up @@ -181,12 +180,8 @@ func LoadNetConf(bytes []byte) (*NetConf, error) {
netconf.BinDir = defaultBinDir
}

if netconf.DefaultNetworkFile == "" {
netconf.DefaultNetworkFile = defaultDefaultNetworkFile
}

if netconf.DefaultNetworkWaitSeconds < 1 {
netconf.DefaultNetworkWaitSeconds = defaultDefaultNetworkWaitSeconds
if netconf.ReadinessIndicatorFile == "" {
netconf.ReadinessIndicatorFile = defaultReadinessIndicatorFile
}

for idx, rawConf := range netconf.RawDelegates {
Expand Down
30 changes: 13 additions & 17 deletions types/conf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ var _ = Describe("config operations", func() {
Expect(err).To(HaveOccurred())
})

It("has defaults set for network readiness", func() {
conf := `{
It("has defaults set for network readiness", func() {
conf := `{
"name": "defaultnetwork",
"type": "multus",
"kubeconfig": "/etc/kubernetes/kubelet.conf",
Expand All @@ -94,18 +94,16 @@ var _ = Describe("config operations", func() {
"isDefaultGateway": true
}]
}`
netConf, err := LoadNetConf([]byte(conf))
Expect(err).NotTo(HaveOccurred())
Expect(netConf.DefaultNetworkFile).To(Equal(""))
Expect(netConf.DefaultNetworkWaitSeconds).To(Equal(120))
})
netConf, err := LoadNetConf([]byte(conf))
Expect(err).NotTo(HaveOccurred())
Expect(netConf.ReadinessIndicatorFile).To(Equal(""))
})

It("honors overrides for network readiness", func() {
conf := `{
It("honors overrides for network readiness", func() {
conf := `{
"name": "defaultnetwork",
"type": "multus",
"defaultnetworkfile": "/etc/cni/net.d/foo",
"defaultnetworkwaitseconds": 30,
"readinessindicatorfile": "/etc/cni/net.d/foo",
"kubeconfig": "/etc/kubernetes/kubelet.conf",
"delegates": [{
"cniVersion": "0.3.0",
Expand All @@ -114,11 +112,9 @@ var _ = Describe("config operations", func() {
"isDefaultGateway": true
}]
}`
netConf, err := LoadNetConf([]byte(conf))
Expect(err).NotTo(HaveOccurred())
Expect(netConf.DefaultNetworkFile).To(Equal("/etc/cni/net.d/foo"))
Expect(netConf.DefaultNetworkWaitSeconds).To(Equal(30))
})

netConf, err := LoadNetConf([]byte(conf))
Expect(err).NotTo(HaveOccurred())
Expect(netConf.ReadinessIndicatorFile).To(Equal("/etc/cni/net.d/foo"))
})

})
3 changes: 1 addition & 2 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ type NetConf struct {
LogFile string `json:"logFile"`
LogLevel string `json:"logLevel"`
// Default network readiness options
DefaultNetworkFile string `json:defaultnetworkfile`
DefaultNetworkWaitSeconds int `json:defaultnetworkwaitseconds`
ReadinessIndicatorFile string `json:readinessindicatorfile`
}

type NetworkStatus struct {
Expand Down

0 comments on commit 6cb2e8c

Please sign in to comment.