blob: e184301c5a10a753737ba28a6bf83149eae9f90e [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
Andrew Geissler53be16b2017-09-06 16:23:27 -050010urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
11
Andrew Geissler53be16b2017-09-06 16:23:27 -050012class BMC:
13 def __init__(self, server):
14 self.url = "https://{0}/".format(server)
15 self.session = requests.Session()
16 self.login()
17
18 def login(self):
19 r = self.session.post(self.url + 'login',
20 json={'data': ['root', '0penBmc']},
21 verify=False)
22 j = r.json()
23 if j['status'] != 'ok':
24 raise Exception("Failed to login: \n" + r.text)
25
26 def list_sfw(self):
27 r = self.session.get(self.url + 'xyz/openbmc_project/software/',
28 verify=False)
29 j = r.json()
30 if j['status'] != 'ok':
Andrew Geissler942eca22017-09-08 11:20:17 -050031 raise Exception("Failed to query software: \n" + r.text)
Andrew Geissler53be16b2017-09-06 16:23:27 -050032
33 events = j['data']
34
35 return events
36
37 def get_image(self, image):
38 r = self.session.get(self.url + image, verify=False)
39
40 j = r.json()
41 if j['status'] != 'ok':
Andrew Geissler942eca22017-09-08 11:20:17 -050042 raise Exception("Failed to get image " + image + ": \n" + r.text)
Andrew Geissler53be16b2017-09-06 16:23:27 -050043
44 return j['data']
45
46 def upload_image(self, image):
Charles P. Hofer88d15b32017-09-12 11:32:55 -050047
Andrew Geissler53be16b2017-09-06 16:23:27 -050048 data = open(image,'rb').read()
49 r = self.session.post(self.url + "/upload/image",
50 data=data,
51 headers={'Content-Type': 'application/octet-stream'},
52 verify=False)
53 j = r.json()
54 if j['status'] != 'ok':
55 raise Exception("Failed to get event " + image + ": \n" + r.text)
56
57 return j['data']
58
Andrew Geissler942eca22017-09-08 11:20:17 -050059 def activate_image(self, image_id):
Charles P. Hofer88d15b32017-09-12 11:32:55 -050060 r = self.session.put(self.url + "/xyz/openbmc_project/software/" + image_id + "/attr/RequestedActivation",
Andrew Geissler64da2182017-09-08 14:06:42 -050061 json={'data': 'xyz.openbmc_project.Software.Activation.RequestedActivations.Active'},
Andrew Geissler942eca22017-09-08 11:20:17 -050062 verify=False)
Charles P. Hofer88d15b32017-09-12 11:32:55 -050063
Andrew Geissler942eca22017-09-08 11:20:17 -050064 j = r.json()
65 if j['status'] != 'ok':
66 raise Exception("Failed to activate image " + image_id + ": \n" + r.text)
67
68 return j['data']
69
Andrew Geisslercb4d0622017-09-21 12:54:01 -050070 def set_priority(self, image_id, priority):
71 r = self.session.put(self.url + "/xyz/openbmc_project/software/" + image_id + "/attr/Priority",
72 json={'data': int(priority)},
73 verify=False)
74
75 j = r.json()
76 if j['status'] != 'ok':
77 raise Exception("Failed to set priority of image " + image_id + ": \n" + r.text)
78
79 return j['data']
80
Andrew Geisslere1b6a3e2017-09-20 21:57:37 -050081 def delete_image(self, image_id):
82 r = self.session.post(self.url + "/xyz/openbmc_project/software/" + image_id + "/action/delete",
83 headers={'Content-Type': 'application/json'},
84 data='{"data":[]}',
85 verify=False)
86
87 j = r.json()
88 if j['status'] != 'ok':
89 raise Exception("Failed to delete image " + image_id + ": \n" + r.text)
90
91 return j['data']
92
Charles P. Hofer88d15b32017-09-12 11:32:55 -050093 def update_auto(self, image, reboot):
94 image_version = self.__get_image_version(image)
95 self.upload_image(image)
96 image_id = self.__wait_for_image_id(image_version)
97 self.activate_image(image_id)
98 self.__wait_for_activation(image_id)
99 if reboot:
100 self.reboot()
101
102 def reboot(self):
103 r = self.session.post(
104 self.url + '/org/openbmc/control/bmc0/action/warmReset',
105 headers={'Content-Type': 'application/json'},
106 data='{"data":[]}',
107 verify=False)
108
109 j = r.json()
110 if j['status'] != 'ok':
111 raise Exception("Failed to reboot BMC:\n" + r.text)
112
113 def __get_image_version(self, image_file_path):
114 # Open up the manfest file.
115 image_tar = tarfile.open(name=image_file_path, mode='r')
116 manifest = image_tar.extractfile('MANIFEST')
117
118 # Find version line.
119 for line in manifest:
120 if line.startswith('version='):
121 manifest.close()
122 image_tar.close()
123 return line.split('version=', 1)[1].strip()
124
125 # If we didn't find the version line, print an error and return false.
126 manifest.close()
127 image_tar.close()
128 raise Exception("Could not find version line in image manifest")
129
130 def __wait_for_image_id(self, image_version):
131 # Try 8 times, once every 15 seconds.
132 for attempt in range(8):
133 software = self.list_sfw()
134 # Look for our the image with the given version in software
135 for path in software:
136 image = self.get_image(path)
Charles P. Hoferc772b472017-09-20 16:02:48 -0500137 if 'Version' in image and image_version == image['Version']:
Charles P. Hofer88d15b32017-09-12 11:32:55 -0500138 return path.split('/')[-1]
139 time.sleep(15)
140 return False
141
142 def __wait_for_activation(self, image_id):
143 # Keep waiting until the image is active or activation fails.
144 active = False
145 while not active:
146 image = self.get_image("/xyz/openbmc_project/software/" + image_id)
147 if 'xyz.openbmc_project.Software.Activation.Activations.Active' \
148 == image['Activation']:
149 print 'Activation Progress: 100%'
150 active = True
151 elif 'xyz.openbmc_project.Software.Activation.Activations.Activating' \
152 == image['Activation']:
153 print 'Activation Progress: ' + str(image['Progress']) + '%'
154 else:
155 raise Exception("Image activation failed. The BMC has set " \
156 + "the'Activation' property to " + image['Activation'])
157 time.sleep(15)
Andrew Geissler53be16b2017-09-06 16:23:27 -0500158
159def do_list_sfw(args):
160 s = BMC(server=args.server)
161 for e in s.list_sfw():
Andrew Geisslercfc7e4c2017-09-20 14:17:12 -0500162 if (e == '/xyz/openbmc_project/software/active'):
163 continue
Andrew Geisslerd4623842017-09-29 13:23:26 -0500164 if (e == '/xyz/openbmc_project/software/functional'):
165 continue
Andrew Geissler53be16b2017-09-06 16:23:27 -0500166 info = s.get_image(e)
Andrew Geisslercfc7e4c2017-09-20 14:17:12 -0500167 if (((info['Purpose'] == 'xyz.openbmc_project.Software.Version.VersionPurpose.BMC') and
168 (args.bmc or not args.host)) or \
169 ((info['Purpose'] == 'xyz.openbmc_project.Software.Version.VersionPurpose.Host') and
170 (args.host or not args.bmc))):
171 print(e)
172 print json.dumps(info, indent=4)
Charles P. Hofer88d15b32017-09-12 11:32:55 -0500173
Andrew Geissler53be16b2017-09-06 16:23:27 -0500174def do_view_image(args):
175 s = BMC(server=args.server)
176 print json.dumps(s.get_image(args.image), indent=4)
177
178def do_upload_image(args):
179 s = BMC(server=args.server)
180 s.upload_image(args.image)
181
Andrew Geissler942eca22017-09-08 11:20:17 -0500182def do_activate_image(args):
183 s = BMC(server=args.server)
184 s.activate_image(args.image_id)
185
Charles P. Hofer88d15b32017-09-12 11:32:55 -0500186def do_update_auto(args):
187 s = BMC(server=args.server)
188 s.update_auto(args.image, args.reboot)
189
Andrew Geisslere1b6a3e2017-09-20 21:57:37 -0500190def do_delete_image(args):
191 s = BMC(server=args.server)
192 s.delete_image(args.image_id)
193
Andrew Geisslercb4d0622017-09-21 12:54:01 -0500194def do_set_priority(args):
195 s = BMC(server=args.server)
196 s.set_priority(args.image_id,args.priority)
197
Andrew Geissler53be16b2017-09-06 16:23:27 -0500198parser = argparse.ArgumentParser()
199parser.add_argument('--server', help='hostname or IP of BMC', type=str,
200 required=True)
201
202subparsers = parser.add_subparsers()
203list_events = subparsers.add_parser('list', help='List all software images on BMC')
204list_events.set_defaults(func=do_list_sfw)
Andrew Geisslercfc7e4c2017-09-20 14:17:12 -0500205list_events.add_argument(
206 '--bmc',
207 action='store_true',
208 default=False,
209 help='Set if you want to see BMC images')
210list_events.add_argument(
211 '--host',
212 action='store_true',
213 default=False,
214 help='Set if you want to see Host images')
Andrew Geissler53be16b2017-09-06 16:23:27 -0500215
216image_view = subparsers.add_parser('view', help='View info of input image')
217image_view.add_argument('image', help='The image to analyze')
218image_view.set_defaults(func=do_view_image)
219
220image_upload = subparsers.add_parser('upload', help='Upload input image')
221image_upload.add_argument('image', help='The image to upload')
222image_upload.set_defaults(func=do_upload_image)
223
Andrew Geissler942eca22017-09-08 11:20:17 -0500224image_activate = subparsers.add_parser('activate', help='Activate input image id')
225image_activate.add_argument('image_id', help='The image id to activate')
226image_activate.set_defaults(func=do_activate_image)
227
Charles P. Hofer88d15b32017-09-12 11:32:55 -0500228image_update_auto = subparsers.add_parser('update_auto', help='Upload and '
229 + 'activate an image, and then reboot the BMC to apply the update '
230 + 'if necessary')
231image_update_auto.add_argument('image', help='The image to update to')
232image_update_auto.add_argument(
233 '--reboot',
Charles P. Hofer88d15b32017-09-12 11:32:55 -0500234 action='store_true',
235 default=False,
236 help='Set if the BMC should reboot after the update')
Charles P. Hofer88d15b32017-09-12 11:32:55 -0500237image_update_auto.set_defaults(func=do_update_auto)
238
Andrew Geisslere1b6a3e2017-09-20 21:57:37 -0500239image_delete = subparsers.add_parser('delete', help='Delete input image id')
240image_delete.add_argument('image_id', help='The image id to delete')
241image_delete.set_defaults(func=do_delete_image)
242
Andrew Geisslercb4d0622017-09-21 12:54:01 -0500243image_priority = subparsers.add_parser('priority', help='Set priority of input image')
244image_priority.add_argument('image_id', help='The image id to set priority of')
245image_priority.add_argument('priority', help='The priority to set')
246image_priority.set_defaults(func=do_set_priority)
247
Andrew Geissler53be16b2017-09-06 16:23:27 -0500248args = parser.parse_args()
249
250if 'func' in args:
251 args.func(args)
252else:
253 parser.print_help()