lib/url: Include port in pb_url_to_string()
[petitboot] / utils / ipmi-mailbox-config.py
1 #!/usr/bin/env python3
2
3 import argparse
4 import subprocess
5
6 def send_block_read_command(hostname, username, password, index, dry_run):
7
8     if hostname is None and dry_run:
9         hostname = "<hostname>"
10
11     cmd = "ipmitool -I lanplus -H " + hostname
12     if username is not None:
13         cmd = cmd + " -U " + username
14     if password is not None:
15         cmd = cmd + " -P " + password
16
17     # chassis netfn, get-sys-boot-options, parameter 7, set-sel, block-sel
18     cmd = cmd + " raw 0x00 0x09 0x07 " + hex(index) + " 0x00 "
19
20     print(cmd)
21     if not dry_run:
22         rc = subprocess.call(cmd, shell=True)
23         if rc != 0:
24             print("Command returned error: {}".format(rc))
25
26 def send_block_command(hostname, username, password, block, index, dry_run):
27
28     if hostname is None and dry_run:
29         hostname = "<hostname>"
30
31     cmd = "ipmitool -I lanplus -H " + hostname
32     if username is not None:
33         cmd = cmd + " -U " + username
34     if password is not None:
35         cmd = cmd + " -P " + password
36
37     # chassis netfn, set-sys-boot-options, parameter 7, set-sel, block-sel
38     cmd = cmd + " raw 0x00 0x08 0x07 " + hex(index) + " " + block
39
40     print(cmd)
41     if not dry_run:
42         rc = subprocess.call(cmd, shell=True)
43         if rc != 0:
44             print("Command returned error: {}".format(rc))
45
46 def construct_buffer(config, max_blocks):
47
48     # Add IBM's IANA prefix
49     raw = bytes([0x02, 0x00, 0x00]) + config.encode('ascii')
50
51     n_blocks = int(len(raw) / 16)
52     if len(raw) % 16 != 0:
53         n_blocks += 1
54
55     if n_blocks > 255:
56         print("ERROR: buffer would require {} blocks".format(n_blocks) +
57                 " which is more than hypothetically possible (255)")
58         return None
59
60     if n_blocks > max_blocks:
61         print("ERROR: buffer would require {} blocks".format(n_blocks) +
62                 " which is more than max_blocks ({})".format(max_blocks))
63         return None
64
65     if n_blocks > 5:
66         print("Warning: buffer would require {} blocks".format(n_blocks) +
67                 "which is more than some BMCs support")
68
69     blocks = []
70     rem = len(raw)
71     for i in range(n_blocks):
72         block = ""
73         if rem >= 16:
74             last = 16
75         else:
76             last = rem
77
78         for j in range(16):
79             if j < last:
80                 block += "{:#02x} ".format(raw[i * 16 + j])
81             else:
82                 # Pad out to 16 bytes
83                 block += "0x00 "
84
85
86         blocks.append(block)
87         rem -= last
88
89     if n_blocks < max_blocks:
90         for i in range(max_blocks - n_blocks):
91             blocks.append("0x00 0x00 0x00 0x00 " +
92                           "0x00 0x00 0x00 0x00 " +
93                           "0x00 0x00 0x00 0x00 " +
94                           "0x00 0x00 0x00 0x00")
95
96     return blocks
97
98 def construct_empty_buffer(max_blocks):
99
100     blocks = []
101     for i in range(max_blocks):
102         blocks.append("0x00 0x00 0x00 0x00 " +
103                       "0x00 0x00 0x00 0x00 " +
104                       "0x00 0x00 0x00 0x00 " +
105                       "0x00 0x00 0x00 0x00")
106
107     return blocks
108
109 def main():
110
111     parser = argparse.ArgumentParser()
112     parser.add_argument("-b", "--bmc-hostname")
113     parser.add_argument("-u", "--username")
114     parser.add_argument("-p", "--password")
115     parser.add_argument("-n", "--dry-run", action="store_true")
116     parser.add_argument("-c", "--config")
117     parser.add_argument("-x", "--clear", action="store_true")
118     parser.add_argument("-d", "--dump", action="store_true")
119     parser.add_argument("-m", "--max-blocks")
120
121     args = parser.parse_args()
122
123     if not args.dry_run and args.bmc_hostname is None:
124         print("No hostname specified!")
125         return -1
126
127     if args.config and args.clear:
128         print("Can't specify --config and --clear together")
129         return -1
130
131     if args.max_blocks:
132         n_blocks = int(args.max_blocks)
133     else:
134         n_blocks = 16
135
136
137     if args.config or args.clear:
138         if args.config:
139             blocks = construct_buffer(args.config, int(args.max_blocks))
140         if args.clear:
141             blocks = construct_empty_buffer(int(args.max_blocks))
142         if blocks is None:
143             print("Failed to construct buffer")
144             return -1
145
146         print("{} blocks to send".format(len(blocks)))
147         print("---------------------------------------")
148         for i in range(len(blocks)):
149             try:
150                 send_block_command(args.bmc_hostname, args.username, args.password,
151                         blocks[i], i, args.dry_run)
152             except Exception as e:
153                 print(e)
154                 print("Error sending block {}".format(i))
155                 return -1
156             i += 1
157
158     if args.dump:
159         print("\nReading {} blocks".format(n_blocks))
160         print("---------------------------------------")
161         for i in range(n_blocks):
162             send_block_read_command(args.bmc_hostname, args.username,
163                     args.password, i, args.dry_run)
164
165 if __name__ == "__main__":
166     main()