1# OpenBMC REST API 2 3The primary management interface for OpenBMC is REST. This document provides 4some basic structure and usage examples for the REST interface. 5 6The schema for the rest interface is directly defined by the OpenBMC D-Bus 7structure. Therefore, the objects, attributes and methods closely map to those 8in the D-Bus schema. 9 10For a quick explanation of HTTP verbs and how they relate to a RESTful API, see 11<http://www.restapitutorial.com/lessons/httpmethods.html>. 12 13## Authentication 14 15See the details on authentication at 16https://github.com/openbmc/docs/blob/master/REST-cheatsheet.md 17 18This tutorial uses the basic authentication URL encoding, so just pass in the 19user name and password as part of the URL and no separate login/logout commands 20are required: 21 22``` 23export bmc=<username>:<password>@<hostname> 24``` 25 26## HTTP GET operations & URL structure 27 28There are a few conventions on the URL structure of the OpenBMC rest interface. 29They are: 30 31 - To query the attributes of an object, perform a GET request on the object 32 name, with no trailing slash. For example: 33 34 $ curl -k https://${bmc}/xyz/openbmc_project/inventory/system 35 { 36 "data": { 37 "AssetTag": "", 38 "BuildDate": "", 39 "Cached": 0, 40 "FieldReplaceable": 0, 41 "Manufacturer": "", 42 "Model": "0000000000000000", 43 "PartNumber": "", 44 "Present": 1, 45 "PrettyName": "", 46 "SerialNumber": "0000000000000000" 47 }, 48 "message": "200 OK", 49 "status": "ok" 50 } 51 52 - To query a single attribute, use the `attr/<name>` path. Using the 53 `system` object from above, we can query just the `Name` value: 54 55 $ curl -k https://${bmc}/xyz/openbmc_project/inventory/system/attr/Model 56 { 57 "data": "0000000000000000", 58 "message": "200 OK", 59 "status": "ok" 60 } 61 62 - When a path has a trailing-slash, the response will list the sub objects of 63 the URL. For example, using the same object path as above, but adding a 64 slash: 65 66 $ curl -k https://${bmc}/xyz/openbmc_project/ 67 { 68 "data": [ 69 "/xyz/openbmc_project/dump", 70 "/xyz/openbmc_project/software", 71 "/xyz/openbmc_project/control", 72 "/xyz/openbmc_project/network", 73 "/xyz/openbmc_project/logging", 74 "/xyz/openbmc_project/sensors", 75 "/xyz/openbmc_project/inventory", 76 "/xyz/openbmc_project/user", 77 "/xyz/openbmc_project/time", 78 "/xyz/openbmc_project/led", 79 "/xyz/openbmc_project/state" 80 81 ], 82 "message": "200 OK", 83 "status": "ok" 84 } 85 86 This shows that there are 11 children of the `openbmc_project/` object: 87 `dump`, `software`, `control`, `network`, `logging`, `sensors`, `inventory`, 88 `user`, `time`, `led`, and `state`. This can be used with the base REST URL 89 (ie., `http://${bmc}/`), to discover all objects in the hierarchy. 90 91 - Performing the same query with `/list` will list the child objects 92 *recursively*. 93 94 $ curl -k https://${bmc}/xyz/openbmc_project/network/list 95 { 96 "data": [ 97 "/xyz/openbmc_project/network/config", 98 "/xyz/openbmc_project/network/eth0", 99 "/xyz/openbmc_project/network/eth0/ipv4/3cf9573", 100 "/xyz/openbmc_project/network/eth0/ipv6/c354c06", 101 "/xyz/openbmc_project/network/host0/intf", 102 "/xyz/openbmc_project/network/host0/intf/addr", 103 "/xyz/openbmc_project/network/config/dhcp" 104 ], 105 "message": "200 OK", 106 "status": "ok" 107 } 108 109 - Adding `/enumerate` instead of `/list` will also include the attributes of 110 the listed objects. 111 112 $ curl -k https://${bmc}/xyz/openbmc_project/time/enumerate 113 { 114 "data": { 115 "/xyz/openbmc_project/time/bmc": { 116 "Elapsed": 1511205212119165 117 }, 118 "/xyz/openbmc_project/time/host": { 119 "Elapsed": 1511205212134372 120 }, 121 "/xyz/openbmc_project/time/owner": { 122 "TimeOwner": "xyz.openbmc_project.Time.Owner.Owners.BMC" 123 }, 124 "/xyz/openbmc_project/time/sync_method": { 125 "TimeSyncMethod": "xyz.openbmc_project.Time.Synchronization.Method.NTP" 126 } 127 }, 128 "message": "200 OK", 129 "status": "ok" 130 } 131 132## HTTP PUT operations 133 134PUT operations are for updating an existing resource (an object or property), or 135for creating a new resource when the client already knows where to put it. 136These require a json formatted payload. To get an example of what that looks 137like: 138 139 curl -k https://${bmc}/xyz/openbmc_project/state/host0 > host.json 140 141 $ cat host.json 142 { 143 "data": { 144 "AttemptsLeft": 0, 145 "BootProgress": "xyz.openbmc_project.State.Boot.Progress.ProgressStages.Unspecified", 146 "CurrentHostState": "xyz.openbmc_project.State.Host.HostState.Off", 147 "OperatingSystemState": "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive", 148 "RequestedHostTransition": "xyz.openbmc_project.State.Host.Transition.Off" 149 }, 150 "message": "200 OK", 151 "status": "ok" 152 } 153 154or 155 156 curl -k \ 157 https://${bmc}/xyz/openbmc_project/state/host0/attr/RequestedHostTransition > requested_host.json 158 159 $ cat requested_host.json 160 { 161 "data": "xyz.openbmc_project.State.Host.Transition.Off", 162 "message": "200 OK", 163 "status": "ok" 164 } 165 166When turning around and sending these as requests, delete the message and status 167properties. 168 169To make curl use the correct content type header use the -H option to specify 170that we're sending JSON data: 171 172 curl -k -X PUT -d <json> <url> 173 174A PUT operation on an object requires a complete object. For partial updates 175there is PATCH but that is not implemented yet. As a workaround individual 176attributes are PUTable. 177 178For example, make changes to the requested_host.json file and do a PUT (upload): 179 180 $ cat requested_host.json 181 {"data": "xyz.openbmc_project.State.Host.Transition.On"} 182 183 curl -k -X PUT -T requested_host.json \ 184 https://${bmc}/xyz/openbmc_project/state/host0/attr/RequestedHostTransition 185 186Alternatively specify the json inline with -d: 187 188 curl -k -X PUT \ 189 -d '{"data": "xyz.openbmc_project.State.Host.Transition.On"}' \ 190 https://${bmc}/xyz/openbmc_project/state/host0/attr/RequestedHostTransition 191 192When using '-d' just remember that json requires quoting. 193 194## HTTP POST operations 195POST operations are for calling methods, but also for creating new resources 196when the client doesn't know where to put it. OpenBMC does not support creating 197new resources via REST so any attempt to create a new resource will result in a 198HTTP 403 (Forbidden). 199 200These also require a json formatted payload. 201 202To invoke a method with parameters (Downloading a Tar image via TFTP): 203 204 curl -k -X POST -d '{"data": ["<Image Tarball>", "<TFTP Server>"]}' \ 205 https://${bmc}/xyz/openbmc_project/software/action/DownloadViaTFTP 206 207To invoke a method without parameters (Factory Reset of BMC and Host): 208 209 curl -k -X POST -d '{"data":[]}' \ 210 https://${bmc}/xyz/openbmc_project/software/action/Reset 211 212## HTTP DELETE operations 213DELETE operations are for removing instances. Only D-Bus objects (instances) can 214be removed. If the underlying D-Bus object implements the 215`xyz.openbmc_project.Object.Delete` interface the REST server will call it. If 216`xyz.openbmc_project.Object.Delete` is not implemented, the REST server will 217return a HTTP 403 (Forbidden) error. 218 219For example, to delete the event record with ID 1: 220 221 curl -k -X DELETE https://${bmc}/xyz/openbmc_project/logging/entry/1 222 223 224## Uploading images 225It is possible to upload software upgrade images (for example to upgrade the BMC 226or host software) via REST. The content-type should be set to 227"application/octet-stream". 228 229For example, to upload an image: 230 231 curl -k -H "Content-Type: application/octet-stream" \ 232 -X POST -T <file_to_upload> https://${bmc}/upload/image 233 234In above example, the filename on the BMC will be chosen by the REST server. 235 236It is possible for the user to choose the uploaded file's remote name: 237 238 curl -k -H "Content-Type: application/octet-stream" \ 239 -X PUT -T foo https://${bmc}/upload/image/bar 240 241In above example, the file foo will be saved with the name bar on the BMC. 242 243The operation will either return the version id (hash) of the uploaded file 244on success: 245 246 { 247 "data": "ffdaab9b", 248 "message": "200 OK", 249 "status": "ok" 250 } 251 252or an error message: 253 254 { 255 "data": { 256 "description": "Version already exists or failed to be extracted" 257 }, 258 "message": "400 Bad Request", 259 "status": "error" 260 } 261 262## Event subscription protocol 263It is possible to subscribe to events, of interest, occurring on the BMC. The 264implementation on the BMC uses WebSockets for this purpose, so that clients 265don't have do employ polling. Instead, the rest server on the BMC can push 266data to clients over a websocket. The BMC can push out information 267pertaining to D-Bus InterfacesAdded and PropertiesChanged signals. 268 269Following is a description of the event subscription protocol, with example 270JS code snippets denoting client-side code. 271 272a) The client needs to have logged on to the BMC. 273b) The client needs to open a secure websocket with the URL <BMC IP>/subscribe. 274 275``` 276 var ws = new WebSocket("wss://<BMC IP>/subscribe") 277``` 278 279c) The client needs to send, over the websocket, a JSON dictionary, comprising 280 of key-value pairs. This dictionary serves as the "events filter". All the 281 keys are optional, so the dictionary can be empty if no filtering is desired. 282 The filters represented by each of the key-value pairs are ORed. 283 284 One of the supported keys is "paths". The corresponding value is an array of 285 D-Bus paths. The InterfacesAdded and PropertiesChanged D-Bus signals 286 emanating from any of these path(s) alone, and not from any other paths, will 287 be included in the event message going out of the BMC. 288 289 The other supported key is "interfaces". The corresponding value is an 290 array of D-Bus interfaces. The InterfacesAdded and PropertiesChanged D-Bus 291 signal messages comprising of any of these interfaces will be included in 292 the event message going out of the BMC. 293 294 All of the following are valid: 295 296 ``` 297 var data = JSON.stringify( 298 { 299 "paths": ["/xyz/openbmc_project/logging", "/xyz/openbmc_project/sensors"], 300 "interfaces": ["xyz.openbmc_project.Logging.Entry", "xyz.openbmc_project.Sensor.Value"] 301 }); 302 ws.onopen = function() { 303 ws.send(data); 304 }; 305 ``` 306 307 ``` 308 var data = JSON.stringify( 309 { 310 "paths": ["/xyz/openbmc_project/logging", "/xyz/openbmc_project/sensors"], 311 }); 312 ws.onopen = function() { 313 ws.send(data); 314 }; 315 ``` 316 317 ``` 318 var data = JSON.stringify( 319 { 320 "interfaces": ["xyz.openbmc_project.Logging.Entry", "xyz.openbmc_project.Sensor.Value"] 321 }); 322 ws.onopen = function() { 323 ws.send(data); 324 }; 325 ``` 326 327 ``` 328 var data = JSON.stringify( 329 { 330 }); 331 ws.onopen = function() { 332 ws.send(data); 333 }; 334 ``` 335 336d) The rest server on the BMC will respond over the websocket when a D-Bus event 337 occurs, considering the client supplied filters. The rest servers notifies 338 about InterfacesAdded and PropertiesChanged events. The response is a JSON 339 dictionary as follows : 340 341 InterfacesAdded 342 ``` 343 "event": InterfacesAdded 344 "path": <string : new D-Bus path that was created> 345 "interfaces": <dict : a dictionary of interfaces> (similar to org.freedesktop.DBus.ObjectManager.InterfacesAdded ) 346 ``` 347 348 PropertiesChanged 349 ``` 350 "event": PropertiesChanged 351 "path": <string : D-Bus path whose property changed> 352 "interface": <string : D-Bus interface to which the changed property belongs> 353 "properties": <dict : a dictionary of properties> (similar to org.freedesktop.DBus.Properties.PropertiesChanged) 354 ``` 355