1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369 | cloud-init networking allows networking configuration to be defined
by the:
user or image builder: /etc/cloud/cloud.cfg or /etc/cloud/cloud.cfg.d/*.cfg
datasource: datasource discovery and returned in DataSource.network_config
kernel command line / initramfs: ip= on the command line
fallback:
Part of cloud-init netorking support is to allow the datasource
or the image creator to name network devices consistently.
Previously, ubuntu images have had the following in
/etc/network/interfaces:
auto eth0
iface eth0 inet dhcp
/etc/network/interfaces will be referred to as ENI for brevity.
This was less than ideal for a number of reasons.
* 'eth0' is not a stable device name.
The ethX namespace is owned by the kernel, and thus users
can't really rely on names in that namespace.
* in order to make that ENI file right, we have to boot
with systemd naming disabled. (kernel command line net.ifnames=0)
In order for 'cloud-init-local' to search and apply network configuration
before the system brings up the network, we'll employ the following behavior
on ubuntu.
1.) cloud-init udev rule 79-cloud-init-net-setup-link.rules
this uses IMPORT to execute
/lib/udev/cloud-init-wait cloud-init-local
udev will thus stop processing this event until cloud-init-wait
is finished.
2.) cloud-init-wait service [timeout]
This program blocks until the provided service has finished.
if cloud-init is disabled, it will exit immediately.
if timeout is reached it will exit non-zero.
3.) cloud-init-local will will populate files systemd.link files and ENI
systemd.link files will be written with name template
50-cloud-init-*.link with rules to accomplish the desired device
names. the '*' is the device name. this should be sufficient
as cloud-init will only render .link files for naming reasons.
cloud-init-local should delete any 50-* link files that it did not
author.
an alternative to '*' would be with
'mac_address'.lower().replace(":", "")
At the point when cloud-init-local exits,
/etc/network/interfaces.d/50-cloud-init.cfg
will have been populated with the content provided.
== control of network configuration ==
All automatic network configuration in cloud-init can be disabled system
configuration in /etc/cloud/cloud.cfg or /etc/cloud/cloud.cfg.d/ via:
network:
config: disabled
Simple example:
echo 'network: {config: disabled}"' > /etc/cloud/cloud.cfg.d/go-away.cfg
== Upgrades ==
upgrades that find a working local datasource (or one with a quick search)
would be fine. No networking would be written by 'cloud-init local'
as it would not be found to be a new instance id.
Upgrades from older versions of cloud-init should mark that they are
upgrade, via /var/lib/cloud/data/upgraded-network.
This file being present has the same affect as
network: config: disabled
An upgrade from a network-enabled version of cloud-init to a new version will
not need to write this file.
When testing, where we insert a cloud-init and want to boot with network
config, we will just need to ensure that file is removed after package
upgrade.
== Precedence ==
network configuration is consulted in the following order, with
subsequent definition taking precedence.
TODO: is it right to have kernel command line override datasource?
alternative would be to make the datasource able to easily
consume the kernel command line, and leave that up to the ds.
* fallback
this will dynamically generate a network config
based entirely on hueristics. it will essentially
scan the system and say "dhcp on everything" and assign
'en*' namespace for nic names
a system with one nic would end up with fallback config like:
config:
- type: physical
name: en0
mac_address: "c0:d6:9f:2c:e8:80"
auto: true
subnets:
- type: dhcp4
if networking was configured in the initramfs (ip= on cmdline)
it will write config for each device that was configured in initramfs.
* image /etc/cloud/cloud.cfg or /etc/cloud/cloud.cfg.d/*.cfg
this allows the image author (or CPC) to provide network
config like:
| network:
| config:
| - type: physical
| name: en0
| match:
| Path: pci-0000:00:1a.0-*
if something more dynamic than this is needed, then we should
improve the datasource to dynamically determine this config
or the datasource should actually find the configuration from
a declaritive source.
* datasource
* kernel command line (ip=)
== Use Cases ==
1.) EC2
characteristics:
- no local source of network information
- network device needed to dhcp to reach metadata service
behavior:
- determine which device is to be dhcp'd on for MD access
- author ENI for "dhcp on eth0"
2.) openstack config drive
characteristics:
- local declarative network configuration
- network configuration provides 'id's for devices, but
not intended names. id is to be used as the device name.
- quick check for "is new instance id"
- network configuration contains mac addresses
behavior:
- author ENI on first boot
- render network device rules that make 'id' == 'name'
3.) cloud-localds
characteristics:
- local declarative network configuration
- network configuration provides device names
- quick check for 'seed'ed data, but not for attached disk
behavior:
- by default do *not* move devices out of 'eth' namespace
3.) maas iscsi root
characteristics:
- ip= on kernel command line
behavior:
- need to leave in place devices brought up by ip=
4.) iscsi root bigstep
characteristics:
- ip= or iscsi ibft configuration
- datasource 'local' mode might be tough to determine
explicitly that this is bigstep. (but ds=bigstep might be an option)
5.) maas install via curtin
curtin writes 70-persistent-net.rules and correct
/etc/network/interfaces. So here we either have to
a.) have cloud-init *NOT* muck with ENI or
if cloud-init only writes systemd.rules and to 50-cloud-init.cfg
then situation as it is right now cloud-init's changes
would have no affect at all, and end result the same.
alternatively, curtin install could disable network config.
b.) curtin need to change to just writing its network_config
to where cloud-init would read it and apply on boot
'a' is how this worked in the past. 'b' is more like we'd
be working on other first boot clouds.
6.) cloud instance disabled cloud-init
the user boots a cloud instance and then is done with cloud-init
and wants to avoid magic happening on reboot. They thus touch
/etc/cloud/cloud-init.disabled.
The next reboot is expected to function fine, but not have
cloud-init affecting it in any way.
The fallout of this use case is that cloud-init needs to write
its systemd.link files to a persistent directory.
thus /etc/systemd/network/ is chosen over /run/systend/network
7.) lxd
characteristics:
- stable device names in 'eth0' range
== cloud-init local ==
* cloud-init local
a.) add 'quick check' for data sources
if there is a previous datasource in
/var/lib/cloud/data/previous-datasource then ask that datasource
if the instance is the same.
For openstack and azure, simply read dmi data and compare
to previous. If this is the same, exit quickly.
/sys/class/dmi/id/product_uuid on azure
This would essentially behave like 'manual_cache_clean: true'
in this case.
b.) if local datasource is found:
if new instance:
apply networking config per Precedence above
else:
no network changes made
c.) if no local datasource is found
if manual_cache_clean:
remove link
apply fallback network config
general:
* search any previously found datasource first
the most likely case is that you've snapshotted on the same cloud.
This will generally improve boot speed.
If user is snappshotting with intent to move to another cloud, they can
rm /var/lib/cloud/data/datasource
* [brainstorm] it seems maybe that all all datasources could have a local datasource
portion that searched and said 'yes' or 'no', and provided network
config. Then, should be able to
search for network config. Ie, even EC2 or MAAS would
* [brainstorm] All datasources run in network mode
== Code items ==
* cloudinit/net: support rendering ENI to a specific file
instead of rendering to /e/n/i, we need to render to
/e/n/i.d/50-cloud-init.cfg
* cloudinit/net: support rendering systemd.link rules
Note, we want to render systemd.link files rather than
70-persistent-net.rules because systemd.link files are consumed
more dynamically [although this statement is untested].
cloud-init-local can write these files while the ADD event
is being run (and blocked). Where as rules files are not
dynamically re-read during the procesing of an event.
* cloudinit/net: support 'match' attribute on an interface
network config like:
| config:
| - type: physical
| name: en0
| match:
| Path: pci-0000:00:1a.0-*
should render into a systemd.link file named 50-cloudinit-en0.link
| [Match]
| MACAddress=12:34:56:78:9a:bc
| Driver=brcmsmac
| Path=pci-0000:02:00.0-*
|
| [Link]
| Name=en0
* bin/cloud-init: quick check support
* bin/cloud-init: change search to prefer previous datasource first
* cloudinit/net: read 'ip=' / initramfs code
started https://code.launchpad.net/~wesley-wiedenmeier/cloud-init/trunk.net1-cmdline-ip
Wesley has support for merging there, which is nice.
* [CPC] stop writing /etc/network/interfaces.d/eth0.cfg:
cloud-init will start writing the equivalent.
* cloudinit/stages (or possibly cloudinit/net): apply networking generically
networking configuration was previously applied in the datasource
instead we need to implement that here. Still using the distro
but the Init after it finds the datasource it should apply the config.
* udev/cloud-init-wait:
this takes the name of a service to wait for. It waits until
it has finished (pass or fail) and then exits.
We may have to employ 'sleep' loop to do this. One simple
solution is just to have a loop do
while [ ! -f /some/file ]; do sleep 1; done'
and then have cloud-init-local touch that file.
* datasource rework
currently datasources are either "Network" or "Local"
They ones that describe themselves as local are called by cloud-init
in cloud-init-local. And those network are called at network time.
This needs changing, to instead allow for the datasource to be
invoked when local is present and still claim itself.
the general path is present in both the DataSourceNoCloud and
the DataSourceOpenstack , where they use 'dsmode' to by default
have the local datasource just return not found so that it is
then consumed later in network mode.
this should be generalized, so that for example Azure's "Local"
datasource would claim 'found'. This way other datasources
dont have to get searched, the search is over, but
cloud-init [network] would still load the datasource.
* cloudinit/sources/DataSourceNoCloud.py
Add
change make 'ds=nocloud' read data in /var/lib/cloud/data/seed/nocloud-net
it should read this if /var/lib/cloud/ata/seed/nocloud is not populated.
this is desireable as then the local
== Notes ==
* when writing rules, cloud-init will not move device names out of
the kernel's internel namespaces (ethX).
Ideally, the network config provider should provide us names not in
that namespace.
We could add a cloud-config variable:
network_config_replace_namespace:
eth: foo
that would then replace 'eth0' with 'foo0'.
* cloud-init will render networking into
/etc/network/interfaces.d/50-cloud-init.cfg
If /etc/network/interfaces in the image does not include
source /etc/network/interfaces.d/*.cfg
Then it will not be read.
cloud-init should probably WARN if its writing that file
and ENI has no 'source' line that would seem to match
== Not Addressed ==
* user puts rules (either udev 70-persistent-net.rules or
systemd.link files */systemd/network/*.link) that conflict
with cloud-init's name.
ie, user puts a file in 10-local.link that says match Path=*
name=mynic0. Cloud-init would author rules that named it 'en0'
but the nic's name would be 'mynic0'. ENI would contain 'en0'
and would sit around waiting for that device to appear.
if we wanted to address this, we'd have two options:
a.) cloud-init implement its own rules and naming function
b.) cloud-init have to parse */systemd/network/*.link for
== Trusty / 14.04 ==
On 14.04 we will not have 'net_setup_link' in udev or the ability
to use systemd.link. There, we would have to have cloud-initg
== Things to think about ==
* iscsi root. bigstep and maas use iscsi root.
initramfs naming will not have the benefit of knowledge in cloud-init
(except for on updated initramfs).
Because the root's network device comes up, it cannot be subsequently
renamed. cloud-initramfs-dyn-netconf and bigstep links below
have a solution for writing ENI for this device.
Links:
* https://public.etherpad-mozilla.org/p/cloud-init-networking
* https://bugs.launchpad.net/ubuntu/+source/cloud-init/+bug/1549403
* bigstep udev rules
https://git.launchpad.net/~utlemming/+git/bigstep-initramfs/tree/sbin/cloud-bigstep-eth.sh
https://git.launchpad.net/~utlemming/+git/bigstep-initramfs/tree/lib/udev/rules.d/74-bigstep.rules
* smoser random work towards this from http://paste.ubuntu.com/15419087/
bzr+ssh://bazaar.launchpad.net/~smoser/cloud-init/trunk.net1/
|