2 # Chris Lumens <clumens@redhat.com>
4 # Copyright 2005, 2006, 2007, 2008 Red Hat, Inc.
6 # This copyrighted material is made available to anyone wishing to use, modify,
7 # copy, or redistribute it subject to the terms and conditions of the GNU
8 # General Public License v.2. This program is distributed in the hope that it
9 # will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
10 # implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 # See the GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License along with
14 # this program; if not, write to the Free Software Foundation, Inc., 51
15 # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
16 # trademarks that are incorporated in the source code or documentation are not
17 # subject to the GNU General Public License and may only be used or replicated
18 # with the express permission of Red Hat, Inc.
20 from pykickstart
.base
import BaseData
, KickstartCommand
21 from pykickstart
.constants
import BOOTPROTO_BOOTP
, BOOTPROTO_DHCP
, BOOTPROTO_IBFT
, BOOTPROTO_QUERY
, BOOTPROTO_STATIC
22 from pykickstart
.options
import KSOptionParser
23 from pykickstart
.errors
import KickstartValueError
, formatErrorMsg
27 _
= lambda x
: gettext
.ldgettext("pykickstart", x
)
32 class FC3_NetworkData(BaseData
):
33 removedKeywords
= BaseData
.removedKeywords
34 removedAttrs
= BaseData
.removedAttrs
36 def __init__(self
, *args
, **kwargs
):
37 BaseData
.__init
__(self
, *args
, **kwargs
)
38 self
.bootProto
= kwargs
.get("bootProto", BOOTPROTO_DHCP
)
39 self
.dhcpclass
= kwargs
.get("dhcpclass", "")
40 self
.device
= kwargs
.get("device", "")
41 self
.essid
= kwargs
.get("essid", "")
42 self
.ethtool
= kwargs
.get("ethtool", "")
43 self
.gateway
= kwargs
.get("gateway", "")
44 self
.hostname
= kwargs
.get("hostname", "")
45 self
.ip
= kwargs
.get("ip", "")
46 self
.mtu
= kwargs
.get("mtu", "")
47 self
.nameserver
= kwargs
.get("nameserver", "")
48 self
.netmask
= kwargs
.get("netmask", "")
49 self
.nodns
= kwargs
.get("nodns", False)
50 self
.onboot
= kwargs
.get("onboot", True)
51 self
.wepkey
= kwargs
.get("wepkey", "")
57 return self
.device
and self
.device
== y
.device
62 def _getArgsAsStr(self
):
65 if self
.bootProto
!= "":
66 retval
+= " --bootproto=%s" % self
.bootProto
67 if self
.dhcpclass
!= "":
68 retval
+= " --dhcpclass=%s" % self
.dhcpclass
70 retval
+= " --device=%s" % self
.device
72 retval
+= " --essid=\"%s\"" % self
.essid
73 if self
.ethtool
!= "":
74 retval
+= " --ethtool=\"%s\"" % self
.ethtool
75 if self
.gateway
!= "":
76 retval
+= " --gateway=%s" % self
.gateway
77 if self
.hostname
!= "":
78 retval
+= " --hostname=%s" % self
.hostname
80 retval
+= " --ip=%s" % self
.ip
82 retval
+= " --mtu=%s" % self
.mtu
83 if self
.nameserver
!= "":
84 retval
+= " --nameserver=%s" % self
.nameserver
85 if self
.netmask
!= "":
86 retval
+= " --netmask=%s" % self
.netmask
90 retval
+= " --onboot=off"
92 retval
+= " --wepkey=%s" % self
.wepkey
97 retval
= BaseData
.__str
__(self
)
98 retval
+= "network %s\n" % self
._getArgsAsStr
()
101 class FC4_NetworkData(FC3_NetworkData
):
102 removedKeywords
= FC3_NetworkData
.removedKeywords
103 removedAttrs
= FC3_NetworkData
.removedAttrs
105 def __init__(self
, *args
, **kwargs
):
106 FC3_NetworkData
.__init
__(self
, *args
, **kwargs
)
107 self
.notksdevice
= kwargs
.get("notksdevice", False)
109 def _getArgsAsStr(self
):
110 retval
= FC3_NetworkData
._getArgsAsStr
(self
)
113 retval
+= " --notksdevice"
117 class FC6_NetworkData(FC4_NetworkData
):
118 removedKeywords
= FC4_NetworkData
.removedKeywords
119 removedAttrs
= FC4_NetworkData
.removedAttrs
121 def __init__(self
, *args
, **kwargs
):
122 FC4_NetworkData
.__init
__(self
, *args
, **kwargs
)
123 self
.noipv4
= kwargs
.get("noipv4", False)
124 self
.noipv6
= kwargs
.get("noipv6", False)
126 def _getArgsAsStr(self
):
127 retval
= FC4_NetworkData
._getArgsAsStr
(self
)
130 retval
+= " --noipv4"
132 retval
+= " --noipv6"
136 class F8_NetworkData(FC6_NetworkData
):
137 removedKeywords
= FC6_NetworkData
.removedKeywords
138 removedAttrs
= FC6_NetworkData
.removedAttrs
140 def __init__(self
, *args
, **kwargs
):
141 FC6_NetworkData
.__init
__(self
, *args
, **kwargs
)
142 self
.ipv6
= kwargs
.get("ipv6", "")
144 def _getArgsAsStr(self
):
145 retval
= FC6_NetworkData
._getArgsAsStr
(self
)
148 retval
+= " --ipv6=%s" % self
.ipv6
152 class F16_NetworkData(F8_NetworkData
):
153 removedKeywords
= F8_NetworkData
.removedKeywords
154 removedAttrs
= F8_NetworkData
.removedAttrs
156 def __init__(self
, *args
, **kwargs
):
157 F8_NetworkData
.__init
__(self
, *args
, **kwargs
)
158 self
.activate
= kwargs
.get("activate", False)
159 self
.nodefroute
= kwargs
.get("nodefroute", False)
160 self
.wpakey
= kwargs
.get("wpakey", "")
162 def _getArgsAsStr(self
):
163 retval
= F8_NetworkData
._getArgsAsStr
(self
)
166 retval
+= " --activate"
168 retval
+= " --nodefroute"
169 if self
.wpakey
!= "":
170 retval
+= " --wpakey=%s" % self
.wpakey
174 class F19_NetworkData(F16_NetworkData
):
175 removedKeywords
= F16_NetworkData
.removedKeywords
176 removedAttrs
= F16_NetworkData
.removedAttrs
178 def __init__(self
, *args
, **kwargs
):
179 F16_NetworkData
.__init
__(self
, *args
, **kwargs
)
180 self
.bondslaves
= kwargs
.get("bondslaves", "")
181 self
.bondopts
= kwargs
.get("bondopts", "")
182 self
.vlanid
= kwargs
.get("vlanid", "")
183 self
.ipv6gateway
= kwargs
.get("ipv6gateway", "")
185 def _getArgsAsStr(self
):
186 retval
= F16_NetworkData
._getArgsAsStr
(self
)
188 if self
.bondslaves
!= "":
189 retval
+= " --bondslaves=%s" % self
.bondslaves
190 if self
.bondopts
!= "":
191 retval
+= " --bondopts=%s" % self
.bondopts
193 retval
+= " --vlanid %s" % self
.vlanid
195 retval
+= " --ipv6gateway %s" % self
.ipv6gateway
199 class F20_NetworkData(F19_NetworkData
):
200 removedKeywords
= F19_NetworkData
.removedKeywords
201 removedAttrs
= F19_NetworkData
.removedAttrs
203 def __init__(self
, *args
, **kwargs
):
204 F19_NetworkData
.__init
__(self
, *args
, **kwargs
)
205 self
.teamslaves
= kwargs
.get("teamslaves", [])
206 self
.teamconfig
= kwargs
.get("teamconfig", "")
208 def _getArgsAsStr(self
):
209 retval
= F19_NetworkData
._getArgsAsStr
(self
)
211 # see the tests for format description
214 for slave
, config
in self
.teamslaves
:
216 config
= "'" + config
+ "'"
217 slavecfgs
.append(slave
+config
)
218 slavecfgs
= ",".join(slavecfgs
).replace('"', r
'\"')
219 retval
+= ' --teamslaves="%s"' % slavecfgs
221 retval
+= ' --teamconfig="%s"' % self
.teamconfig
.replace('"', r
'\"')
224 class F21_NetworkData(F20_NetworkData
):
225 removedKeywords
= F20_NetworkData
.removedKeywords
226 removedAttrs
= F20_NetworkData
.removedAttrs
228 def __init__(self
, *args
, **kwargs
):
229 F20_NetworkData
.__init
__(self
, *args
, **kwargs
)
230 self
.interfacename
= kwargs
.get("interfacename", "")
232 def _getArgsAsStr(self
):
233 retval
= F20_NetworkData
._getArgsAsStr
(self
)
234 if self
.interfacename
:
235 retval
+= " --interfacename=%s" % self
.interfacename
239 class RHEL4_NetworkData(FC3_NetworkData
):
240 removedKeywords
= FC3_NetworkData
.removedKeywords
241 removedAttrs
= FC3_NetworkData
.removedAttrs
243 def __init__(self
, *args
, **kwargs
):
244 FC3_NetworkData
.__init
__(self
, *args
, **kwargs
)
245 self
.notksdevice
= kwargs
.get("notksdevice", False)
247 def _getArgsAsStr(self
):
248 retval
= FC3_NetworkData
._getArgsAsStr
(self
)
251 retval
+= " --notksdevice"
255 class RHEL6_NetworkData(F8_NetworkData
):
256 removedKeywords
= F8_NetworkData
.removedKeywords
257 removedAttrs
= F8_NetworkData
.removedAttrs
259 def __init__(self
, *args
, **kwargs
):
260 F8_NetworkData
.__init
__(self
, *args
, **kwargs
)
261 self
.activate
= kwargs
.get("activate", False)
262 self
.nodefroute
= kwargs
.get("nodefroute", False)
263 self
.vlanid
= kwargs
.get("vlanid", "")
264 self
.bondslaves
= kwargs
.get("bondslaves", "")
265 self
.bondopts
= kwargs
.get("bondopts", "")
267 def _getArgsAsStr(self
):
268 retval
= F8_NetworkData
._getArgsAsStr
(self
)
271 retval
+= " --activate"
273 retval
+= " --nodefroute"
275 retval
+= " --vlanid %s" % self
.vlanid
277 retval
+= " --bondslaves %s" % self
.bondslaves
279 retval
+= " --bondopts %s" % self
.bondopts
284 class RHEL7_NetworkData(F20_NetworkData
):
285 removedKeywords
= F20_NetworkData
.removedKeywords
286 removedAttrs
= F20_NetworkData
.removedAttrs
288 def __init__(self
, *args
, **kwargs
):
289 F20_NetworkData
.__init
__(self
, *args
, **kwargs
)
290 self
.interfacename
= kwargs
.get("interfacename", "")
292 def _getArgsAsStr(self
):
293 retval
= F20_NetworkData
._getArgsAsStr
(self
)
294 if self
.interfacename
:
295 retval
+= " --interfacename=%s" % self
.interfacename
299 class FC3_Network(KickstartCommand
):
300 removedKeywords
= KickstartCommand
.removedKeywords
301 removedAttrs
= KickstartCommand
.removedAttrs
303 def __init__(self
, writePriority
=0, *args
, **kwargs
):
304 KickstartCommand
.__init
__(self
, writePriority
, *args
, **kwargs
)
305 self
.bootprotoList
= [BOOTPROTO_DHCP
, BOOTPROTO_BOOTP
,
308 self
.op
= self
._getParser
()
310 self
.network
= kwargs
.get("network", [])
315 for nic
in self
.network
:
316 retval
+= nic
.__str
__()
319 return "# Network information\n" + retval
323 def _getParser(self
):
324 op
= KSOptionParser()
325 op
.add_option("--bootproto", dest
="bootProto",
326 default
=BOOTPROTO_DHCP
,
327 choices
=self
.bootprotoList
)
328 op
.add_option("--dhcpclass", dest
="dhcpclass")
329 op
.add_option("--device", dest
="device")
330 op
.add_option("--essid", dest
="essid")
331 op
.add_option("--ethtool", dest
="ethtool")
332 op
.add_option("--gateway", dest
="gateway")
333 op
.add_option("--hostname", dest
="hostname")
334 op
.add_option("--ip", dest
="ip")
335 op
.add_option("--mtu", dest
="mtu")
336 op
.add_option("--nameserver", dest
="nameserver")
337 op
.add_option("--netmask", dest
="netmask")
338 op
.add_option("--nodns", dest
="nodns", action
="store_true",
340 op
.add_option("--onboot", dest
="onboot", action
="store",
342 op
.add_option("--wepkey", dest
="wepkey")
345 def parse(self
, args
):
346 (opts
, _extra
) = self
.op
.parse_args(args
=args
, lineno
=self
.lineno
)
347 nd
= self
.handler
.NetworkData()
348 self
._setToObj
(self
.op
, opts
, nd
)
349 nd
.lineno
= self
.lineno
351 # Check for duplicates in the data list.
352 if nd
in self
.dataList():
353 warnings
.warn(_("A network device with the name %s has already been defined.") % nd
.device
)
360 class FC4_Network(FC3_Network
):
361 removedKeywords
= FC3_Network
.removedKeywords
362 removedAttrs
= FC3_Network
.removedAttrs
364 def _getParser(self
):
365 op
= FC3_Network
._getParser
(self
)
366 op
.add_option("--notksdevice", dest
="notksdevice", action
="store_true",
370 class FC6_Network(FC4_Network
):
371 removedKeywords
= FC4_Network
.removedKeywords
372 removedAttrs
= FC4_Network
.removedAttrs
374 def _getParser(self
):
375 op
= FC4_Network
._getParser
(self
)
376 op
.add_option("--noipv4", dest
="noipv4", action
="store_true",
378 op
.add_option("--noipv6", dest
="noipv6", action
="store_true",
382 class F8_Network(FC6_Network
):
383 removedKeywords
= FC6_Network
.removedKeywords
384 removedAttrs
= FC6_Network
.removedAttrs
386 def _getParser(self
):
387 op
= FC6_Network
._getParser
(self
)
388 op
.add_option("--ipv6", dest
="ipv6")
391 class F9_Network(F8_Network
):
392 removedKeywords
= F8_Network
.removedKeywords
393 removedAttrs
= F8_Network
.removedAttrs
395 def __init__(self
, writePriority
=0, *args
, **kwargs
):
396 F8_Network
.__init
__(self
, writePriority
, *args
, **kwargs
)
397 self
.bootprotoList
.append(BOOTPROTO_QUERY
)
399 def _getParser(self
):
400 op
= F8_Network
._getParser
(self
)
401 op
.add_option("--bootproto", dest
="bootProto",
402 default
=BOOTPROTO_DHCP
,
403 choices
=self
.bootprotoList
)
406 class F16_Network(F9_Network
):
407 removedKeywords
= F9_Network
.removedKeywords
408 removedAttrs
= F9_Network
.removedAttrs
410 def __init__(self
, writePriority
=0, *args
, **kwargs
):
411 F9_Network
.__init
__(self
, writePriority
, *args
, **kwargs
)
412 self
.bootprotoList
.append(BOOTPROTO_IBFT
)
414 def _getParser(self
):
415 op
= F9_Network
._getParser
(self
)
416 op
.add_option("--activate", dest
="activate", action
="store_true",
418 op
.add_option("--nodefroute", dest
="nodefroute", action
="store_true",
420 op
.add_option("--wpakey", dest
="wpakey", action
="store", default
="")
423 class F18_Network(F16_Network
):
427 for nd
in self
.dataList():
432 class F19_Network(F18_Network
):
434 def _getParser(self
):
435 op
= F18_Network
._getParser
(self
)
436 op
.add_option("--bondslaves", dest
="bondslaves", action
="store",
438 op
.add_option("--bondopts", dest
="bondopts", action
="store",
440 op
.add_option("--vlanid", dest
="vlanid")
441 op
.add_option("--ipv6gateway", dest
="ipv6gateway", action
="store",
445 class F20_Network(F19_Network
):
447 def _getParser(self
):
448 # see the tests for teamslaves option
449 def teamslaves_cb(option
, opt_str
, value
, parser
):
450 # value is of: "<DEV1>['<JSON_CONFIG1>'],<DEV2>['<JSON_CONFIG2>'],..."
451 # for example: "eth1,eth2'{"prio": 100}',eth3"
454 # Although slaves, having optional config, are separated by ","
455 # first extract json configs because they can contain the ","
456 parts
= value
.split("'")
457 # parts == ['eth1,eth2', '{"prio": 100}', ',eth3']
458 # ensure the list has even number of items for further zipping,
459 # for odd number of items
460 if len(parts
) % 2 == 1:
461 # if the list ends with an empty string which must be a leftover
462 # from splitting string not ending with device eg
463 # "eth1,eth2'{"prio":100"}'"
467 # if not (our example), add empty config for the last device
470 # parts == ['eth1,eth2', '{"prio": 100}', ',eth3', '']
471 # zip devices with their configs
473 for devs
, cfg
in zip(it
,it
):
475 # devs == "eth1,eth2", cfg == '{"prio": 100}'
476 devs
= devs
.strip(',').split(',')
477 # devs == ["eth1", "eth2"]
478 # initialize config of all devs but the last one to empty
480 teamslaves
.append((d
, ''))
481 # teamslaves == [("eth1", '')]
482 # and set config of the last device
483 teamslaves
.append((devs
[-1], cfg
))
484 # teamslaves == [('eth1', ''), ('eth2', '{"prio": 100}']
485 parser
.values
.teamslaves
= teamslaves
487 op
= F19_Network
._getParser
(self
)
488 op
.add_option("--teamslaves", dest
="teamslaves", action
="callback",
489 callback
=teamslaves_cb
, nargs
=1, type="string")
490 op
.add_option("--teamconfig", dest
="teamconfig", action
="store",
494 class F21_Network(F20_Network
):
495 def _getParser(self
):
496 op
= F20_Network
._getParser
(self
)
497 op
.add_option("--interfacename", dest
="interfacename", action
="store",
501 class RHEL4_Network(FC3_Network
):
502 removedKeywords
= FC3_Network
.removedKeywords
503 removedAttrs
= FC3_Network
.removedAttrs
505 def _getParser(self
):
506 op
= FC3_Network
._getParser
(self
)
507 op
.add_option("--notksdevice", dest
="notksdevice", action
="store_true",
511 class RHEL5_Network(FC6_Network
):
512 removedKeywords
= FC6_Network
.removedKeywords
513 removedAttrs
= FC6_Network
.removedAttrs
515 def __init__(self
, writePriority
=0, *args
, **kwargs
):
516 FC6_Network
.__init
__(self
, writePriority
, *args
, **kwargs
)
517 self
.bootprotoList
.append(BOOTPROTO_QUERY
)
519 def _getParser(self
):
520 op
= FC6_Network
._getParser
(self
)
521 op
.add_option("--bootproto", dest
="bootProto",
522 default
=BOOTPROTO_DHCP
,
523 choices
=self
.bootprotoList
)
526 class RHEL6_Network(F9_Network
):
527 removedKeywords
= F9_Network
.removedKeywords
528 removedAttrs
= F9_Network
.removedAttrs
530 def __init__(self
, writePriority
=0, *args
, **kwargs
):
531 F9_Network
.__init
__(self
, writePriority
, *args
, **kwargs
)
532 self
.bootprotoList
.append(BOOTPROTO_IBFT
)
534 def _getParser(self
):
535 op
= F9_Network
._getParser
(self
)
536 op
.add_option("--activate", dest
="activate", action
="store_true",
538 op
.add_option("--nodefroute", dest
="nodefroute", action
="store_true",
540 op
.add_option("--vlanid", dest
="vlanid")
541 op
.add_option("--bondslaves", dest
="bondslaves")
542 op
.add_option("--bondopts", dest
="bondopts")
545 def validate_network_interface_name(name
):
546 """Check if the given network interface name is valid, return an error message
547 if an error is found or None if no errors are found
549 :param str name: name to validate
550 :returns: error message or None if no error is found
551 :rtype: str or NoneType
553 # (for reference see the NetworkManager source code:
554 # NetworkManager/src/settings/plugins/ifcfg-rh/reader.c
555 # and the make_vlan_setting function)
559 # if it contains '.', vlan id should follow (eg 'ens7.171', 'mydev.171')
560 (vlan
, dot
, id_candidate
) = name
.partition(".")
562 # 'vlan' can't be followed by a '.'
564 return _("When using the <prefix>.<vlan id> interface name notation, <prefix> can't be equal to 'vlan'.")
566 vlan_id
= int(id_candidate
)
568 return _("If network --interfacename contains a '.', valid vlan id should follow.")
570 # if it starts with 'vlan', vlan id should follow ('vlan171')
571 (empty
, sep
, id_candidate
) = name
.partition("vlan")
572 if sep
and empty
== "":
573 # if we checked only for empty == "", we would evaluate missing interface name as an error
575 vlan_id
= int(id_candidate
)
577 return _("If network --interfacename starts with 'vlan', valid vlan id should follow.")
579 # check if the vlan id is in range
580 if vlan_id
is not None:
581 if not(MIN_VLAN_ID
<= vlan_id
<= MAX_VLAN_ID
):
582 return _("The vlan id out of the %d-%d vlan id range.") % (MIN_VLAN_ID
, MAX_VLAN_ID
)
584 # network interface name seems to be valid (no error found)
587 class RHEL7_Network(F20_Network
):
588 def _getParser(self
):
589 op
= F20_Network
._getParser
(self
)
590 op
.add_option("--interfacename", dest
="interfacename", action
="store",
594 def parse(self
, args
):
595 # call the overridden command to do it's job first
596 retval
= F20_Network
.parse(self
, args
)
598 # validate the network interface name
599 error_message
= validate_network_interface_name(retval
.interfacename
)
600 # something is wrong with the interface name
601 if error_message
is not None:
602 raise KickstartValueError(formatErrorMsg(self
.lineno
,msg
=error_message
))