1#!/usr/bin/env python3

2# Copyright 2020 Canonical Ltd.

3# All rights reserved.

4#

5# Written by:

6# Jonathan Cave <jonathan.cave@canonical.com>

7

8 import configparser

9 import os

10 import subprocess as sp

11 import sys

12

13

14 def check_networkmanager(interface, expected_address):

15 def nmcli_field(cmd):

16 val = (

17 sp.check_output(cmd)

18 .decode(sys.stdout.encoding)

19 .strip()

20 .split(":")[1]

21 )

22 return val

23

24 carrier = nmcli_field(

25 [

26 "nmcli",

27 "-t",

28 "--fields",

29 "WIRED-PROPERTIES.CARRIER",

30 "d",

31 "show",

32 interface,

33 ]

34 )

35 if carrier == "off":

36 raise SystemExit("ERROR: No cable present")

37

38 conn_name = nmcli_field(

39 [

40 "nmcli",

41 "-t",

42 "--fields",

43 "GENERAL.CONNECTION",

44 "d",

45 "show",

46 interface,

47 ]

48 )

49 if conn_name == "--":

50 raise SystemExit("ERROR: No connection active on {}".format(interface))

51 print("Connection active on {} is {}".format(interface, conn_name))

52

53 conn_method = nmcli_field(

54 ["nmcli", "-t", "--fields", "ipv4.method", "c", "show", conn_name]

55 )

56 if conn_method == "auto":

57 raise SystemExit("FAIL: connection method {}".format(conn_method))

58

59 address = nmcli_field(

60 ["nmcli", "-t", "--fields", "IP4.ADDRESS", "c", "show", conn_name]

61 )

62 print("Found static address: {}".format(address))

63 if expected_address:

64 if expected_address != address:

65 raise SystemExit("FAIL: address doesn't match")

66

67

68 def check_networkd(interface, expected_address):

69 config_f = "/run/systemd/network/10-netplan-{}.network".format(interface)

70 if not os.path.exists(config_f):

71 raise SystemExit(

72 "ERROR: expected config file does not exist {}".format(config_f)

73 )

74

75 parser = configparser.ConfigParser()

76 parser.optionxform = str

77 parser.read(config_f)

78

79 if "Network" not in parser.sections():

80 raise SystemExit('ERROR: no section "Network" found in config file ')

81

82 if "DHCP" in parser["Network"]:

83 if parser["Network"]["DHCP"] in ("true", "ipv4", "ipv6"):

84 raise SystemExit("FAIL: interface configured for DHCP")

85

86 if "Address" in parser["Network"]:

87 print("Found static address: {}".format(parser["Network"]["Address"]))

88 if expected_address:

89 if expected_address != parser["Network"]["Address"]:

90 raise SystemExit("FAIL: address doesn't match")

91

92

93 def main():

94 if len(sys.argv) != 3:

95 raise SystemExit("USAGE: check_static.py [manager] [interface]")

96 manager = sys.argv[1]

97 interface = sys.argv[2]

98

99 if not os.path.exists("/sys/class/net/{}".format(interface)):

100 raise SystemExit("ERROR: {} doesn't exist".format(interface))

101

102 configuration_key = "STATIC_IP_{}".format(interface.upper())

103 expected_address = os.environ.get(configuration_key)

104 if expected_address:

105 print(

106 "Testing for expected address: {}={}\n".format(

107 configuration_key, expected_address

108 )

109 )

110 else:

111 print("No expected address specified, testing for non-DHCP only")

112 print("Set key {} for address check\n".format(configuration_key))

113

114 if manager == "nm":

115 check_networkmanager(interface, expected_address)

116 elif manager == "networkd":

117 check_networkd(interface, expected_address)

118

119 print("PASS")

120

121

122 if __name__ == "__main__":

123 main()