Add new RHEL7 logvol objects to master
[pykickstart.git] / pykickstart / commands / network.py
blob77c16f74f1869f1bff6a398ec985aaede7108cd0
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
25 import gettext
26 import warnings
27 _ = lambda x: gettext.ldgettext("pykickstart", x)
29 MIN_VLAN_ID = 0
30 MAX_VLAN_ID = 4095
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", "")
53 def __eq__(self, y):
54 if not y:
55 return False
57 return self.device and self.device == y.device
59 def __ne__(self, y):
60 return not self == y
62 def _getArgsAsStr(self):
63 retval = ""
65 if self.bootProto != "":
66 retval += " --bootproto=%s" % self.bootProto
67 if self.dhcpclass != "":
68 retval += " --dhcpclass=%s" % self.dhcpclass
69 if self.device != "":
70 retval += " --device=%s" % self.device
71 if self.essid != "":
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
79 if self.ip != "":
80 retval += " --ip=%s" % self.ip
81 if self.mtu != "":
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
87 if self.nodns:
88 retval += " --nodns"
89 if not self.onboot:
90 retval += " --onboot=off"
91 if self.wepkey != "":
92 retval += " --wepkey=%s" % self.wepkey
94 return retval
96 def __str__(self):
97 retval = BaseData.__str__(self)
98 retval += "network %s\n" % self._getArgsAsStr()
99 return retval
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)
112 if self.notksdevice:
113 retval += " --notksdevice"
115 return retval
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)
129 if self.noipv4:
130 retval += " --noipv4"
131 if self.noipv6:
132 retval += " --noipv6"
134 return retval
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)
147 if self.ipv6 != "":
148 retval += " --ipv6=%s" % self.ipv6
150 return retval
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)
165 if self.activate:
166 retval += " --activate"
167 if self.nodefroute:
168 retval += " --nodefroute"
169 if self.wpakey != "":
170 retval += " --wpakey=%s" % self.wpakey
172 return retval
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
192 if self.vlanid:
193 retval += " --vlanid %s" % self.vlanid
194 if self.ipv6gateway:
195 retval += " --ipv6gateway %s" % self.ipv6gateway
197 return retval
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
212 if self.teamslaves:
213 slavecfgs = []
214 for slave, config in self.teamslaves:
215 if config:
216 config = "'" + config + "'"
217 slavecfgs.append(slave+config)
218 slavecfgs = ",".join(slavecfgs).replace('"', r'\"')
219 retval += ' --teamslaves="%s"' % slavecfgs
220 if self.teamconfig:
221 retval += ' --teamconfig="%s"' % self.teamconfig.replace('"', r'\"')
222 return retval
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
237 return retval
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)
250 if self.notksdevice:
251 retval += " --notksdevice"
253 return retval
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)
270 if self.activate:
271 retval += " --activate"
272 if self.nodefroute:
273 retval += " --nodefroute"
274 if self.vlanid:
275 retval += " --vlanid %s" % self.vlanid
276 if self.bondslaves:
277 retval += " --bondslaves %s" % self.bondslaves
278 if self.bondopts:
279 retval += " --bondopts %s" % self.bondopts
282 return retval
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
297 return retval
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,
306 BOOTPROTO_STATIC]
308 self.op = self._getParser()
310 self.network = kwargs.get("network", [])
312 def __str__(self):
313 retval = ""
315 for nic in self.network:
316 retval += nic.__str__()
318 if retval != "":
319 return "# Network information\n" + retval
320 else:
321 return ""
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",
339 default=False)
340 op.add_option("--onboot", dest="onboot", action="store",
341 type="ksboolean")
342 op.add_option("--wepkey", dest="wepkey")
343 return op
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)
355 return nd
357 def dataList(self):
358 return self.network
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",
367 default=False)
368 return op
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",
377 default=False)
378 op.add_option("--noipv6", dest="noipv6", action="store_true",
379 default=False)
380 return op
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")
389 return op
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)
404 return op
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",
417 default=False)
418 op.add_option("--nodefroute", dest="nodefroute", action="store_true",
419 default=False)
420 op.add_option("--wpakey", dest="wpakey", action="store", default="")
421 return op
423 class F18_Network(F16_Network):
425 @property
426 def hostname(self):
427 for nd in self.dataList():
428 if nd.hostname:
429 return nd.hostname
430 return None
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",
437 default="")
438 op.add_option("--bondopts", dest="bondopts", action="store",
439 default="")
440 op.add_option("--vlanid", dest="vlanid")
441 op.add_option("--ipv6gateway", dest="ipv6gateway", action="store",
442 default="")
443 return op
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"
452 teamslaves = []
453 if value:
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"}'"
464 if not parts[-1]:
465 # just remove it
466 parts = parts[:-1]
467 # if not (our example), add empty config for the last device
468 else:
469 parts.append('')
470 # parts == ['eth1,eth2', '{"prio": 100}', ',eth3', '']
471 # zip devices with their configs
472 it = iter(parts)
473 for devs, cfg in zip(it,it):
474 # first loop:
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
479 for d in devs[:-1]:
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",
491 default="")
492 return op
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",
498 default="")
499 return op
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",
508 default=False)
509 return op
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)
524 return op
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",
537 default=False)
538 op.add_option("--nodefroute", dest="nodefroute", action="store_true",
539 default=False)
540 op.add_option("--vlanid", dest="vlanid")
541 op.add_option("--bondslaves", dest="bondslaves")
542 op.add_option("--bondopts", dest="bondopts")
543 return op
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)
557 vlan_id = None
559 # if it contains '.', vlan id should follow (eg 'ens7.171', 'mydev.171')
560 (vlan, dot, id_candidate) = name.partition(".")
561 if dot:
562 # 'vlan' can't be followed by a '.'
563 if vlan == "vlan":
564 return _("When using the <prefix>.<vlan id> interface name notation, <prefix> can't be equal to 'vlan'.")
565 try:
566 vlan_id = int(id_candidate)
567 except ValueError:
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
574 try:
575 vlan_id = int(id_candidate)
576 except ValueError:
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)
585 return None
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",
591 default="")
592 return op
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))
604 return retval