Merge ~akaris/cloud-init:bug1679817 into cloud-init:master
- Git
- lp:~akaris/cloud-init
- bug1679817
- Merge into master
Status: | Superseded |
---|---|
Proposed branch: | ~akaris/cloud-init:bug1679817 |
Merge into: | cloud-init:master |
Diff against target: |
452 lines (+193/-133) 3 files modified
cloudinit/net/sysconfig.py (+168/-71) tests/unittests/test_distros/test_netconfig.py (+3/-5) tests/unittests/test_net.py (+22/-57) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Server Team CI bot | continuous-integration | Approve | |
cloud-init Commiters | Pending | ||
Review via email: mp+323082@code.launchpad.net |
This proposal supersedes a proposal from 2017-04-24.
Commit message
Fix dual stack IPv4/IPv6 configuration for RHEL
Dual stack IPv4/IPv6 configuration via config drive is broken for RHEL7.
This patch fixes several scenarios for IPv4/IPv6/dual stack with multiple IP assignment
Removes unpopular IPv4 alias files and invalid IPv6 alias files
Also fixes associated unit tests
Description of the change
Fix dual stack IPv4/IPv6 configuration for RHEL
Dual stack IPv4/IPv6 configuration via config drive is broken for RHEL7.
This patch fixes several scenarios for IPv4/IPv6/dual stack with multiple IP assignment
Removes unpopular IPv4 alias files and invalid IPv6 alias files
Also fixes associated unit tests
Server Team CI bot (server-team-bot) wrote : Posted in a previous version of this proposal | # |
Server Team CI bot (server-team-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:9ad5280dcc5
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Server Team CI bot (server-team-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:a94ded7f67e
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Server Team CI bot (server-team-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:a94ded7f67e
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Server Team CI bot (server-team-bot) wrote : | # |
FAILED: Continuous integration, rev:46c35411fd7
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
- 5a0bc13... by Andreas Karis
-
fix for flake
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:5a0bc1350a8
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
- 025f52b... by Andreas Karis
-
consolidated to_string_ipv4 and to_string_ipv6
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:025f52bc8f3
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
Unmerged commits
- 025f52b... by Andreas Karis
-
consolidated to_string_ipv4 and to_string_ipv6
- 5a0bc13... by Andreas Karis
-
fix for flake
- 46c3541... by Andreas Karis
-
cleanup for flake
- 23c7007... by Andreas Karis
-
cleanup for flake
- a94ded7... by Andreas Karis
-
Moved IPv6 routes to route6-
- 7569e43... by Andreas Karis
-
added route handling for ipv4 and ipv6 routes
- 2d818c2... by Andreas Karis
-
wrapped str around netmask in cases it is integer
- 9ad5280... by Andreas Karis
-
Remove BOOTPROTO=static and make it BOOTPROTO=none as it should be
- e43facb... by Andreas Karis
- ca539b9... by Andreas Karis
-
fix1
Preview Diff
1 | diff --git a/cloudinit/net/sysconfig.py b/cloudinit/net/sysconfig.py | |||
2 | index 504e4d0..49da3a3 100644 | |||
3 | --- a/cloudinit/net/sysconfig.py | |||
4 | +++ b/cloudinit/net/sysconfig.py | |||
5 | @@ -59,6 +59,9 @@ class ConfigMap(object): | |||
6 | 59 | def __setitem__(self, key, value): | 59 | def __setitem__(self, key, value): |
7 | 60 | self._conf[key] = value | 60 | self._conf[key] = value |
8 | 61 | 61 | ||
9 | 62 | def __getitem__(self, key): | ||
10 | 63 | return self._conf[key] | ||
11 | 64 | |||
12 | 62 | def drop(self, key): | 65 | def drop(self, key): |
13 | 63 | self._conf.pop(key, None) | 66 | self._conf.pop(key, None) |
14 | 64 | 67 | ||
15 | @@ -83,7 +86,8 @@ class ConfigMap(object): | |||
16 | 83 | class Route(ConfigMap): | 86 | class Route(ConfigMap): |
17 | 84 | """Represents a route configuration.""" | 87 | """Represents a route configuration.""" |
18 | 85 | 88 | ||
20 | 86 | route_fn_tpl = '%(base)s/network-scripts/route-%(name)s' | 89 | route_fn_tpl_ipv4 = '%(base)s/network-scripts/route-%(name)s' |
21 | 90 | route_fn_tpl_ipv6 = '%(base)s/network-scripts/route6-%(name)s' | ||
22 | 87 | 91 | ||
23 | 88 | def __init__(self, route_name, base_sysconf_dir): | 92 | def __init__(self, route_name, base_sysconf_dir): |
24 | 89 | super(Route, self).__init__() | 93 | super(Route, self).__init__() |
25 | @@ -102,9 +106,53 @@ class Route(ConfigMap): | |||
26 | 102 | return r | 106 | return r |
27 | 103 | 107 | ||
28 | 104 | @property | 108 | @property |
32 | 105 | def path(self): | 109 | def path_ipv4(self): |
33 | 106 | return self.route_fn_tpl % ({'base': self._base_sysconf_dir, | 110 | return self.route_fn_tpl_ipv4 % ({'base': self._base_sysconf_dir, |
34 | 107 | 'name': self._route_name}) | 111 | 'name': self._route_name}) |
35 | 112 | |||
36 | 113 | @property | ||
37 | 114 | def path_ipv6(self): | ||
38 | 115 | return self.route_fn_tpl_ipv6 % ({'base': self._base_sysconf_dir, | ||
39 | 116 | 'name': self._route_name}) | ||
40 | 117 | |||
41 | 118 | def is_ipv6_route(self, address): | ||
42 | 119 | return ':' in address | ||
43 | 120 | |||
44 | 121 | def to_string(self, proto="ipv4"): | ||
45 | 122 | buf = six.StringIO() | ||
46 | 123 | buf.write(_make_header()) | ||
47 | 124 | if self._conf: | ||
48 | 125 | buf.write("\n") | ||
49 | 126 | # need to reindex IPv4 addresses | ||
50 | 127 | # (because Route can contain a mix of IPv4 and IPv6) | ||
51 | 128 | reindex = -1 | ||
52 | 129 | for key in sorted(self._conf.keys()): | ||
53 | 130 | if 'ADDRESS' in key: | ||
54 | 131 | index = key.replace('ADDRESS', '') | ||
55 | 132 | address_value = str(self._conf[key]) | ||
56 | 133 | # only accept combinations: | ||
57 | 134 | # ipv6 route and proto ipv6 | ||
58 | 135 | # ipv4 route and proto ipv4 | ||
59 | 136 | # do not add any other routes | ||
60 | 137 | if proto == "ipv4" and not self.is_ipv6_route(address_value): | ||
61 | 138 | netmask_value = str(self._conf['NETMASK' + index]) | ||
62 | 139 | gateway_value = str(self._conf['GATEWAY' + index]) | ||
63 | 140 | # increase IPv4 index | ||
64 | 141 | reindex = reindex + 1 | ||
65 | 142 | buf.write("%s=%s\n" % ('ADDRESS' + str(reindex), | ||
66 | 143 | _quote_value(address_value))) | ||
67 | 144 | buf.write("%s=%s\n" % ('GATEWAY' + str(reindex), | ||
68 | 145 | _quote_value(gateway_value))) | ||
69 | 146 | buf.write("%s=%s\n" % ('NETMASK' + str(reindex), | ||
70 | 147 | _quote_value(netmask_value))) | ||
71 | 148 | elif proto == "ipv6" and self.is_ipv6_route(address_value): | ||
72 | 149 | netmask_value = str(self._conf['NETMASK' + index]) | ||
73 | 150 | gateway_value = str(self._conf['GATEWAY' + index]) | ||
74 | 151 | buf.write("%s/%s via %s\n" % (address_value, | ||
75 | 152 | netmask_value, | ||
76 | 153 | gateway_value)) | ||
77 | 154 | |||
78 | 155 | return buf.getvalue() | ||
79 | 108 | 156 | ||
80 | 109 | 157 | ||
81 | 110 | class NetInterface(ConfigMap): | 158 | class NetInterface(ConfigMap): |
82 | @@ -211,65 +259,117 @@ class Renderer(renderer.Renderer): | |||
83 | 211 | iface_cfg[new_key] = old_value | 259 | iface_cfg[new_key] = old_value |
84 | 212 | 260 | ||
85 | 213 | @classmethod | 261 | @classmethod |
98 | 214 | def _render_subnet(cls, iface_cfg, route_cfg, subnet): | 262 | def _render_subnets(cls, iface_cfg, subnets): |
99 | 215 | subnet_type = subnet.get('type') | 263 | # setting base values |
100 | 216 | if subnet_type == 'dhcp6': | 264 | iface_cfg['BOOTPROTO'] = 'none' |
101 | 217 | iface_cfg['DHCPV6C'] = True | 265 | |
102 | 218 | iface_cfg['IPV6INIT'] = True | 266 | # modifying base values according to subnets |
103 | 219 | iface_cfg['BOOTPROTO'] = 'dhcp' | 267 | for i, subnet in enumerate(subnets, start=len(iface_cfg.children)): |
104 | 220 | elif subnet_type in ['dhcp4', 'dhcp']: | 268 | subnet_type = subnet.get('type') |
105 | 221 | iface_cfg['BOOTPROTO'] = 'dhcp' | 269 | if subnet_type == 'dhcp6': |
94 | 222 | elif subnet_type == 'static': | ||
95 | 223 | iface_cfg['BOOTPROTO'] = 'static' | ||
96 | 224 | if subnet_is_ipv6(subnet): | ||
97 | 225 | iface_cfg['IPV6ADDR'] = subnet['address'] | ||
106 | 226 | iface_cfg['IPV6INIT'] = True | 270 | iface_cfg['IPV6INIT'] = True |
107 | 271 | iface_cfg['DHCPV6C'] = True | ||
108 | 272 | iface_cfg['BOOTPROTO'] = 'dhcp' | ||
109 | 273 | elif subnet_type in ['dhcp4', 'dhcp']: | ||
110 | 274 | iface_cfg['BOOTPROTO'] = 'dhcp' | ||
111 | 275 | elif subnet_type == 'static': | ||
112 | 276 | # grep BOOTPROTO sysconfig.txt -A2 | head -3 | ||
113 | 277 | # BOOTPROTO=none|bootp|dhcp | ||
114 | 278 | # 'bootp' or 'dhcp' cause a DHCP client | ||
115 | 279 | # to run on the device. Any other | ||
116 | 280 | # value causes any static configuration | ||
117 | 281 | # in the file to be applied. | ||
118 | 282 | # ==> the following should not be set to 'static' | ||
119 | 283 | # but should remain 'none' | ||
120 | 284 | # if iface_cfg['BOOTPROTO'] == 'none': | ||
121 | 285 | # iface_cfg['BOOTPROTO'] = 'static' | ||
122 | 286 | if subnet_is_ipv6(subnet): | ||
123 | 287 | iface_cfg['IPV6INIT'] = True | ||
124 | 227 | else: | 288 | else: |
170 | 228 | iface_cfg['IPADDR'] = subnet['address'] | 289 | raise ValueError("Unknown subnet type '%s' found" |
171 | 229 | else: | 290 | " for interface '%s'" % (subnet_type, |
172 | 230 | raise ValueError("Unknown subnet type '%s' found" | 291 | iface_cfg.name)) |
173 | 231 | " for interface '%s'" % (subnet_type, | 292 | |
174 | 232 | iface_cfg.name)) | 293 | # set IPv4 and IPv6 static addresses |
175 | 233 | if 'netmask' in subnet: | 294 | ipv4_index = -1 |
176 | 234 | iface_cfg['NETMASK'] = subnet['netmask'] | 295 | ipv6_index = -1 |
177 | 235 | for route in subnet.get('routes', []): | 296 | for i, subnet in enumerate(subnets, start=len(iface_cfg.children)): |
178 | 236 | if subnet.get('ipv6'): | 297 | subnet_type = subnet.get('type') |
179 | 237 | gw_cfg = 'IPV6_DEFAULTGW' | 298 | if subnet_type == 'dhcp6': |
180 | 238 | else: | 299 | continue |
181 | 239 | gw_cfg = 'GATEWAY' | 300 | elif subnet_type in ['dhcp4', 'dhcp']: |
182 | 240 | 301 | continue | |
183 | 241 | if _is_default_route(route): | 302 | elif subnet_type == 'static': |
184 | 242 | if ( | 303 | if subnet_is_ipv6(subnet): |
185 | 243 | (subnet.get('ipv4') and | 304 | ipv6_index = ipv6_index + 1 |
186 | 244 | route_cfg.has_set_default_ipv4) or | 305 | if 'netmask' in subnet and str(subnet['netmask']) != "": |
187 | 245 | (subnet.get('ipv6') and | 306 | ipv6_cidr = (subnet['address'] + |
188 | 246 | route_cfg.has_set_default_ipv6) | 307 | '/' + |
189 | 247 | ): | 308 | str(subnet['netmask'])) |
190 | 248 | raise ValueError("Duplicate declaration of default " | 309 | else: |
191 | 249 | "route found for interface '%s'" | 310 | ipv6_cidr = subnet['address'] |
192 | 250 | % (iface_cfg.name)) | 311 | if ipv6_index == 0: |
193 | 251 | # NOTE(harlowja): ipv6 and ipv4 default gateways | 312 | iface_cfg['IPV6ADDR'] = ipv6_cidr |
194 | 252 | gw_key = 'GATEWAY0' | 313 | elif ipv6_index == 1: |
195 | 253 | nm_key = 'NETMASK0' | 314 | iface_cfg['IPV6ADDR_SECONDARIES'] = ipv6_cidr |
196 | 254 | addr_key = 'ADDRESS0' | 315 | else: |
197 | 255 | # The owning interface provides the default route. | 316 | iface_cfg['IPV6ADDR_SECONDARIES'] = ( |
198 | 256 | # | 317 | iface_cfg['IPV6ADDR_SECONDARIES'] + |
199 | 257 | # TODO(harlowja): add validation that no other iface has | 318 | " " + ipv6_cidr) |
200 | 258 | # also provided the default route? | 319 | else: |
201 | 259 | iface_cfg['DEFROUTE'] = True | 320 | ipv4_index = ipv4_index + 1 |
202 | 260 | if 'gateway' in route: | 321 | if ipv4_index == 0: |
203 | 261 | iface_cfg[gw_cfg] = route['gateway'] | 322 | iface_cfg['IPADDR'] = subnet['address'] |
204 | 262 | route_cfg.has_set_default = True | 323 | if 'netmask' in subnet: |
205 | 263 | else: | 324 | iface_cfg['NETMASK'] = subnet['netmask'] |
206 | 264 | gw_key = 'GATEWAY%s' % route_cfg.last_idx | 325 | else: |
207 | 265 | nm_key = 'NETMASK%s' % route_cfg.last_idx | 326 | iface_cfg['IPADDR' + str(ipv4_index)] = \ |
208 | 266 | addr_key = 'ADDRESS%s' % route_cfg.last_idx | 327 | subnet['address'] |
209 | 267 | route_cfg.last_idx += 1 | 328 | if 'netmask' in subnet: |
210 | 268 | for (old_key, new_key) in [('gateway', gw_key), | 329 | iface_cfg['NETMASK' + str(ipv4_index)] = \ |
211 | 269 | ('netmask', nm_key), | 330 | subnet['netmask'] |
212 | 270 | ('network', addr_key)]: | 331 | |
213 | 271 | if old_key in route: | 332 | @classmethod |
214 | 272 | route_cfg[new_key] = route[old_key] | 333 | def _render_subnet_routes(cls, iface_cfg, route_cfg, subnets): |
215 | 334 | for i, subnet in enumerate(subnets, start=len(iface_cfg.children)): | ||
216 | 335 | for route in subnet.get('routes', []): | ||
217 | 336 | if subnet.get('ipv6'): | ||
218 | 337 | gw_cfg = 'IPV6_DEFAULTGW' | ||
219 | 338 | else: | ||
220 | 339 | gw_cfg = 'GATEWAY' | ||
221 | 340 | |||
222 | 341 | if _is_default_route(route): | ||
223 | 342 | if ( | ||
224 | 343 | (subnet.get('ipv4') and | ||
225 | 344 | route_cfg.has_set_default_ipv4) or | ||
226 | 345 | (subnet.get('ipv6') and | ||
227 | 346 | route_cfg.has_set_default_ipv6) | ||
228 | 347 | ): | ||
229 | 348 | raise ValueError("Duplicate declaration of default " | ||
230 | 349 | "route found for interface '%s'" | ||
231 | 350 | % (iface_cfg.name)) | ||
232 | 351 | # NOTE(harlowja): ipv6 and ipv4 default gateways | ||
233 | 352 | gw_key = 'GATEWAY0' | ||
234 | 353 | nm_key = 'NETMASK0' | ||
235 | 354 | addr_key = 'ADDRESS0' | ||
236 | 355 | # The owning interface provides the default route. | ||
237 | 356 | # | ||
238 | 357 | # TODO(harlowja): add validation that no other iface has | ||
239 | 358 | # also provided the default route? | ||
240 | 359 | iface_cfg['DEFROUTE'] = True | ||
241 | 360 | if 'gateway' in route: | ||
242 | 361 | iface_cfg[gw_cfg] = route['gateway'] | ||
243 | 362 | route_cfg.has_set_default = True | ||
244 | 363 | else: | ||
245 | 364 | gw_key = 'GATEWAY%s' % route_cfg.last_idx | ||
246 | 365 | nm_key = 'NETMASK%s' % route_cfg.last_idx | ||
247 | 366 | addr_key = 'ADDRESS%s' % route_cfg.last_idx | ||
248 | 367 | route_cfg.last_idx += 1 | ||
249 | 368 | for (old_key, new_key) in [('gateway', gw_key), | ||
250 | 369 | ('netmask', nm_key), | ||
251 | 370 | ('network', addr_key)]: | ||
252 | 371 | if old_key in route: | ||
253 | 372 | route_cfg[new_key] = route[old_key] | ||
254 | 273 | 373 | ||
255 | 274 | @classmethod | 374 | @classmethod |
256 | 275 | def _render_bonding_opts(cls, iface_cfg, iface): | 375 | def _render_bonding_opts(cls, iface_cfg, iface): |
257 | @@ -295,15 +395,9 @@ class Renderer(renderer.Renderer): | |||
258 | 295 | iface_subnets = iface.get("subnets", []) | 395 | iface_subnets = iface.get("subnets", []) |
259 | 296 | iface_cfg = iface_contents[iface_name] | 396 | iface_cfg = iface_contents[iface_name] |
260 | 297 | route_cfg = iface_cfg.routes | 397 | route_cfg = iface_cfg.routes |
270 | 298 | if len(iface_subnets) == 1: | 398 | |
271 | 299 | cls._render_subnet(iface_cfg, route_cfg, iface_subnets[0]) | 399 | cls._render_subnets(iface_cfg, iface_subnets) |
272 | 300 | elif len(iface_subnets) > 1: | 400 | cls._render_subnet_routes(iface_cfg, route_cfg, iface_subnets) |
264 | 301 | for i, isubnet in enumerate(iface_subnets, | ||
265 | 302 | start=len(iface_cfg.children)): | ||
266 | 303 | iface_sub_cfg = iface_cfg.copy() | ||
267 | 304 | iface_sub_cfg.name = "%s:%s" % (iface_name, i) | ||
268 | 305 | iface_cfg.children.append(iface_sub_cfg) | ||
269 | 306 | cls._render_subnet(iface_sub_cfg, route_cfg, isubnet) | ||
273 | 307 | 401 | ||
274 | 308 | @classmethod | 402 | @classmethod |
275 | 309 | def _render_bond_interfaces(cls, network_state, iface_contents): | 403 | def _render_bond_interfaces(cls, network_state, iface_contents): |
276 | @@ -387,7 +481,10 @@ class Renderer(renderer.Renderer): | |||
277 | 387 | if iface_cfg: | 481 | if iface_cfg: |
278 | 388 | contents[iface_cfg.path] = iface_cfg.to_string() | 482 | contents[iface_cfg.path] = iface_cfg.to_string() |
279 | 389 | if iface_cfg.routes: | 483 | if iface_cfg.routes: |
281 | 390 | contents[iface_cfg.routes.path] = iface_cfg.routes.to_string() | 484 | contents[iface_cfg.routes.path_ipv4] = \ |
282 | 485 | iface_cfg.routes.to_string("ipv4") | ||
283 | 486 | contents[iface_cfg.routes.path_ipv6] = \ | ||
284 | 487 | iface_cfg.routes.to_string("ipv6") | ||
285 | 391 | return contents | 488 | return contents |
286 | 392 | 489 | ||
287 | 393 | def render_network_state(self, network_state, target=None): | 490 | def render_network_state(self, network_state, target=None): |
288 | diff --git a/tests/unittests/test_distros/test_netconfig.py b/tests/unittests/test_distros/test_netconfig.py | |||
289 | index 8837066..6d6b985 100644 | |||
290 | --- a/tests/unittests/test_distros/test_netconfig.py | |||
291 | +++ b/tests/unittests/test_distros/test_netconfig.py | |||
292 | @@ -431,7 +431,7 @@ NETWORKING=yes | |||
293 | 431 | expected_buf = ''' | 431 | expected_buf = ''' |
294 | 432 | # Created by cloud-init on instance boot automatically, do not edit. | 432 | # Created by cloud-init on instance boot automatically, do not edit. |
295 | 433 | # | 433 | # |
297 | 434 | BOOTPROTO=static | 434 | BOOTPROTO=none |
298 | 435 | DEVICE=eth0 | 435 | DEVICE=eth0 |
299 | 436 | IPADDR=192.168.1.5 | 436 | IPADDR=192.168.1.5 |
300 | 437 | NETMASK=255.255.255.0 | 437 | NETMASK=255.255.255.0 |
301 | @@ -488,7 +488,6 @@ NETWORKING=yes | |||
302 | 488 | mock.patch.object(util, 'load_file', return_value='')) | 488 | mock.patch.object(util, 'load_file', return_value='')) |
303 | 489 | mocks.enter_context( | 489 | mocks.enter_context( |
304 | 490 | mock.patch.object(os.path, 'isfile', return_value=False)) | 490 | mock.patch.object(os.path, 'isfile', return_value=False)) |
305 | 491 | |||
306 | 492 | rh_distro.apply_network(BASE_NET_CFG_IPV6, False) | 491 | rh_distro.apply_network(BASE_NET_CFG_IPV6, False) |
307 | 493 | 492 | ||
308 | 494 | self.assertEqual(len(write_bufs), 4) | 493 | self.assertEqual(len(write_bufs), 4) |
309 | @@ -581,11 +580,10 @@ IPV6_AUTOCONF=no | |||
310 | 581 | expected_buf = ''' | 580 | expected_buf = ''' |
311 | 582 | # Created by cloud-init on instance boot automatically, do not edit. | 581 | # Created by cloud-init on instance boot automatically, do not edit. |
312 | 583 | # | 582 | # |
314 | 584 | BOOTPROTO=static | 583 | BOOTPROTO=none |
315 | 585 | DEVICE=eth0 | 584 | DEVICE=eth0 |
317 | 586 | IPV6ADDR=2607:f0d0:1002:0011::2 | 585 | IPV6ADDR=2607:f0d0:1002:0011::2/64 |
318 | 587 | IPV6INIT=yes | 586 | IPV6INIT=yes |
319 | 588 | NETMASK=64 | ||
320 | 589 | NM_CONTROLLED=no | 587 | NM_CONTROLLED=no |
321 | 590 | ONBOOT=yes | 588 | ONBOOT=yes |
322 | 591 | TYPE=Ethernet | 589 | TYPE=Ethernet |
323 | diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py | |||
324 | index 89e7536..1157c95 100644 | |||
325 | --- a/tests/unittests/test_net.py | |||
326 | +++ b/tests/unittests/test_net.py | |||
327 | @@ -136,7 +136,7 @@ OS_SAMPLES = [ | |||
328 | 136 | """ | 136 | """ |
329 | 137 | # Created by cloud-init on instance boot automatically, do not edit. | 137 | # Created by cloud-init on instance boot automatically, do not edit. |
330 | 138 | # | 138 | # |
332 | 139 | BOOTPROTO=static | 139 | BOOTPROTO=none |
333 | 140 | DEFROUTE=yes | 140 | DEFROUTE=yes |
334 | 141 | DEVICE=eth0 | 141 | DEVICE=eth0 |
335 | 142 | GATEWAY=172.19.3.254 | 142 | GATEWAY=172.19.3.254 |
336 | @@ -204,38 +204,14 @@ nameserver 172.19.0.12 | |||
337 | 204 | # Created by cloud-init on instance boot automatically, do not edit. | 204 | # Created by cloud-init on instance boot automatically, do not edit. |
338 | 205 | # | 205 | # |
339 | 206 | BOOTPROTO=none | 206 | BOOTPROTO=none |
340 | 207 | DEVICE=eth0 | ||
341 | 208 | HWADDR=fa:16:3e:ed:9a:59 | ||
342 | 209 | NM_CONTROLLED=no | ||
343 | 210 | ONBOOT=yes | ||
344 | 211 | TYPE=Ethernet | ||
345 | 212 | USERCTL=no | ||
346 | 213 | """.lstrip()), | ||
347 | 214 | ('etc/sysconfig/network-scripts/ifcfg-eth0:0', | ||
348 | 215 | """ | ||
349 | 216 | # Created by cloud-init on instance boot automatically, do not edit. | ||
350 | 217 | # | ||
351 | 218 | BOOTPROTO=static | ||
352 | 219 | DEFROUTE=yes | 207 | DEFROUTE=yes |
354 | 220 | DEVICE=eth0:0 | 208 | DEVICE=eth0 |
355 | 221 | GATEWAY=172.19.3.254 | 209 | GATEWAY=172.19.3.254 |
356 | 222 | HWADDR=fa:16:3e:ed:9a:59 | 210 | HWADDR=fa:16:3e:ed:9a:59 |
357 | 223 | IPADDR=172.19.1.34 | 211 | IPADDR=172.19.1.34 |
358 | 212 | IPADDR1=10.0.0.10 | ||
359 | 224 | NETMASK=255.255.252.0 | 213 | NETMASK=255.255.252.0 |
374 | 225 | NM_CONTROLLED=no | 214 | NETMASK1=255.255.255.0 |
361 | 226 | ONBOOT=yes | ||
362 | 227 | TYPE=Ethernet | ||
363 | 228 | USERCTL=no | ||
364 | 229 | """.lstrip()), | ||
365 | 230 | ('etc/sysconfig/network-scripts/ifcfg-eth0:1', | ||
366 | 231 | """ | ||
367 | 232 | # Created by cloud-init on instance boot automatically, do not edit. | ||
368 | 233 | # | ||
369 | 234 | BOOTPROTO=static | ||
370 | 235 | DEVICE=eth0:1 | ||
371 | 236 | HWADDR=fa:16:3e:ed:9a:59 | ||
372 | 237 | IPADDR=10.0.0.10 | ||
373 | 238 | NETMASK=255.255.255.0 | ||
375 | 239 | NM_CONTROLLED=no | 215 | NM_CONTROLLED=no |
376 | 240 | ONBOOT=yes | 216 | ONBOOT=yes |
377 | 241 | TYPE=Ethernet | 217 | TYPE=Ethernet |
378 | @@ -265,7 +241,7 @@ nameserver 172.19.0.12 | |||
379 | 265 | }], | 241 | }], |
380 | 266 | "ip_address": "172.19.1.34", "id": "network0" | 242 | "ip_address": "172.19.1.34", "id": "network0" |
381 | 267 | }, { | 243 | }, { |
383 | 268 | "network_id": "public-ipv6", | 244 | "network_id": "public-ipv6-a", |
384 | 269 | "type": "ipv6", "netmask": "", | 245 | "type": "ipv6", "netmask": "", |
385 | 270 | "link": "tap1a81968a-79", | 246 | "link": "tap1a81968a-79", |
386 | 271 | "routes": [ | 247 | "routes": [ |
387 | @@ -276,6 +252,20 @@ nameserver 172.19.0.12 | |||
388 | 276 | } | 252 | } |
389 | 277 | ], | 253 | ], |
390 | 278 | "ip_address": "2001:DB8::10", "id": "network1" | 254 | "ip_address": "2001:DB8::10", "id": "network1" |
391 | 255 | }, { | ||
392 | 256 | "network_id": "public-ipv6-b", | ||
393 | 257 | "type": "ipv6", "netmask": "64", | ||
394 | 258 | "link": "tap1a81968a-79", | ||
395 | 259 | "routes": [ | ||
396 | 260 | ], | ||
397 | 261 | "ip_address": "2001:DB9::10", "id": "network2" | ||
398 | 262 | }, { | ||
399 | 263 | "network_id": "public-ipv6-c", | ||
400 | 264 | "type": "ipv6", "netmask": "64", | ||
401 | 265 | "link": "tap1a81968a-79", | ||
402 | 266 | "routes": [ | ||
403 | 267 | ], | ||
404 | 268 | "ip_address": "2001:DB10::10", "id": "network3" | ||
405 | 279 | }], | 269 | }], |
406 | 280 | "links": [ | 270 | "links": [ |
407 | 281 | { | 271 | { |
408 | @@ -295,41 +285,16 @@ nameserver 172.19.0.12 | |||
409 | 295 | # Created by cloud-init on instance boot automatically, do not edit. | 285 | # Created by cloud-init on instance boot automatically, do not edit. |
410 | 296 | # | 286 | # |
411 | 297 | BOOTPROTO=none | 287 | BOOTPROTO=none |
412 | 298 | DEVICE=eth0 | ||
413 | 299 | HWADDR=fa:16:3e:ed:9a:59 | ||
414 | 300 | NM_CONTROLLED=no | ||
415 | 301 | ONBOOT=yes | ||
416 | 302 | TYPE=Ethernet | ||
417 | 303 | USERCTL=no | ||
418 | 304 | """.lstrip()), | ||
419 | 305 | ('etc/sysconfig/network-scripts/ifcfg-eth0:0', | ||
420 | 306 | """ | ||
421 | 307 | # Created by cloud-init on instance boot automatically, do not edit. | ||
422 | 308 | # | ||
423 | 309 | BOOTPROTO=static | ||
424 | 310 | DEFROUTE=yes | 288 | DEFROUTE=yes |
426 | 311 | DEVICE=eth0:0 | 289 | DEVICE=eth0 |
427 | 312 | GATEWAY=172.19.3.254 | 290 | GATEWAY=172.19.3.254 |
428 | 313 | HWADDR=fa:16:3e:ed:9a:59 | 291 | HWADDR=fa:16:3e:ed:9a:59 |
429 | 314 | IPADDR=172.19.1.34 | 292 | IPADDR=172.19.1.34 |
430 | 315 | NETMASK=255.255.252.0 | ||
431 | 316 | NM_CONTROLLED=no | ||
432 | 317 | ONBOOT=yes | ||
433 | 318 | TYPE=Ethernet | ||
434 | 319 | USERCTL=no | ||
435 | 320 | """.lstrip()), | ||
436 | 321 | ('etc/sysconfig/network-scripts/ifcfg-eth0:1', | ||
437 | 322 | """ | ||
438 | 323 | # Created by cloud-init on instance boot automatically, do not edit. | ||
439 | 324 | # | ||
440 | 325 | BOOTPROTO=static | ||
441 | 326 | DEFROUTE=yes | ||
442 | 327 | DEVICE=eth0:1 | ||
443 | 328 | HWADDR=fa:16:3e:ed:9a:59 | ||
444 | 329 | IPV6ADDR=2001:DB8::10 | 293 | IPV6ADDR=2001:DB8::10 |
445 | 294 | IPV6ADDR_SECONDARIES="2001:DB9::10/64 2001:DB10::10/64" | ||
446 | 330 | IPV6INIT=yes | 295 | IPV6INIT=yes |
447 | 331 | IPV6_DEFAULTGW=2001:DB8::1 | 296 | IPV6_DEFAULTGW=2001:DB8::1 |
449 | 332 | NETMASK= | 297 | NETMASK=255.255.252.0 |
450 | 333 | NM_CONTROLLED=no | 298 | NM_CONTROLLED=no |
451 | 334 | ONBOOT=yes | 299 | ONBOOT=yes |
452 | 335 | TYPE=Ethernet | 300 | TYPE=Ethernet |
FAILED: Continuous integration, rev:e43facbb2b0 b0e88e16c45c8b1 ed14c621bdf3ad /jenkins. ubuntu. com/server/ job/cloud- init-ci/ 263/ /jenkins. ubuntu. com/server/ job/cloud- init-ci/ nodes=metal- amd64/263/ console /jenkins. ubuntu. com/server/ job/cloud- init-ci/ nodes=metal- arm64/263/ console /jenkins. ubuntu. com/server/ job/cloud- init-ci/ nodes=metal- ppc64el/ 263/console /jenkins. ubuntu. com/server/ job/cloud- init-ci/ nodes=metal- s390x/263/ console /jenkins. ubuntu. com/server/ job/cloud- init-ci/ nodes=vm- i386/263/ console
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild: /jenkins. ubuntu. com/server/ job/cloud- init-ci/ 263/rebuild
https:/