blob: cd439e6f881564ee9ed4bcdbd760198d4f6ae04e [file] [log] [blame]
Andrew Jeffery114010c2017-10-06 11:44:56 +10301#!/usr/bin/env python
Andrew Geissler53be16b2017-09-06 16:23:27 -05002
3import argparse
4import requests
Charles P. Hofer88d15b32017-09-12 11:32:55 -05005import tarfile
6import time
Andrew Geissler53be16b2017-09-06 16:23:27 -05007import json
8
9import urllib3
Charles P. Hofere3ec3572017-09-15 13:30:37 -050010#import _sysconfigdata
Andrew Geissler53be16b2017-09-06 16:23:27 -050011urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
12
13
14class BMC:
15 def __init__(self, server):
16 self.url = "https://{0}/".format(server)
17 self.session = requests.Session()
18 self.login()
19
20 def login(self):
21 r = self.session.post(self.url + 'login',
22 json={'data': ['root', '0penBmc']},
23 verify=False)
24 j = r.json()
25 if j['status'] != 'ok':
26 raise Exception("Failed to login: \n" + r.text)
27
28 def list_sfw(self):
29 r = self.session.get(self.url + 'xyz/openbmc_project/software/',
30 verify=False)
31 j = r.json()
32 if j['status'] != 'ok':
Andrew Geissler942eca22017-09-08 11:20:17 -050033 raise Exception("Failed to query software: \n" + r.text)
Andrew Geissler53be16b2017-09-06 16:23:27 -050034
35 events = j['data']
36
37 return events
38
39 def get_image(self, image):
40 r = self.session.get(self.url + image, verify=False)
41
42 j = r.json()
43 if j['status'] != 'ok':
Andrew Geissler942eca22017-09-08 11:20:17 -050044 raise Exception("Failed to get image " + image + ": \n" + r.text)
Andrew Geissler53be16b2017-09-06 16:23:27 -050045
46 return j['data']
47
48 def upload_image(self, image):
Charles P. Hofer88d15b32017-09-12 11:32:55 -050049
Andrew Geissler53be16b2017-09-06 16:23:27 -050050 data = open(image,'rb').read()
51 r = self.session.post(self.url + "/upload/image",
52 data=data,
53 headers={'Content-Type': 'application/octet-stream'},
54 verify=False)
55 j = r.json()
56 if j['status'] != 'ok':
57 raise Exception("Failed to get event " + image + ": \n" + r.text)
58
59 return j['data']
60
Andrew Geissler942eca22017-09-08 11:20:17 -050061 def activate_image(self, image_id):
Charles P. Hofer88d15b32017-09-12 11:32:55 -050062 r = self.session.put(self.url + "/xyz/openbmc_project/software/" + image_id + "/attr/RequestedActivation",
Andrew Geissler64da2182017-09-08 14:06:42 -050063 json={'data': 'xyz.openbmc_project.Software.Activation.RequestedActivations.Active'},
Andrew Geissler942eca22017-09-08 11:20:17 -050064 verify=False)
Charles P. Hofer88d15b32017-09-12 11:32:55 -050065
Andrew Geissler942eca22017-09-08 11:20:17 -050066 j = r.json()
67 if j['status'] != 'ok':
68 raise Exception("Failed to activate image " + image_id + ": \n" + r.text)
69
70 return j['data']
71
Andrew Geisslercb4d0622017-09-21 12:54:01 -050072 def set_priority(self, image_id, priority):
73 r = self.session.put(self.url + "/xyz/openbmc_project/software/" + image_id + "/attr/Priority",
74 json={'data': int(priority)},
75 verify=False)
76
77 j = r.json()
78 if j['status'] != 'ok':
79 raise Exception("Failed to set priority of image " + image_id + ": \n" + r.text)
80
81 return j['data']
82
Andrew Geisslere1b6a3e2017-09-20 21:57:37 -050083 def delete_image(self, image_id):
84 r = self.session.post(self.url + "/xyz/openbmc_project/software/" + image_id + "/action/delete",
85 headers={'Content-Type': 'application/json'},
86 data='{"data":[]}',
87 verify=False)
88
89 j = r.json()
90 if j['status'] != 'ok':
91 raise Exception("Failed to delete image " + image_id + ": \n" + r.text)
92
93 return j['data']
94
Charles P. Hofer88d15b32017-09-12 11:32:55 -050095 def update_auto(self, image, reboot):
96 image_version = self.__get_image_version(image)
97 self.upload_image(image)
98 image_id = self.__wait_for_image_id(image_version)
99 self.activate_image(image_id)
100 self.__wait_for_activation(image_id)
101 if reboot:
102 self.reboot()
103
104 def reboot(self):
105 r = self.session.post(
106 self.url + '/org/openbmc/control/bmc0/action/warmReset',
107 headers={'Content-Type': 'application/json'},
108 data='{"data":[]}',
109 verify=False)
110
111 j = r.json()
112 if j['status'] != 'ok':
113 raise Exception("Failed to reboot BMC:\n" + r.text)
114
115 def __get_image_version(self, image_file_path):
116 # Open up the manfest file.
117 image_tar = tarfile.open(name=image_file_path, mode='r')
118 manifest = image_tar.extractfile('MANIFEST')
119
120 # Find version line.
121 for line in manifest:
122 if line.startswith('version='):
123 manifest.close()
124 image_tar.close()
125 return line.split('version=', 1)[1].strip()
126
127 # If we didn't find the version line, print an error and return false.
128 manifest.close()
129 image_tar.close()
130 raise Exception("Could not find version line in image manifest")
131
132 def __wait_for_image_id(self, image_version):
133 # Try 8 times, once every 15 seconds.
134 for attempt in range(8):
135 software = self.list_sfw()
136 # Look for our the image with the given version in software
137 for path in software:
138 image = self.get_image(path)
Charles P. Hoferc772b472017-09-20 16:02:48 -0500139 if 'Version' in image and image_version == image['Version']:
Charles P. Hofer88d15b32017-09-12 11:32:55 -0500140 return path.split('/')[-1]
141 time.sleep(15)
142 return False
143
144 def __wait_for_activation(self, image_id):
145 # Keep waiting until the image is active or activation fails.
146 active = False
147 while not active:
148 image = self.get_image("/xyz/openbmc_project/software/" + image_id)
149 if 'xyz.openbmc_project.Software.Activation.Activations.Active' \
150 == image['Activation']:
151 print 'Activation Progress: 100%'
152 active = True
153 elif 'xyz.openbmc_project.Software.Activation.Activations.Activating' \
154 == image['Activation']:
155 print 'Activation Progress: ' + str(image['Progress']) + '%'
156 else:
157 raise Exception("Image activation failed. The BMC has set " \
158 + "the'Activation' property to " + image['Activation'])
159 time.sleep(15)
Andrew Geissler53be16b2017-09-06 16:23:27 -0500160
161def do_list_sfw(args):
162 s = BMC(server=args.server)
163 for e in s.list_sfw():
Andrew Geisslercfc7e4c2017-09-20 14:17:12 -0500164 if (e == '/xyz/openbmc_project/software/active'):
165 continue
Andrew Geisslerd4623842017-09-29 13:23:26 -0500166 if (e == '/xyz/openbmc_project/software/functional'):
167 continue
Andrew Geissler53be16b2017-09-06 16:23:27 -0500168 info = s.get_image(e)
Andrew Geisslercfc7e4c2017-09-20 14:17:12 -0500169 if (((info['Purpose'] == 'xyz.openbmc_project.Software.Version.VersionPurpose.BMC') and
170 (args.bmc or not args.host)) or \
171 ((info['Purpose'] == 'xyz.openbmc_project.Software.Version.VersionPurpose.Host') and
172 (args.host or not args.bmc))):
173 print(e)
174 print json.dumps(info, indent=4)
Charles P. Hofer88d15b32017-09-12 11:32:55 -0500175
Andrew Geissler53be16b2017-09-06 16:23:27 -0500176def do_view_image(args):
177 s = BMC(server=args.server)
178 print json.dumps(s.get_image(args.image), indent=4)
179
180def do_upload_image(args):
181 s = BMC(server=args.server)
182 s.upload_image(args.image)
183
Andrew Geissler942eca22017-09-08 11:20:17 -0500184def do_activate_image(args):
185 s = BMC(server=args.server)
186 s.activate_image(args.image_id)
187
Charles P. Hofer88d15b32017-09-12 11:32:55 -0500188def do_update_auto(args):
189 s = BMC(server=args.server)
190 s.update_auto(args.image, args.reboot)
191
Andrew Geisslere1b6a3e2017-09-20 21:57:37 -0500192def do_delete_image(args):
193 s = BMC(server=args.server)
194 s.delete_image(args.image_id)
195
Andrew Geisslercb4d0622017-09-21 12:54:01 -0500196def do_set_priority(args):
197 s = BMC(server=args.server)
198 s.set_priority(args.image_id,args.priority)
199
Andrew Geissler53be16b2017-09-06 16:23:27 -0500200parser = argparse.ArgumentParser()
201parser.add_argument('--server', help='hostname or IP of BMC', type=str,
202 required=True)
203
204subparsers = parser.add_subparsers()
205list_events = subparsers.add_parser('list', help='List all software images on BMC')
206list_events.set_defaults(func=do_list_sfw)
Andrew Geisslercfc7e4c2017-09-20 14:17:12 -0500207list_events.add_argument(
208 '--bmc',
209 action='store_true',
210 default=False,
211 help='Set if you want to see BMC images')
212list_events.add_argument(
213 '--host',
214 action='store_true',
215 default=False,
216 help='Set if you want to see Host images')
Andrew Geissler53be16b2017-09-06 16:23:27 -0500217
218image_view = subparsers.add_parser('view', help='View info of input image')
219image_view.add_argument('image', help='The image to analyze')
220image_view.set_defaults(func=do_view_image)
221
222image_upload = subparsers.add_parser('upload', help='Upload input image')
223image_upload.add_argument('image', help='The image to upload')
224image_upload.set_defaults(func=do_upload_image)
225
Andrew Geissler942eca22017-09-08 11:20:17 -0500226image_activate = subparsers.add_parser('activate', help='Activate input image id')
227image_activate.add_argument('image_id', help='The image id to activate')
228image_activate.set_defaults(func=do_activate_image)
229
Charles P. Hofer88d15b32017-09-12 11:32:55 -0500230image_update_auto = subparsers.add_parser('update_auto', help='Upload and '
231 + 'activate an image, and then reboot the BMC to apply the update '
232 + 'if necessary')
233image_update_auto.add_argument('image', help='The image to update to')
234image_update_auto.add_argument(
235 '--reboot',
Charles P. Hofer88d15b32017-09-12 11:32:55 -0500236 action='store_true',
237 default=False,
238 help='Set if the BMC should reboot after the update')
Charles P. Hofer88d15b32017-09-12 11:32:55 -0500239image_update_auto.set_defaults(func=do_update_auto)
240
Andrew Geisslere1b6a3e2017-09-20 21:57:37 -0500241image_delete = subparsers.add_parser('delete', help='Delete input image id')
242image_delete.add_argument('image_id', help='The image id to delete')
243image_delete.set_defaults(func=do_delete_image)
244
Andrew Geisslercb4d0622017-09-21 12:54:01 -0500245image_priority = subparsers.add_parser('priority', help='Set priority of input image')
246image_priority.add_argument('image_id', help='The image id to set priority of')
247image_priority.add_argument('priority', help='The priority to set')
248image_priority.set_defaults(func=do_set_priority)
249
Andrew Geissler53be16b2017-09-06 16:23:27 -0500250args = parser.parse_args()
251
252if 'func' in args:
253 args.func(args)
254else:
255 parser.print_help()