blob: 46a131a871d15974a742b16cc85be3668905b79e [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
Andrew Geissler53be16b2017-09-06 16:23:27 -05009class BMC:
10 def __init__(self, server):
11 self.url = "https://{0}/".format(server)
12 self.session = requests.Session()
13 self.login()
14
15 def login(self):
16 r = self.session.post(self.url + 'login',
17 json={'data': ['root', '0penBmc']},
18 verify=False)
19 j = r.json()
20 if j['status'] != 'ok':
21 raise Exception("Failed to login: \n" + r.text)
22
23 def list_sfw(self):
24 r = self.session.get(self.url + 'xyz/openbmc_project/software/',
25 verify=False)
26 j = r.json()
27 if j['status'] != 'ok':
Andrew Geissler942eca22017-09-08 11:20:17 -050028 raise Exception("Failed to query software: \n" + r.text)
Andrew Geissler53be16b2017-09-06 16:23:27 -050029
30 events = j['data']
31
32 return events
33
34 def get_image(self, image):
35 r = self.session.get(self.url + image, verify=False)
36
37 j = r.json()
38 if j['status'] != 'ok':
Andrew Geissler942eca22017-09-08 11:20:17 -050039 raise Exception("Failed to get image " + image + ": \n" + r.text)
Andrew Geissler53be16b2017-09-06 16:23:27 -050040
41 return j['data']
42
43 def upload_image(self, image):
Charles P. Hofer88d15b32017-09-12 11:32:55 -050044
Andrew Geissler53be16b2017-09-06 16:23:27 -050045 data = open(image,'rb').read()
46 r = self.session.post(self.url + "/upload/image",
47 data=data,
48 headers={'Content-Type': 'application/octet-stream'},
49 verify=False)
50 j = r.json()
51 if j['status'] != 'ok':
52 raise Exception("Failed to get event " + image + ": \n" + r.text)
53
54 return j['data']
55
Andrew Geissler942eca22017-09-08 11:20:17 -050056 def activate_image(self, image_id):
Charles P. Hofer88d15b32017-09-12 11:32:55 -050057 r = self.session.put(self.url + "/xyz/openbmc_project/software/" + image_id + "/attr/RequestedActivation",
Andrew Geissler64da2182017-09-08 14:06:42 -050058 json={'data': 'xyz.openbmc_project.Software.Activation.RequestedActivations.Active'},
Andrew Geissler942eca22017-09-08 11:20:17 -050059 verify=False)
Charles P. Hofer88d15b32017-09-12 11:32:55 -050060
Andrew Geissler942eca22017-09-08 11:20:17 -050061 j = r.json()
62 if j['status'] != 'ok':
63 raise Exception("Failed to activate image " + image_id + ": \n" + r.text)
64
65 return j['data']
66
Andrew Geisslercb4d0622017-09-21 12:54:01 -050067 def set_priority(self, image_id, priority):
68 r = self.session.put(self.url + "/xyz/openbmc_project/software/" + image_id + "/attr/Priority",
69 json={'data': int(priority)},
70 verify=False)
71
72 j = r.json()
73 if j['status'] != 'ok':
74 raise Exception("Failed to set priority of image " + image_id + ": \n" + r.text)
75
76 return j['data']
77
Andrew Geisslere1b6a3e2017-09-20 21:57:37 -050078 def delete_image(self, image_id):
79 r = self.session.post(self.url + "/xyz/openbmc_project/software/" + image_id + "/action/delete",
80 headers={'Content-Type': 'application/json'},
81 data='{"data":[]}',
82 verify=False)
83
84 j = r.json()
85 if j['status'] != 'ok':
86 raise Exception("Failed to delete image " + image_id + ": \n" + r.text)
87
88 return j['data']
89
Charles P. Hofer88d15b32017-09-12 11:32:55 -050090 def update_auto(self, image, reboot):
91 image_version = self.__get_image_version(image)
92 self.upload_image(image)
93 image_id = self.__wait_for_image_id(image_version)
94 self.activate_image(image_id)
95 self.__wait_for_activation(image_id)
96 if reboot:
97 self.reboot()
98
99 def reboot(self):
Andrew Geissler28adfdc2018-02-28 13:10:30 -0600100 r = self.session.put(
101 self.url + '/xyz/openbmc_project/state/bmc0/attr/RequestedBMCTransition',
Charles P. Hofer88d15b32017-09-12 11:32:55 -0500102 headers={'Content-Type': 'application/json'},
Andrew Geissler28adfdc2018-02-28 13:10:30 -0600103 data='{"data": "xyz.openbmc_project.State.BMC.Transition.Reboot"}',
Charles P. Hofer88d15b32017-09-12 11:32:55 -0500104 verify=False)
105
106 j = r.json()
107 if j['status'] != 'ok':
108 raise Exception("Failed to reboot BMC:\n" + r.text)
109
110 def __get_image_version(self, image_file_path):
111 # Open up the manfest file.
112 image_tar = tarfile.open(name=image_file_path, mode='r')
113 manifest = image_tar.extractfile('MANIFEST')
114
115 # Find version line.
116 for line in manifest:
117 if line.startswith('version='):
118 manifest.close()
119 image_tar.close()
120 return line.split('version=', 1)[1].strip()
121
122 # If we didn't find the version line, print an error and return false.
123 manifest.close()
124 image_tar.close()
125 raise Exception("Could not find version line in image manifest")
126
127 def __wait_for_image_id(self, image_version):
128 # Try 8 times, once every 15 seconds.
129 for attempt in range(8):
130 software = self.list_sfw()
131 # Look for our the image with the given version in software
132 for path in software:
133 image = self.get_image(path)
Charles P. Hoferc772b472017-09-20 16:02:48 -0500134 if 'Version' in image and image_version == image['Version']:
Charles P. Hofer88d15b32017-09-12 11:32:55 -0500135 return path.split('/')[-1]
136 time.sleep(15)
137 return False
138
139 def __wait_for_activation(self, image_id):
140 # Keep waiting until the image is active or activation fails.
141 active = False
142 while not active:
143 image = self.get_image("/xyz/openbmc_project/software/" + image_id)
144 if 'xyz.openbmc_project.Software.Activation.Activations.Active' \
145 == image['Activation']:
146 print 'Activation Progress: 100%'
147 active = True
148 elif 'xyz.openbmc_project.Software.Activation.Activations.Activating' \
149 == image['Activation']:
150 print 'Activation Progress: ' + str(image['Progress']) + '%'
151 else:
152 raise Exception("Image activation failed. The BMC has set " \
153 + "the'Activation' property to " + image['Activation'])
154 time.sleep(15)
Andrew Geissler53be16b2017-09-06 16:23:27 -0500155
156def do_list_sfw(args):
157 s = BMC(server=args.server)
158 for e in s.list_sfw():
Andrew Geisslercfc7e4c2017-09-20 14:17:12 -0500159 if (e == '/xyz/openbmc_project/software/active'):
160 continue
Andrew Geisslerd4623842017-09-29 13:23:26 -0500161 if (e == '/xyz/openbmc_project/software/functional'):
162 continue
Andrew Geissler53be16b2017-09-06 16:23:27 -0500163 info = s.get_image(e)
Nagaraju Gorugantic1a00af2018-11-07 00:52:11 -0600164 if (((info['Purpose'] == 'xyz.openbmc_project.Software.Version.VersionPurpose.BMC') and
Andrew Geisslercfc7e4c2017-09-20 14:17:12 -0500165 (args.bmc or not args.host)) or \
166 ((info['Purpose'] == 'xyz.openbmc_project.Software.Version.VersionPurpose.Host') and
167 (args.host or not args.bmc))):
168 print(e)
169 print json.dumps(info, indent=4)
Charles P. Hofer88d15b32017-09-12 11:32:55 -0500170
Andrew Geissler53be16b2017-09-06 16:23:27 -0500171def do_view_image(args):
172 s = BMC(server=args.server)
173 print json.dumps(s.get_image(args.image), indent=4)
174
175def do_upload_image(args):
176 s = BMC(server=args.server)
177 s.upload_image(args.image)
178
Andrew Geissler942eca22017-09-08 11:20:17 -0500179def do_activate_image(args):
180 s = BMC(server=args.server)
181 s.activate_image(args.image_id)
182
Charles P. Hofer88d15b32017-09-12 11:32:55 -0500183def do_update_auto(args):
184 s = BMC(server=args.server)
185 s.update_auto(args.image, args.reboot)
186
Andrew Geisslere1b6a3e2017-09-20 21:57:37 -0500187def do_delete_image(args):
188 s = BMC(server=args.server)
189 s.delete_image(args.image_id)
190
Andrew Geisslercb4d0622017-09-21 12:54:01 -0500191def do_set_priority(args):
192 s = BMC(server=args.server)
193 s.set_priority(args.image_id,args.priority)
194
Andrew Geissler53be16b2017-09-06 16:23:27 -0500195parser = argparse.ArgumentParser()
196parser.add_argument('--server', help='hostname or IP of BMC', type=str,
197 required=True)
Andrew Jefferybff48b32017-10-06 12:03:00 +1030198parser.add_argument('--suppress-insecure-warnings', '-I', action="store_true",
199 default=False)
Andrew Geissler53be16b2017-09-06 16:23:27 -0500200
201subparsers = parser.add_subparsers()
202list_events = subparsers.add_parser('list', help='List all software images on BMC')
203list_events.set_defaults(func=do_list_sfw)
Andrew Geisslercfc7e4c2017-09-20 14:17:12 -0500204list_events.add_argument(
205 '--bmc',
206 action='store_true',
207 default=False,
208 help='Set if you want to see BMC images')
209list_events.add_argument(
210 '--host',
211 action='store_true',
212 default=False,
213 help='Set if you want to see Host images')
Andrew Geissler53be16b2017-09-06 16:23:27 -0500214
215image_view = subparsers.add_parser('view', help='View info of input image')
216image_view.add_argument('image', help='The image to analyze')
217image_view.set_defaults(func=do_view_image)
218
219image_upload = subparsers.add_parser('upload', help='Upload input image')
220image_upload.add_argument('image', help='The image to upload')
221image_upload.set_defaults(func=do_upload_image)
222
Andrew Geissler942eca22017-09-08 11:20:17 -0500223image_activate = subparsers.add_parser('activate', help='Activate input image id')
224image_activate.add_argument('image_id', help='The image id to activate')
225image_activate.set_defaults(func=do_activate_image)
226
Charles P. Hofer88d15b32017-09-12 11:32:55 -0500227image_update_auto = subparsers.add_parser('update_auto', help='Upload and '
228 + 'activate an image, and then reboot the BMC to apply the update '
229 + 'if necessary')
230image_update_auto.add_argument('image', help='The image to update to')
231image_update_auto.add_argument(
232 '--reboot',
Charles P. Hofer88d15b32017-09-12 11:32:55 -0500233 action='store_true',
234 default=False,
235 help='Set if the BMC should reboot after the update')
Charles P. Hofer88d15b32017-09-12 11:32:55 -0500236image_update_auto.set_defaults(func=do_update_auto)
237
Andrew Geisslere1b6a3e2017-09-20 21:57:37 -0500238image_delete = subparsers.add_parser('delete', help='Delete input image id')
239image_delete.add_argument('image_id', help='The image id to delete')
240image_delete.set_defaults(func=do_delete_image)
241
Andrew Geisslercb4d0622017-09-21 12:54:01 -0500242image_priority = subparsers.add_parser('priority', help='Set priority of input image')
243image_priority.add_argument('image_id', help='The image id to set priority of')
244image_priority.add_argument('priority', help='The priority to set')
245image_priority.set_defaults(func=do_set_priority)
246
Andrew Geissler53be16b2017-09-06 16:23:27 -0500247args = parser.parse_args()
248
Andrew Jefferybff48b32017-10-06 12:03:00 +1030249if args.suppress_insecure_warnings:
Andrew Jeffery23da2732017-10-06 12:03:51 +1030250 from requests.packages.urllib3.exceptions import InsecureRequestWarning
251 requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
Andrew Jefferybff48b32017-10-06 12:03:00 +1030252
Andrew Geissler53be16b2017-09-06 16:23:27 -0500253if 'func' in args:
254 args.func(args)
255else:
256 parser.print_help()