Merge lp:~dimitern/juju-core/270-lp-1257649-ssh-timeout-bootstrap into lp:~go-bot/juju-core/trunk
- 270-lp-1257649-ssh-timeout-bootstrap
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Dimiter Naydenov | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 2282 | ||||
Proposed branch: | lp:~dimitern/juju-core/270-lp-1257649-ssh-timeout-bootstrap | ||||
Merge into: | lp:~go-bot/juju-core/trunk | ||||
Prerequisite: | lp:~dimitern/juju-core/260-lp-1067979-duplicate-charm | ||||
Diff against target: |
401 lines (+187/-54) 5 files modified
cmd/juju/bootstrap.go (+10/-1) environs/config/config.go (+78/-15) environs/config/config_test.go (+86/-3) provider/common/bootstrap.go (+11/-33) provider/common/bootstrap_test.go (+2/-2) |
||||
To merge this branch: | bzr merge lp:~dimitern/juju-core/270-lp-1257649-ssh-timeout-bootstrap | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Dimiter Naydenov (community) | Approve | ||
Review via email: mp+203832@code.launchpad.net |
Commit message
bootstrap: Added configurable timeout and delays
Fixed bug #1257649: ssh timeout for bootstrap
could be configurable, by adding 3 new config
settings:
- bootstrap-timeout (default: 600s = 10m)
- bootstrap-
- bootstrap-
All of them are integers, measured in seconds,
and also all of them are optional and have the
specified defaults.
Updated the bootstrap command's help text to
include the new config settings.
https:/
R=natefinch
Description of the change
bootstrap: Added configurable timeout and delays
Fixed bug #1257649: ssh timeout for bootstrap
could be configurable, by adding 3 new config
settings:
- bootstrap-timeout (default: 600s = 10m)
- bootstrap-
- bootstrap-
All of them are integers, measured in seconds,
and also all of them are optional and have the
specified defaults.
Updated the bootstrap command's help text to
include the new config settings.
Dimiter Naydenov (dimitern) wrote : | # |
Nate Finch (natefinch) wrote : | # |
Please remove all user-facing mentions of SSH, since that's an internal
detail and something that would just confuse users. This is just a
bootstrap timeout to an end user, even if it does use SSH behind the
scenes.
https:/
File cmd/juju/
https:/
cmd/juju/
minutes
ssh is an internal detail that will just be confusing to users. This is
just the "bootstrap-timeout" to an end user.
Same goes for retry delay and addresses delay.
Nate Finch (natefinch) wrote : | # |
Oh yeah, otherwise LGTM :)
Dimiter Naydenov (dimitern) wrote : | # |
Please take a look.
Go Bot (go-bot) wrote : | # |
The prerequisite https:/
Dimiter Naydenov (dimitern) wrote : | # |
Please take a look.
Dimiter Naydenov (dimitern) wrote : | # |
Self-approving after fixing merge conflicts.
Go Bot (go-bot) wrote : | # |
The attempt to merge lp:~dimitern/juju-core/270-lp-1257649-ssh-timeout-bootstrap into lp:juju-core failed. Below is the output from the failed tests.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
? launchpad.
? launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? lau...
Dimiter Naydenov (dimitern) wrote : | # |
Please take a look.
Dimiter Naydenov (dimitern) wrote : | # |
Self-approving after fixing a test.
Preview Diff
1 | === modified file 'cmd/juju/bootstrap.go' | |||
2 | --- cmd/juju/bootstrap.go 2014-01-30 06:21:03 +0000 | |||
3 | +++ cmd/juju/bootstrap.go 2014-01-30 17:28:09 +0000 | |||
4 | @@ -42,7 +42,16 @@ | |||
5 | 42 | Bootstrap initializes the cloud environment synchronously and displays information | 42 | Bootstrap initializes the cloud environment synchronously and displays information |
6 | 43 | about the current installation steps. The time for bootstrap to complete varies | 43 | about the current installation steps. The time for bootstrap to complete varies |
7 | 44 | across cloud providers from a few seconds to several minutes. Once bootstrap has | 44 | across cloud providers from a few seconds to several minutes. Once bootstrap has |
9 | 45 | completed, you can run other juju commands against your environment. | 45 | completed, you can run other juju commands against your environment. You can change |
10 | 46 | the default timeout and retry delays used during the bootstrap by changing the | ||
11 | 47 | following settings in your environments.yaml (all values represent number of seconds): | ||
12 | 48 | |||
13 | 49 | # How long to wait for a connection to the state server. | ||
14 | 50 | bootstrap-timeout: 600 # default: 10 minutes | ||
15 | 51 | # How long to wait between connection attempts to a state server address. | ||
16 | 52 | bootstrap-retry-delay: 5 # default: 5 seconds | ||
17 | 53 | # How often to refresh state server addresses from the API server. | ||
18 | 54 | bootstrap-addresses-delay: 10 # default: 10 seconds | ||
19 | 46 | 55 | ||
20 | 47 | Private clouds may need to specify their own custom image metadata, and possibly upload | 56 | Private clouds may need to specify their own custom image metadata, and possibly upload |
21 | 48 | Juju tools to cloud storage if no outgoing Internet access is available. In this case, | 57 | Juju tools to cloud storage if no outgoing Internet access is available. In this case, |
22 | 49 | 58 | ||
23 | === modified file 'environs/config/config.go' | |||
24 | --- environs/config/config.go 2014-01-29 09:58:08 +0000 | |||
25 | +++ environs/config/config.go 2014-01-30 17:28:09 +0000 | |||
26 | @@ -45,6 +45,19 @@ | |||
27 | 45 | // DefaultSyslogPort is the default port that the syslog UDP listener is | 45 | // DefaultSyslogPort is the default port that the syslog UDP listener is |
28 | 46 | // listening on. | 46 | // listening on. |
29 | 47 | DefaultSyslogPort int = 514 | 47 | DefaultSyslogPort int = 514 |
30 | 48 | |||
31 | 49 | // DefaultBootstrapSSHTimeout is the amount of time to wait | ||
32 | 50 | // contacting a state server, in seconds. | ||
33 | 51 | DefaultBootstrapSSHTimeout int = 600 | ||
34 | 52 | |||
35 | 53 | // DefaultBootstrapSSHRetryDelay is the amount of time between | ||
36 | 54 | // attempts to connect to an address, in seconds. | ||
37 | 55 | DefaultBootstrapSSHRetryDelay int = 5 | ||
38 | 56 | |||
39 | 57 | // DefaultBootstrapSSHAddressesDelay is the amount of time between | ||
40 | 58 | // refreshing the addresses, in seconds. Not too frequent, as we | ||
41 | 59 | // refresh addresses from the provider each time. | ||
42 | 60 | DefaultBootstrapSSHAddressesDelay int = 10 | ||
43 | 48 | ) | 61 | ) |
44 | 49 | 62 | ||
45 | 50 | // Config holds an immutable environment configuration. | 63 | // Config holds an immutable environment configuration. |
46 | @@ -473,6 +486,26 @@ | |||
47 | 473 | return c.getWithFallback("apt-ftp-proxy", "ftp-proxy") | 486 | return c.getWithFallback("apt-ftp-proxy", "ftp-proxy") |
48 | 474 | } | 487 | } |
49 | 475 | 488 | ||
50 | 489 | // BootstrapSSHOpts returns the SSH timeout and retry delays used | ||
51 | 490 | // during bootstrap. | ||
52 | 491 | func (c *Config) BootstrapSSHOpts() SSHTimeoutOpts { | ||
53 | 492 | opts := SSHTimeoutOpts{ | ||
54 | 493 | Timeout: time.Duration(DefaultBootstrapSSHTimeout) * time.Second, | ||
55 | 494 | RetryDelay: time.Duration(DefaultBootstrapSSHRetryDelay) * time.Second, | ||
56 | 495 | AddressesDelay: time.Duration(DefaultBootstrapSSHAddressesDelay) * time.Second, | ||
57 | 496 | } | ||
58 | 497 | if v, ok := c.m["bootstrap-timeout"].(int); ok && v != 0 { | ||
59 | 498 | opts.Timeout = time.Duration(v) * time.Second | ||
60 | 499 | } | ||
61 | 500 | if v, ok := c.m["bootstrap-retry-delay"].(int); ok && v != 0 { | ||
62 | 501 | opts.RetryDelay = time.Duration(v) * time.Second | ||
63 | 502 | } | ||
64 | 503 | if v, ok := c.m["bootstrap-addresses-delay"].(int); ok && v != 0 { | ||
65 | 504 | opts.AddressesDelay = time.Duration(v) * time.Second | ||
66 | 505 | } | ||
67 | 506 | return opts | ||
68 | 507 | } | ||
69 | 508 | |||
70 | 476 | // CACert returns the certificate of the CA that signed the state server | 509 | // CACert returns the certificate of the CA that signed the state server |
71 | 477 | // certificate, in PEM format, and whether the setting is available. | 510 | // certificate, in PEM format, and whether the setting is available. |
72 | 478 | func (c *Config) CACert() ([]byte, bool) { | 511 | func (c *Config) CACert() ([]byte, bool) { |
73 | @@ -639,6 +672,9 @@ | |||
74 | 639 | "apt-http-proxy": schema.String(), | 672 | "apt-http-proxy": schema.String(), |
75 | 640 | "apt-https-proxy": schema.String(), | 673 | "apt-https-proxy": schema.String(), |
76 | 641 | "apt-ftp-proxy": schema.String(), | 674 | "apt-ftp-proxy": schema.String(), |
77 | 675 | "bootstrap-timeout": schema.ForceInt(), | ||
78 | 676 | "bootstrap-retry-delay": schema.ForceInt(), | ||
79 | 677 | "bootstrap-addresses-delay": schema.ForceInt(), | ||
80 | 642 | 678 | ||
81 | 643 | // Deprecated fields, retain for backwards compatibility. | 679 | // Deprecated fields, retain for backwards compatibility. |
82 | 644 | "tools-url": schema.String(), | 680 | "tools-url": schema.String(), |
83 | @@ -653,21 +689,24 @@ | |||
84 | 653 | // but some fields listed as optional here are actually mandatory | 689 | // but some fields listed as optional here are actually mandatory |
85 | 654 | // with NoDefaults and are checked at the later Validate stage. | 690 | // with NoDefaults and are checked at the later Validate stage. |
86 | 655 | var alwaysOptional = schema.Defaults{ | 691 | var alwaysOptional = schema.Defaults{ |
102 | 656 | "agent-version": schema.Omit, | 692 | "agent-version": schema.Omit, |
103 | 657 | "ca-cert": schema.Omit, | 693 | "ca-cert": schema.Omit, |
104 | 658 | "authorized-keys": schema.Omit, | 694 | "authorized-keys": schema.Omit, |
105 | 659 | "authorized-keys-path": schema.Omit, | 695 | "authorized-keys-path": schema.Omit, |
106 | 660 | "ca-cert-path": schema.Omit, | 696 | "ca-cert-path": schema.Omit, |
107 | 661 | "ca-private-key-path": schema.Omit, | 697 | "ca-private-key-path": schema.Omit, |
108 | 662 | "logging-config": schema.Omit, | 698 | "logging-config": schema.Omit, |
109 | 663 | "provisioner-safe-mode": schema.Omit, | 699 | "provisioner-safe-mode": schema.Omit, |
110 | 664 | "http-proxy": schema.Omit, | 700 | "http-proxy": schema.Omit, |
111 | 665 | "https-proxy": schema.Omit, | 701 | "https-proxy": schema.Omit, |
112 | 666 | "ftp-proxy": schema.Omit, | 702 | "ftp-proxy": schema.Omit, |
113 | 667 | "apt-http-proxy": schema.Omit, | 703 | "apt-http-proxy": schema.Omit, |
114 | 668 | "apt-https-proxy": schema.Omit, | 704 | "apt-https-proxy": schema.Omit, |
115 | 669 | "apt-ftp-proxy": schema.Omit, | 705 | "apt-ftp-proxy": schema.Omit, |
116 | 670 | "image-stream": schema.Omit, | 706 | "image-stream": schema.Omit, |
117 | 707 | "bootstrap-timeout": schema.Omit, | ||
118 | 708 | "bootstrap-retry-delay": schema.Omit, | ||
119 | 709 | "bootstrap-addresses-delay": schema.Omit, | ||
120 | 671 | 710 | ||
121 | 672 | // Deprecated fields, retain for backwards compatibility. | 711 | // Deprecated fields, retain for backwards compatibility. |
122 | 673 | "tools-url": "", | 712 | "tools-url": "", |
123 | @@ -706,6 +745,9 @@ | |||
124 | 706 | "state-port": DefaultStatePort, | 745 | "state-port": DefaultStatePort, |
125 | 707 | "api-port": DefaultAPIPort, | 746 | "api-port": DefaultAPIPort, |
126 | 708 | "syslog-port": DefaultSyslogPort, | 747 | "syslog-port": DefaultSyslogPort, |
127 | 748 | "bootstrap-timeout": DefaultBootstrapSSHTimeout, | ||
128 | 749 | "bootstrap-retry-delay": DefaultBootstrapSSHRetryDelay, | ||
129 | 750 | "bootstrap-addresses-delay": DefaultBootstrapSSHAddressesDelay, | ||
130 | 709 | } | 751 | } |
131 | 710 | for attr, val := range alwaysOptional { | 752 | for attr, val := range alwaysOptional { |
132 | 711 | d[attr] = val | 753 | d[attr] = val |
133 | @@ -739,6 +781,9 @@ | |||
134 | 739 | "state-port", | 781 | "state-port", |
135 | 740 | "api-port", | 782 | "api-port", |
136 | 741 | "syslog-port", | 783 | "syslog-port", |
137 | 784 | "bootstrap-timeout", | ||
138 | 785 | "bootstrap-retry-delay", | ||
139 | 786 | "bootstrap-addresses-delay", | ||
140 | 742 | } | 787 | } |
141 | 743 | 788 | ||
142 | 744 | var ( | 789 | var ( |
143 | @@ -802,6 +847,24 @@ | |||
144 | 802 | return repo | 847 | return repo |
145 | 803 | } | 848 | } |
146 | 804 | 849 | ||
147 | 850 | // SSHTimeoutOpts lists the amount of time we will wait for various | ||
148 | 851 | // parts of the SSH connection to complete. This is similar to | ||
149 | 852 | // DialOpts, see http://pad.lv/1258889 about possibly deduplicating | ||
150 | 853 | // them. | ||
151 | 854 | type SSHTimeoutOpts struct { | ||
152 | 855 | // Timeout is the amount of time to wait contacting a state | ||
153 | 856 | // server. | ||
154 | 857 | Timeout time.Duration | ||
155 | 858 | |||
156 | 859 | // RetryDelay is the amount of time between attempts to connect to | ||
157 | 860 | // an address. | ||
158 | 861 | RetryDelay time.Duration | ||
159 | 862 | |||
160 | 863 | // AddressesDelay is the amount of time between refreshing the | ||
161 | 864 | // addresses. | ||
162 | 865 | AddressesDelay time.Duration | ||
163 | 866 | } | ||
164 | 867 | |||
165 | 805 | // ProxyConfigMap returns a map suitable to be applied to a Config to update | 868 | // ProxyConfigMap returns a map suitable to be applied to a Config to update |
166 | 806 | // proxy settings. | 869 | // proxy settings. |
167 | 807 | func ProxyConfigMap(proxy osenv.ProxySettings) map[string]interface{} { | 870 | func ProxyConfigMap(proxy osenv.ProxySettings) map[string]interface{} { |
168 | 808 | 871 | ||
169 | === modified file 'environs/config/config_test.go' | |||
170 | --- environs/config/config_test.go 2014-01-29 09:58:08 +0000 | |||
171 | +++ environs/config/config_test.go 2014-01-30 17:28:09 +0000 | |||
172 | @@ -513,6 +513,57 @@ | |||
173 | 513 | }, | 513 | }, |
174 | 514 | err: `syslog-port: expected number, got string\("illegal"\)`, | 514 | err: `syslog-port: expected number, got string\("illegal"\)`, |
175 | 515 | }, { | 515 | }, { |
176 | 516 | about: "Explicit bootstrap timeout", | ||
177 | 517 | useDefaults: config.UseDefaults, | ||
178 | 518 | attrs: testing.Attrs{ | ||
179 | 519 | "type": "my-type", | ||
180 | 520 | "name": "my-name", | ||
181 | 521 | "bootstrap-timeout": 300, | ||
182 | 522 | }, | ||
183 | 523 | }, { | ||
184 | 524 | about: "Invalid bootstrap timeout", | ||
185 | 525 | useDefaults: config.UseDefaults, | ||
186 | 526 | attrs: testing.Attrs{ | ||
187 | 527 | "type": "my-type", | ||
188 | 528 | "name": "my-name", | ||
189 | 529 | "bootstrap-timeout": "illegal", | ||
190 | 530 | }, | ||
191 | 531 | err: `bootstrap-timeout: expected number, got string\("illegal"\)`, | ||
192 | 532 | }, { | ||
193 | 533 | about: "Explicit bootstrap retry delay", | ||
194 | 534 | useDefaults: config.UseDefaults, | ||
195 | 535 | attrs: testing.Attrs{ | ||
196 | 536 | "type": "my-type", | ||
197 | 537 | "name": "my-name", | ||
198 | 538 | "bootstrap-retry-delay": 5, | ||
199 | 539 | }, | ||
200 | 540 | }, { | ||
201 | 541 | about: "Invalid bootstrap retry delay", | ||
202 | 542 | useDefaults: config.UseDefaults, | ||
203 | 543 | attrs: testing.Attrs{ | ||
204 | 544 | "type": "my-type", | ||
205 | 545 | "name": "my-name", | ||
206 | 546 | "bootstrap-retry-delay": "illegal", | ||
207 | 547 | }, | ||
208 | 548 | err: `bootstrap-retry-delay: expected number, got string\("illegal"\)`, | ||
209 | 549 | }, { | ||
210 | 550 | about: "Explicit bootstrap addresses delay", | ||
211 | 551 | useDefaults: config.UseDefaults, | ||
212 | 552 | attrs: testing.Attrs{ | ||
213 | 553 | "type": "my-type", | ||
214 | 554 | "name": "my-name", | ||
215 | 555 | "bootstrap-addresses-delay": 15, | ||
216 | 556 | }, | ||
217 | 557 | }, { | ||
218 | 558 | about: "Invalid bootstrap addresses delay", | ||
219 | 559 | useDefaults: config.UseDefaults, | ||
220 | 560 | attrs: testing.Attrs{ | ||
221 | 561 | "type": "my-type", | ||
222 | 562 | "name": "my-name", | ||
223 | 563 | "bootstrap-addresses-delay": "illegal", | ||
224 | 564 | }, | ||
225 | 565 | err: `bootstrap-addresses-delay: expected number, got string\("illegal"\)`, | ||
226 | 566 | }, { | ||
227 | 516 | about: "Invalid logging configuration", | 567 | about: "Invalid logging configuration", |
228 | 517 | useDefaults: config.UseDefaults, | 568 | useDefaults: config.UseDefaults, |
229 | 518 | attrs: testing.Attrs{ | 569 | attrs: testing.Attrs{ |
230 | @@ -854,6 +905,25 @@ | |||
231 | 854 | } else { | 905 | } else { |
232 | 855 | c.Assert(cfg.ProvisionerSafeMode(), gc.Equals, false) | 906 | c.Assert(cfg.ProvisionerSafeMode(), gc.Equals, false) |
233 | 856 | } | 907 | } |
234 | 908 | sshOpts := cfg.BootstrapSSHOpts() | ||
235 | 909 | test.assertDuration( | ||
236 | 910 | c, | ||
237 | 911 | "bootstrap-timeout", | ||
238 | 912 | sshOpts.Timeout, | ||
239 | 913 | config.DefaultBootstrapSSHTimeout, | ||
240 | 914 | ) | ||
241 | 915 | test.assertDuration( | ||
242 | 916 | c, | ||
243 | 917 | "bootstrap-retry-delay", | ||
244 | 918 | sshOpts.RetryDelay, | ||
245 | 919 | config.DefaultBootstrapSSHRetryDelay, | ||
246 | 920 | ) | ||
247 | 921 | test.assertDuration( | ||
248 | 922 | c, | ||
249 | 923 | "bootstrap-addresses-delay", | ||
250 | 924 | sshOpts.AddressesDelay, | ||
251 | 925 | config.DefaultBootstrapSSHAddressesDelay, | ||
252 | 926 | ) | ||
253 | 857 | 927 | ||
254 | 858 | if v, ok := test.attrs["image-stream"]; ok { | 928 | if v, ok := test.attrs["image-stream"]; ok { |
255 | 859 | c.Assert(cfg.ImageStream(), gc.Equals, v) | 929 | c.Assert(cfg.ImageStream(), gc.Equals, v) |
256 | @@ -888,6 +958,15 @@ | |||
257 | 888 | } | 958 | } |
258 | 889 | } | 959 | } |
259 | 890 | 960 | ||
260 | 961 | func (test configTest) assertDuration(c *gc.C, name string, actual time.Duration, defaultInSeconds int) { | ||
261 | 962 | value, ok := test.attrs[name].(int) | ||
262 | 963 | if !ok || value == 0 { | ||
263 | 964 | c.Assert(actual, gc.Equals, time.Duration(defaultInSeconds)*time.Second) | ||
264 | 965 | } else { | ||
265 | 966 | c.Assert(actual, gc.Equals, time.Duration(value)*time.Second) | ||
266 | 967 | } | ||
267 | 968 | } | ||
268 | 969 | |||
269 | 891 | func (s *ConfigSuite) TestConfigAttrs(c *gc.C) { | 970 | func (s *ConfigSuite) TestConfigAttrs(c *gc.C) { |
270 | 892 | // Normally this is handled by testing.FakeHome | 971 | // Normally this is handled by testing.FakeHome |
271 | 893 | s.PatchEnvironment(osenv.JujuLoggingConfigEnvKey, "") | 972 | s.PatchEnvironment(osenv.JujuLoggingConfigEnvKey, "") |
272 | @@ -905,6 +984,9 @@ | |||
273 | 905 | "state-port": 1234, | 984 | "state-port": 1234, |
274 | 906 | "api-port": 4321, | 985 | "api-port": 4321, |
275 | 907 | "syslog-port": 2345, | 986 | "syslog-port": 2345, |
276 | 987 | "bootstrap-timeout": 3600, | ||
277 | 988 | "bootstrap-retry-delay": 30, | ||
278 | 989 | "bootstrap-addresses-delay": 10, | ||
279 | 908 | "default-series": "precise", | 990 | "default-series": "precise", |
280 | 909 | "charm-store-auth": "token=auth", | 991 | "charm-store-auth": "token=auth", |
281 | 910 | } | 992 | } |
282 | @@ -921,17 +1003,18 @@ | |||
283 | 921 | attrs["tools-url"] = "" | 1003 | attrs["tools-url"] = "" |
284 | 922 | // Default firewall mode is instance | 1004 | // Default firewall mode is instance |
285 | 923 | attrs["firewall-mode"] = string(config.FwInstance) | 1005 | attrs["firewall-mode"] = string(config.FwInstance) |
288 | 924 | c.Assert(cfg.AllAttrs(), gc.DeepEquals, attrs) | 1006 | c.Assert(cfg.AllAttrs(), jc.DeepEquals, attrs) |
289 | 925 | c.Assert(cfg.UnknownAttrs(), gc.DeepEquals, map[string]interface{}{"unknown": "my-unknown"}) | 1007 | c.Assert(cfg.UnknownAttrs(), jc.DeepEquals, map[string]interface{}{"unknown": "my-unknown"}) |
290 | 926 | 1008 | ||
291 | 927 | newcfg, err := cfg.Apply(map[string]interface{}{ | 1009 | newcfg, err := cfg.Apply(map[string]interface{}{ |
292 | 928 | "name": "new-name", | 1010 | "name": "new-name", |
293 | 929 | "new-unknown": "my-new-unknown", | 1011 | "new-unknown": "my-new-unknown", |
294 | 930 | }) | 1012 | }) |
295 | 1013 | c.Assert(err, gc.IsNil) | ||
296 | 931 | 1014 | ||
297 | 932 | attrs["name"] = "new-name" | 1015 | attrs["name"] = "new-name" |
298 | 933 | attrs["new-unknown"] = "my-new-unknown" | 1016 | attrs["new-unknown"] = "my-new-unknown" |
300 | 934 | c.Assert(newcfg.AllAttrs(), gc.DeepEquals, attrs) | 1017 | c.Assert(newcfg.AllAttrs(), jc.DeepEquals, attrs) |
301 | 935 | } | 1018 | } |
302 | 936 | 1019 | ||
303 | 937 | type validationTest struct { | 1020 | type validationTest struct { |
304 | 938 | 1021 | ||
305 | === modified file 'provider/common/bootstrap.go' | |||
306 | --- provider/common/bootstrap.go 2014-01-28 04:58:43 +0000 | |||
307 | +++ provider/common/bootstrap.go 2014-01-30 17:28:09 +0000 | |||
308 | @@ -19,6 +19,7 @@ | |||
309 | 19 | "launchpad.net/juju-core/environs" | 19 | "launchpad.net/juju-core/environs" |
310 | 20 | "launchpad.net/juju-core/environs/bootstrap" | 20 | "launchpad.net/juju-core/environs/bootstrap" |
311 | 21 | "launchpad.net/juju-core/environs/cloudinit" | 21 | "launchpad.net/juju-core/environs/cloudinit" |
312 | 22 | "launchpad.net/juju-core/environs/config" | ||
313 | 22 | "launchpad.net/juju-core/instance" | 23 | "launchpad.net/juju-core/instance" |
314 | 23 | coretools "launchpad.net/juju-core/tools" | 24 | coretools "launchpad.net/juju-core/tools" |
315 | 24 | "launchpad.net/juju-core/utils" | 25 | "launchpad.net/juju-core/utils" |
316 | @@ -191,10 +192,14 @@ | |||
317 | 191 | exit 1 | 192 | exit 1 |
318 | 192 | fi | 193 | fi |
319 | 193 | `, nonceFile, utils.ShQuote(machineConfig.MachineNonce)) | 194 | `, nonceFile, utils.ShQuote(machineConfig.MachineNonce)) |
324 | 194 | // TODO: jam 2013-12-04 bug #1257649 | 195 | addr, err := waitSSH( |
325 | 195 | // It would be nice if users had some controll over their bootstrap | 196 | ctx, |
326 | 196 | // timeout, since it is unlikely to be a perfect match for all clouds. | 197 | interrupted, |
327 | 197 | addr, err := waitSSH(ctx, interrupted, client, checkNonceCommand, inst, DefaultBootstrapSSHTimeout()) | 198 | client, |
328 | 199 | checkNonceCommand, | ||
329 | 200 | inst, | ||
330 | 201 | machineConfig.Config.BootstrapSSHOpts(), | ||
331 | 202 | ) | ||
332 | 198 | if err != nil { | 203 | if err != nil { |
333 | 199 | return err | 204 | return err |
334 | 200 | } | 205 | } |
335 | @@ -216,33 +221,6 @@ | |||
336 | 216 | }) | 221 | }) |
337 | 217 | } | 222 | } |
338 | 218 | 223 | ||
339 | 219 | // SSHTimeoutOpts lists the amount of time we will wait for various parts of | ||
340 | 220 | // the SSH connection to complete. This is similar to DialOpts, see | ||
341 | 221 | // http://pad.lv/1258889 about possibly deduplicating them. | ||
342 | 222 | type SSHTimeoutOpts struct { | ||
343 | 223 | // Timeout is the amount of time to wait contacting | ||
344 | 224 | // a state server. | ||
345 | 225 | Timeout time.Duration | ||
346 | 226 | |||
347 | 227 | // ConnectDelay is the amount of time between attempts to connect to an address. | ||
348 | 228 | ConnectDelay time.Duration | ||
349 | 229 | |||
350 | 230 | // AddressesDelay is the amount of time between refreshing the addresses. | ||
351 | 231 | AddressesDelay time.Duration | ||
352 | 232 | } | ||
353 | 233 | |||
354 | 234 | // DefaultBootstrapSSHTimeout is the time we'll wait for SSH to come up on the bootstrap node | ||
355 | 235 | func DefaultBootstrapSSHTimeout() SSHTimeoutOpts { | ||
356 | 236 | return SSHTimeoutOpts{ | ||
357 | 237 | Timeout: 10 * time.Minute, | ||
358 | 238 | |||
359 | 239 | ConnectDelay: 5 * time.Second, | ||
360 | 240 | |||
361 | 241 | // Not too frequent, as we refresh addresses from the provider each time. | ||
362 | 242 | AddressesDelay: 10 * time.Second, | ||
363 | 243 | } | ||
364 | 244 | } | ||
365 | 245 | |||
366 | 246 | type addresser interface { | 224 | type addresser interface { |
367 | 247 | // Refresh refreshes the addresses for the instance. | 225 | // Refresh refreshes the addresses for the instance. |
368 | 248 | Refresh() error | 226 | Refresh() error |
369 | @@ -377,7 +355,7 @@ | |||
370 | 377 | // the presence of a file on the machine that contains the | 355 | // the presence of a file on the machine that contains the |
371 | 378 | // machine's nonce. The "checkHostScript" is a bash script | 356 | // machine's nonce. The "checkHostScript" is a bash script |
372 | 379 | // that performs this file check. | 357 | // that performs this file check. |
374 | 380 | func waitSSH(ctx environs.BootstrapContext, interrupted <-chan os.Signal, client ssh.Client, checkHostScript string, inst addresser, timeout SSHTimeoutOpts) (addr string, err error) { | 358 | func waitSSH(ctx environs.BootstrapContext, interrupted <-chan os.Signal, client ssh.Client, checkHostScript string, inst addresser, timeout config.SSHTimeoutOpts) (addr string, err error) { |
375 | 381 | globalTimeout := time.After(timeout.Timeout) | 359 | globalTimeout := time.After(timeout.Timeout) |
376 | 382 | pollAddresses := time.NewTimer(0) | 360 | pollAddresses := time.NewTimer(0) |
377 | 383 | 361 | ||
378 | @@ -389,7 +367,7 @@ | |||
379 | 389 | client: client, | 367 | client: client, |
380 | 390 | stderr: ctx.Stderr(), | 368 | stderr: ctx.Stderr(), |
381 | 391 | active: make(map[instance.Address]chan struct{}), | 369 | active: make(map[instance.Address]chan struct{}), |
383 | 392 | checkDelay: timeout.ConnectDelay, | 370 | checkDelay: timeout.RetryDelay, |
384 | 393 | checkHostScript: checkHostScript, | 371 | checkHostScript: checkHostScript, |
385 | 394 | } | 372 | } |
386 | 395 | defer checker.Kill() | 373 | defer checker.Kill() |
387 | 396 | 374 | ||
388 | === modified file 'provider/common/bootstrap_test.go' | |||
389 | --- provider/common/bootstrap_test.go 2014-01-28 04:58:43 +0000 | |||
390 | +++ provider/common/bootstrap_test.go 2014-01-30 17:28:09 +0000 | |||
391 | @@ -261,9 +261,9 @@ | |||
392 | 261 | return nil, nil | 261 | return nil, nil |
393 | 262 | } | 262 | } |
394 | 263 | 263 | ||
396 | 264 | var testSSHTimeout = common.SSHTimeoutOpts{ | 264 | var testSSHTimeout = config.SSHTimeoutOpts{ |
397 | 265 | Timeout: coretesting.ShortWait, | 265 | Timeout: coretesting.ShortWait, |
399 | 266 | ConnectDelay: 1 * time.Millisecond, | 266 | RetryDelay: 1 * time.Millisecond, |
400 | 267 | AddressesDelay: 1 * time.Millisecond, | 267 | AddressesDelay: 1 * time.Millisecond, |
401 | 268 | } | 268 | } |
402 | 269 | 269 |
Reviewers: mp+203832_ code.launchpad. net,
Message:
Please take a look.
Description:
bootstrap: Added configurable timeout and delays
Fixed bug #1257649: ssh timeout for bootstrap ssh-timeout (default: 600s = 10m) ssh-retry- delay (default: 5s) ssh-addresses- delay (default: 10s)
could be configurable, by adding 3 new config
settings:
- bootstrap-
- bootstrap-
- bootstrap-
All of them are integers, measured in seconds,
and also all of them are optional and have the
specified defaults.
Updated the bootstrap command's help text to
include the new config settings.
https:/ /code.launchpad .net/~dimitern/ juju-core/ 270-lp- 1257649- ssh-timeout- bootstrap/ +merge/ 203832
Requires: /code.launchpad .net/~dimitern/ juju-core/ 260-lp- 1067979- duplicate- charm/+ merge/203291
https:/
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/58170045/
Affected files (+236, -101 lines): bootstrap. go config/ config. go config/ config_ test.go common/ bootstrap. go
A [revision details]
M cmd/juju/
M environs/
M environs/
M provider/