X Tutup
Skip to content

Commit b0f687b

Browse files
Merge pull request docker-archive-public#2168 from dgageot/2167-b2d-upgrade
FIX docker-archive-public#2167 b2d download timeout during upgrade
2 parents 6a646ae + 1f0de8f commit b0f687b

File tree

4 files changed

+121
-63
lines changed

4 files changed

+121
-63
lines changed

libmachine/mcnutils/b2d.go

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"os"
1212
"path/filepath"
1313
"regexp"
14-
"time"
1514

1615
"github.com/docker/machine/libmachine/log"
1716
)
@@ -20,12 +19,8 @@ var (
2019
GithubAPIToken string
2120
)
2221

23-
const (
24-
timeout = time.Second * 5
25-
)
26-
2722
func defaultTimeout(network, addr string) (net.Conn, error) {
28-
return net.DialTimeout(network, addr, timeout)
23+
return net.Dial(network, addr)
2924
}
3025

3126
func getClient() *http.Client {
@@ -139,20 +134,27 @@ func removeFileIfExists(name string) error {
139134
// DownloadISO downloads boot2docker ISO image for the given tag and save it at dest.
140135
func (b *B2dUtils) DownloadISO(dir, file, isoURL string) error {
141136
u, err := url.Parse(isoURL)
137+
142138
var src io.ReadCloser
143139
if u.Scheme == "file" || u.Scheme == "" {
144140
s, err := os.Open(u.Path)
145141
if err != nil {
146142
return err
147143
}
144+
148145
src = s
149146
} else {
150147
client := getClient()
151148
s, err := client.Get(isoURL)
152149
if err != nil {
153150
return err
154151
}
155-
src = s.Body
152+
153+
src = &ReaderWithProgress{
154+
ReadCloser: s.Body,
155+
out: os.Stdout,
156+
expectedLength: s.ContentLength,
157+
}
156158
}
157159

158160
defer src.Close()
@@ -170,7 +172,6 @@ func (b *B2dUtils) DownloadISO(dir, file, isoURL string) error {
170172
}()
171173

172174
if _, err := io.Copy(f, src); err != nil {
173-
// TODO: display download progress?
174175
return err
175176
}
176177

@@ -194,6 +195,39 @@ func (b *B2dUtils) DownloadISO(dir, file, isoURL string) error {
194195
return nil
195196
}
196197

198+
type ReaderWithProgress struct {
199+
io.ReadCloser
200+
out io.Writer
201+
bytesTransferred int64
202+
expectedLength int64
203+
nextPercentToPrint int64
204+
}
205+
206+
func (r *ReaderWithProgress) Read(p []byte) (int, error) {
207+
n, err := r.ReadCloser.Read(p)
208+
209+
if n > 0 {
210+
r.bytesTransferred += int64(n)
211+
percentage := r.bytesTransferred * 100 / r.expectedLength
212+
213+
for percentage >= r.nextPercentToPrint {
214+
if r.nextPercentToPrint%10 == 0 {
215+
fmt.Fprintf(r.out, "%d%%", r.nextPercentToPrint)
216+
} else if r.nextPercentToPrint%2 == 0 {
217+
fmt.Fprint(r.out, ".")
218+
}
219+
r.nextPercentToPrint += 2
220+
}
221+
}
222+
223+
return n, err
224+
}
225+
226+
func (r *ReaderWithProgress) Close() error {
227+
fmt.Fprintln(r.out)
228+
return r.ReadCloser.Close()
229+
}
230+
197231
func (b *B2dUtils) DownloadLatestBoot2Docker(apiURL string) error {
198232
latestReleaseURL, err := b.GetLatestBoot2DockerReleaseURL(apiURL)
199233
if err != nil {

libmachine/mcnutils/b2d_test.go

Lines changed: 57 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import (
77
"net/http/httptest"
88
"path/filepath"
99
"testing"
10+
11+
"bytes"
12+
13+
"github.com/stretchr/testify/assert"
1014
)
1115

1216
func TestGetLatestBoot2DockerReleaseUrl(t *testing.T) {
@@ -18,14 +22,9 @@ func TestGetLatestBoot2DockerReleaseUrl(t *testing.T) {
1822

1923
b := NewB2dUtils("/tmp/isos")
2024
isoURL, err := b.GetLatestBoot2DockerReleaseURL(ts.URL + "/repos/org/repo/releases")
21-
if err != nil {
22-
t.Fatal(err)
23-
}
2425

25-
expectedURL := fmt.Sprintf("%s/org/repo/releases/download/0.1/boot2docker.iso", ts.URL)
26-
if isoURL != expectedURL {
27-
t.Fatalf("expected url %s; received %s", expectedURL, isoURL)
28-
}
26+
assert.NoError(t, err)
27+
assert.Equal(t, fmt.Sprintf("%s/org/repo/releases/download/0.1/boot2docker.iso", ts.URL), isoURL)
2928
}
3029

3130
func TestDownloadIso(t *testing.T) {
@@ -38,49 +37,76 @@ func TestDownloadIso(t *testing.T) {
3837
filename := "test"
3938

4039
tmpDir, err := ioutil.TempDir("", "machine-test-")
41-
if err != nil {
42-
t.Fatal(err)
43-
}
40+
41+
assert.NoError(t, err)
4442

4543
b := NewB2dUtils("/tmp/artifacts")
46-
if err := b.DownloadISO(tmpDir, filename, ts.URL); err != nil {
47-
t.Fatal(err)
48-
}
44+
err = b.DownloadISO(tmpDir, filename, ts.URL)
45+
46+
assert.NoError(t, err)
4947

5048
data, err := ioutil.ReadFile(filepath.Join(tmpDir, filename))
51-
if err != nil {
52-
t.Fatal(err)
53-
}
5449

55-
if string(data) != testData {
56-
t.Fatalf("expected data \"%s\"; received \"%s\"", testData, string(data))
57-
}
50+
assert.NoError(t, err)
51+
assert.Equal(t, testData, string(data))
5852
}
5953

6054
func TestGetReleasesRequestNoToken(t *testing.T) {
6155
GithubAPIToken = ""
56+
6257
b2d := NewB2dUtils("/tmp/store")
6358
req, err := b2d.getReleasesRequest("http://some.github.api")
64-
if err != nil {
65-
t.Fatal("Expected err to be nil, got ", err)
66-
}
6759

68-
if req.Header.Get("Authorization") != "" {
69-
t.Fatal("Expected not to get an 'Authorization' header, but got one: ", req.Header.Get("Authorization"))
70-
}
60+
assert.NoError(t, err)
61+
assert.Empty(t, req.Header.Get("Authorization"))
7162
}
7263

7364
func TestGetReleasesRequest(t *testing.T) {
7465
expectedToken := "CATBUG"
7566
GithubAPIToken = expectedToken
76-
b2d := NewB2dUtils("/tmp/store")
7767

68+
b2d := NewB2dUtils("/tmp/store")
7869
req, err := b2d.getReleasesRequest("http://some.github.api")
79-
if err != nil {
80-
t.Fatal("Expected err to be nil, got ", err)
81-
}
8270

83-
if req.Header.Get("Authorization") != fmt.Sprintf("token %s", expectedToken) {
84-
t.Fatal("Header was not set as expected: ", req.Header.Get("Authorization"))
71+
assert.NoError(t, err)
72+
assert.Equal(t, fmt.Sprintf("token %s", expectedToken), req.Header.Get("Authorization"))
73+
}
74+
75+
type MockReadCloser struct {
76+
blockLengths []int
77+
currentBlock int
78+
}
79+
80+
func (r *MockReadCloser) Read(p []byte) (n int, err error) {
81+
n = r.blockLengths[r.currentBlock]
82+
r.currentBlock++
83+
return
84+
}
85+
86+
func (r *MockReadCloser) Close() error {
87+
return nil
88+
}
89+
90+
func TestReaderWithProgress(t *testing.T) {
91+
readCloser := MockReadCloser{blockLengths: []int{5, 45, 50}}
92+
output := new(bytes.Buffer)
93+
buffer := make([]byte, 100)
94+
95+
readerWithProgress := ReaderWithProgress{
96+
ReadCloser: &readCloser,
97+
out: output,
98+
expectedLength: 100,
8599
}
100+
101+
readerWithProgress.Read(buffer)
102+
assert.Equal(t, "0%..", output.String())
103+
104+
readerWithProgress.Read(buffer)
105+
assert.Equal(t, "0%....10%....20%....30%....40%....50%", output.String())
106+
107+
readerWithProgress.Read(buffer)
108+
assert.Equal(t, "0%....10%....20%....30%....40%....50%....60%....70%....80%....90%....100%", output.String())
109+
110+
readerWithProgress.Close()
111+
assert.Equal(t, "0%....10%....20%....30%....40%....50%....60%....70%....80%....90%....100%\n", output.String())
86112
}

libmachine/provision/boot2docker.go

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -42,38 +42,17 @@ type Boot2DockerProvisioner struct {
4242
}
4343

4444
func (provisioner *Boot2DockerProvisioner) Service(name string, action serviceaction.ServiceAction) error {
45-
var (
46-
err error
47-
)
48-
49-
if _, err = provisioner.SSHCommand(fmt.Sprintf("sudo /etc/init.d/%s %s", name, action.String())); err != nil {
50-
return err
51-
}
52-
53-
return nil
45+
_, err := provisioner.SSHCommand(fmt.Sprintf("sudo /etc/init.d/%s %s", name, action.String()))
46+
return err
5447
}
5548

5649
func (provisioner *Boot2DockerProvisioner) upgradeIso() error {
57-
log.Info("Stopping machine to do the upgrade...")
58-
59-
if err := provisioner.Driver.Stop(); err != nil {
60-
return err
61-
}
62-
63-
if err := mcnutils.WaitFor(drivers.MachineInState(provisioner.Driver, state.Stopped)); err != nil {
64-
return err
65-
}
66-
67-
machineName := provisioner.GetDriver().GetMachineName()
68-
69-
log.Infof("Upgrading machine %s...", machineName)
70-
7150
// TODO: Ideally, we should not read from mcndirs directory at all.
7251
// The driver should be able to communicate how and where to place the
7352
// relevant files.
7453
b2dutils := mcnutils.NewB2dUtils(mcndirs.GetBaseDir())
7554

76-
//Check if the driver has specifed a custom b2d url
55+
// Check if the driver has specified a custom b2d url
7756
jsonDriver, err := json.Marshal(provisioner.GetDriver())
7857
if err != nil {
7958
return err
@@ -83,13 +62,30 @@ func (provisioner *Boot2DockerProvisioner) upgradeIso() error {
8362
}
8463
json.Unmarshal(jsonDriver, &d)
8564

65+
log.Info("Downloading latest boot2docker iso...")
66+
8667
// Usually we call this implicitly, but call it here explicitly to get
8768
// the latest default boot2docker ISO.
8869
if d.Boot2DockerURL == "" {
8970
if err := b2dutils.DownloadLatestBoot2Docker(d.Boot2DockerURL); err != nil {
9071
return err
9172
}
9273
}
74+
75+
log.Info("Stopping machine to do the upgrade...")
76+
77+
if err := provisioner.Driver.Stop(); err != nil {
78+
return err
79+
}
80+
81+
if err := mcnutils.WaitFor(drivers.MachineInState(provisioner.Driver, state.Stopped)); err != nil {
82+
return err
83+
}
84+
85+
machineName := provisioner.GetDriver().GetMachineName()
86+
87+
log.Infof("Upgrading machine %q...", machineName)
88+
9389
// Either download the latest version of the b2d url that was explicitly
9490
// specified when creating the VM or copy the (updated) default ISO
9591
if err := b2dutils.CopyIsoToMachineDir(d.Boot2DockerURL, machineName); err != nil {

libmachine/provision/provisioner.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ func Register(name string, p *RegisteredProvisioner) {
7272
}
7373

7474
func DetectProvisioner(d drivers.Driver) (Provisioner, error) {
75+
log.Info("Detecting the provisioner...")
76+
7577
osReleaseOut, err := drivers.RunSSHCommandFromDriver(d, "cat /etc/os-release")
7678
if err != nil {
7779
return nil, fmt.Errorf("Error getting SSH command: %s", err)

0 commit comments

Comments
 (0)
X Tutup