Hello everyone, and welcome to a really special episode of SolarWinds Lab. I am Patrick Hubbard. And I'm Tim Danner. Why is this so special? Well, because we do an awful lot of how-tos on this show and a few overviews, and we don't have a lot of time, but we always prefer to be on the keyboard and not just yakking. Well, you're pretty good at yakking. Ow. Yeah, it hurts, but it's probably because it's a little bit true. But seriously, we try not to distract our senior architects unless there's a good reason for it. Like when fans from your show start, bugging me on THWACK to do a SolarWinds programming class? Absolutely, and we encourage you guys to go light up the SDK forum, and you've done an amazing job answering those questions. So they know you a little bit certainly from comments, but tell us a little bit about yourself. Well, I've been with SolarWinds since 2007. I am the lead architect for the Orion Platform, and among other jobs, I maintain the SDK and answer questions about it on THWACK. Yeah, so see why I'm looking forward to that? And what's really different about this episode is I've certainly done a couple of different episodes and a THWACKcamp session or two on the API, but what I haven't done is an actual programming class. But you are a programmer. I was a coder. I'll answer to that. And kind of clever but terribly undisciplined, and that was also a really, really long time ago. Ah, thanks for admitting that. So today, we're going to go out in the studio to my desk since this is going to be really detailed and pretty much all screen capture. Also, I'm going to be on my Windows and Linux dev machine, so it will be easier that way. Also because you don't want to do the actual typing right here on the lab desk? That—seriously—I don't know how you guys do that. You fake it 'til you make it, my friend! All right, so we've got Linux coming, that's really cool, and what are you going to show us? First, we'll pull down the SWIS SDK from GitHub. Hmm, I love it! Very open ‘source-y’ distribution. Correct. Then we'll show you how to query data using SWQL and REST. SolarWinds Query Language. Correct. Then we'll do an update using CRUD of some custom properties in Orion. I'm sorry, you had me at SWQL. Okay, so let's do this thing—and this may be the most technical show that we've ever done, so plan on using the pause and playback buttons a lot, and be sure to also check out the show notes below. You ready? Yeah. Then let's head upstairs. All right. All right, welcome to Tim's office. Tim, thanks again for having us up here. Thanks for coming. Yeah. I mean, this is pretty nice here. You've got four monitors. You've got your Linux box. This is like a real setup to actually do some programming. Some real work. Yeah. Now, of course, remind me why it is that we're going to do this on my laptop instead of your multi-monitor setup? Because this laptop has Camtasia on it. That's why. That's true. And of course, this thing also means that you can do everything that you want to do in this episode on one machine. Sure. There's nothing extra. We do have a Linux VM that we're going to show you, so that you can actually do cross operating system port 7778. Yeah, we'll show some stuff from Linux and some stuff from Windows. We don't have Orion installed on this laptop or anything like that. This is all remote API stuff. Awesome. And it's so much more comfortable in here. I like it. Yeah. I took my lab coat off. You know why that is, of course. No coats and ties up here. Because—well, no coats and ties up here. But there's actual development going on this floor. People are actually writing code. And I want to believe that we are of similar ilk in this moment. I'll entertain that. You'll entertain that. All right. So talk us through what we're going to do here. We're going to see this both for Windows and on Linux. Mmm-hmm. So we're going to do PowerShell and then also using REST directly. Correct. Okay, so talk us through the use case for this first session. Okay, so here's the plan. First, I'm going to demonstrate just making a couple of simple calls using the cURL command line tool, just to show that it's just a plain jane HTTP API. Then I'll do a little bit of automation in Python just to show how you can put a little structure around that. Finally, we'll flip over to Windows and I'll show the SQL studio query tool. Okay. And then we'll use PowerShell to do a couple of operations from there, so you can see how that works. Okay, so the first thing that you did here—and I believe we have a video on this and if not—I don't think we do, actually. I'll have a link up to the forum on THWACK where you can see how to do this. First thing you need to do is download the SDK. And once upon a time, you were an MSI installer, and it would unpack on Windows. And now it's located on... It's on GitHub now, so you can go to www.github.com/solarwinds/OrionSDK and pick it up there. And pick it up there. Latest and greatest version is always out there. This is currently 2.0.30 beta 2. Yeah we've got it labeled as a beta now, but it should work for you. Yeah, and they get updated pretty regularly, and of course, I'm not going to completely out you and say that you're always on the forum and always available. But you do mind it pretty closely, and I know you're always working with folks and getting new use cases. >Yes. So if you have questions please bring them to the forum and I'll help you out there. Awesome. Okay so what are we going to do first? You want to do Windows first or Linux? Let's start out on Linux and we'll show closer to the middle. Okay, because then you can actually see what's going on behind the scenes because the C-sharp code and the PowerShell SnapIn are both doing the same thing behind the scenes. We're just going to look at it raw. Exactly. So that you could start without even— you could actually just use the documentation with the SDK without using any of the libraries for Perl or anything else that you'll download from GitHub. You could just do it directly if you want to do REST. But we'll take a look at that and see what that looks like. Right, okay. So I've got my Linux VM here. This is a Windows laptop so we're using PuTTY to get there. Ah, PuTTY. So, we're going to start out with cURL. Let's see, we'll use HTTPS. Orion has a self-signed certificate. So when I'm going to do this, I'm going to get a certificate error. And then I'll show you how to work around that. So you'll suppress the error. Yes, I will. This is another virtual machine where I have Orion installed at that IP address. So it's not a separate add-on. It's just going directly to the same information services that support everything else on that server. That's right, that's right. Okay. And that's our port. And it's 17778 because you're going direct through the interoperability port, not 17777 which would be the .NET TCP port. Exactly. So https for the API happens on 17778, independent of whatever you have set up for the Orion website. v3/Json/Query. So that's our URL. And then we have to provide an argument. And the argument, in this case, is going to be the actual query. And this is a URL, so you have to put pluses for the spaces. You have to escape it. Yeah, yeah. And we're going to show you the SWQL Studio in a minute. And that's really where you can learn and experiment with SWQL, which looks an awful lot like a database query like a SQL Server. But in this case, he's just typing it directly. Right. So there's my certificate error. And it even tells us that if you're okay with that, which we are—this is expected. And this is generally going to be on an internal network anyway. We'll give it dash K to say no certificate error. It doesn't fix no SQL error? Ah, there we go, there we go. That's my typo. That's how you know it's real. I don't know how you do this from memory. I go out to THWACK, I get my parts, and I cut and paste. And then I just derive everything from that. Well, you can do it that way, but I'm showing my steps here. So you see we got no output from that. Okay. Let's see why is that. We'll give cURL-V for verbose. Okay, and then we see 401 unauthorized. We've got to give it a username and password. Okay, well we can do that. And the option for that in cURL is that. So I'm going to give—this is an Orion username and password. If you have actor directory integration set up with Orion, you can use Windows usernames and passwords. You'll just pass through like you would with regular logon to the front page of Orion. Exactly, exactly. So I created a user called Tim on that Orion server, and I have my top-secret password that you all get to see. We can blur that out if you want. No, that's okay. All right. I think I am going to blur that out. All right, that's fine. Okay, so there and I can take the dash V off there because we don't need that anymore. And you see what we get back here looks like regular old JSON, because it is. So that's a good thing. And it's also enforcing the same visibility rules you would have, like few limitations on that user. Yes, that's right. So that's another thing: sometimes you might be using a restricted user or maybe that user has limited access based on a custom property or something else. So if you execute the query, you know you're not getting an error, and no data's coming back, just go in and make sure you don't have view restrictions for that user as why you wouldn't get something back. Yes, so if account limitations were preventing me from seeing any results from my query, what I would expect to get back is a JSON object with a results property. And the value of that results property would be an empty array. Okay. All right. So, that shows us getting some results. But doing all this by typing cURL commands... ... gets a little old. ... And the batch would get old quickly. So we're going to write a little script. You can use whatever language you're comfortable with. Of course, you're going to use Emacs. [LAUGH] What else is there? Okay, I'm going to use Python because it looks nice. Python is nice. Python is nice. And I'm going to pull in two libraries. I'm going to pull in the request library, which is a general-purpose REST API client. If you don't already have it installed, you can get it from PIP. And I'm going to pull in the JSON library from this Python standard library. And I'm going to make a class for this. And I'm going to give it a constructor. And I'm going to look at the camera and whisper. I normally would talk during this, but because he's actually typing, I'm being very, very quiet. Okay, thank you. All right. So it's going to take a few parameters—host name or IP address, user name, and password— and it's going to set up a couple of properties. We're going to set up a base URL. That's going to be—put a little placeholder there for me to put the host name in. And there are examples of this in the Python sample code that comes down in the Git repository as well. Yeah, that's right. In fact, what I'm doing is actually very similar to what is in that Python sample. No, but you're doing it for real. That's right. I am typing it out here. Not the user name, the host name. There we go. Okay. So, that gives me a base URL that I can use for the various API sub handlers. And we need to save the credentials. I'm going to put those in a little ‘two-ple,’ user name and password. And then we need a method for a generic request, and I'll put the little underscore for a private method. So we need a fragment of the URL and we need some data. Okay, so what do we do with that? We are going to return requests.request. This is going to be a post. And pass our data. I'm going to tell it do not bother with SSL verification because it is self-signed. If you want to get fancy, there are hooks for validating the thumbprint of the certificate, so you can know that you have the right certificate and that post authentication even with the self-certification that way. Well, I can think of a lot of cases when you're doing that. I mean, especially if you were updating custom properties or something else where you may have compliance or something else that's a part of it. You would probably want to do that securely over the wire. Exactly. And then I'll provide the credentials, so we get HTTP basic authentication. And finally, when we're doing a post request, we need an extra header to specify that we're sending adjacent data. Okay, so now that we have a private method for doing an arbitrary request, we need to do a public method if we're doing a specific request, like a query. Okay, let's see. So they have a query, so we need to make a request. And the fragment that we need to do is just query, like we saw I did in the command line. Right. But instead of sending the query as a query string, we're going to send it as post data. And we're going to send a JSON object… Which contains the body. Yeah, yeah. Let's see. And I just realized I made a mistake up here. I don't want to send a Python object. I need to dump it as JSON. You should probably do that. Yeah. All right, so we'll send the query there. If we had query parameters, you could add that there too, but I'm not going to include that in this little demo. And I want to make another method for another kind of API called an update. And so to do an update you need to provide SwisClient URI, and you need to provide the properties you want to update. And with the star, I'm going to allow us to pass those as key word arguments in Python. Yep. And they'll wind up in here, in this method as a Python dictionary, and then when that goes through the JSON dump; it's going to wind up as a JSON object and it will do the right thing. There's no return value from updates, so I don't need to return. I just need to call that passing the URI as the fragment and the properties as they go. Very simple. Okay. Okay, so just to back up here. You're doing this as a post because you're also going to do updates. If you were just doing queries, you could use get. You could use get. Once you go to the trouble of wrapping it into a whole library and you're not just doing it from the cURL command line, I would just use the post all the time. Okay. There's kind of no harm in it. Because otherwise you're going to end up with two base methods. Exactly, and once you start wanting to use query parameters, you have to use post anyway. Got it. So I'll save that, exit, and fire up my handy Python interactive mode. And then from demo, I'm going to import SwisClient. Okay, so there's that. Now I need to make one. Okay, SwisClient… And that's going to give you a session. Or, it's not a session; it's actually sort of an endpoint. It's not going to create the session until it actually makes the request. Right. So nothing happened on the network right there. All that did was just set up some properties. And then it will make the request when I get an actual one. Okay, so first, let's just do a little test. We'll say swis.query and then do select. We're going to get a few properties. We're going to get a caption. We're going to get a URI that I'm going to need in a minute. And I'm going to get CustomProperties.City FROM Orion.Nodes n… And again, that's just raw SWQL. Yes, exactly. Okay. And you don't have to URL escape it, because it's going to go ahead and get it. All right. And there's my SSL warning again. There is a way to turn that off. It's a little bit verbose. But you can do that to cut down on bad outputs. I can do .urllib3.disable_warnings. Oops. That sounds like something you'd want to actually put in the script. Yeah, [laughs] I would recommend that. But I can do it here. And now when I do the query, no warning. Response okay. Yeah, response okay. You know what I need to do? You have to actually get the JSON out of there. Okay. There we go. So that parsed the response as JSON and returned it as a Python dictionary. Okay. Okay. So, let's see. If you look at, let's say… It's a multidimensional dictionary. Yeah, so node 9 here, it's a Meru access point in our lab. You see it has city none. Well, that's actually located in Austin. So I'm going to go ahead and update that. All right. So we'll do swis.update. And then rather than retyping the URI, I'm just going to copy and paste it there. All right. Yeah, there we go. So the URI, just to remind everybody, we're not just saying the node ID. That's actually essentially a fully qualified locator of where that thing is. Exactly. It's going to be the server that it's running on and then the fact that it's part of nodes and then the ID. So instead of having lots and lots and lots of parameters at the end, it's just fully qualified to say: it's this node on this list of nodes on this server. Yes. One string to uniquely identify it in all the world of Orion. Okay, except we want to access an object even more specific than that. We want to access the custom properties object. That's great. You didn't even have to say object equals custom properties. It just knows off the slash. It's a really restful interface. It's going to check to see if that's a property that's available. If it was one that's always there, it would always be there, but if it's one that you've added to the custom property editor, it's just automatically going to be added. Exactly. Okay. And then in our second argument, now we're in the key words arguments portion of it. So I'm just going to say City=Austin, TX. All right. Done. Okay, and then what I can do is, I can repeat the query. And now we see that node ID 9 has a city Austin, Texas. Yes, great. And the nice thing there is you're taking full advantage of all of the caching properties and the information services. You're using the dot object notation that extends SWQL for being something like basic SQL, or TSQL, where you would normally have to do explicit joins and actually build all of your objects. In this case, it knows things. Like if you're querying interfaces, you can say dot node on an interface and get the node properties for that. And here, again, you're returning native. You're initially expressing and returning native Python dictionary objects, but it's automatically through the convert call converting it into the JSON that it's using behind the scenes to actually push to the server. Right. And now let me show you something here. If I change this and, instead of connecting as myself, I connect as guest and no password, the default permissions in an Orion install, guest is allowed to see things. Right. Oh, but I have an account limitation that says they can only see node ID 1. That's fine. However, if I then go and do the update, and let me change it to node ID if we can actually see—there we go. And it's not going to update it. But, of course in this script, because we just put this together in five minutes—or, you just put this together in five minutes, it would have eaten the fact that you got an error back as a part of that post. You would have gotten JSON back with the error saying you're not allowed to update that node. Yeah, so it actually will give you a 400-series error in HTTP because that's an access error. Okay. So all of the CRUD actions will enforce all of the access permissions based on the users, and the objects, and the node limitations for that logon. Exactly. So, to update a custom property, you need to both be able to see that node, and you need to have managed nodes rights… Got it. —and guest does not have managed nodes rights. Well, do you have a lot of customers that will do that, where they'll build one interface and then make it available to different groups, and then use visibility rules so that they get effectively differentiated APIs without having to build a custom interface for each, with its own internal properties? Exactly. So, rather than having to build your own front end, that checks access and restrictions, you can rely on the SWIS API to do that for you. And that's especially handy. We had a customer tell us the other day; he was doing it with the Active Directory integration. There was a kind of cowboy developer on their team, did a lot of great stuff, also caused a little bit of trouble. And he was involuntarily separated from the company. I see. And was thereby automatically locked out of the API access as well, because as soon as his account was disabled in AD, he couldn't log into Orion, and it also cut off access for the API. The dream of single sign on. I know. It's just a beautiful thing. Wait now. Are we calling Active Directory single sign on, or do you want to call it single authority? Let's call it single authority. Let's call it single authority. We'll be generous. Okay. Okay. I like AD. Okay, Jim, that's awesome. And you know, when you think about interoperability; that can really be a challenge sometimes. This was a piece of cake. I mean, you're executing Python. I think you had less than 20 lines of code in the script itself. You're doing all of it interactively which is nice because you can do discovery right there through the interface. And if you're especially worried, one, you should probably set up a dev environment. Just do an extra download and set it up on a machine while you experiment with it. But you can also, if you're worried about it, again, use the permissions so that you don't have to worry about updating the data in the database, and then just do read only or just use get at first while you're experimenting doing reads, and then transition to posts for updates. Yeah, now you mentioned SWQL Studio before. Yeah. That's a tool you can use for experimenting with a query language to try some things out. It's a little bit friendlier for interactive use than a command line or a Python shell. Yeah, and it's cool because you've got data sets and everything else with it, so you can actually build, like in this case where you were typing sort of off the top of your head. You may have one that's pretty complex, or maybe you're going to go out and get NetFlow data, for example. That is pretty complex. Which can get kind of complex, because there's a lot of data there, and you want to use all the expressiveness of the language. That's a great place to test it, because you'll always get dynamic results back and you can literally just cut and paste it directly into these integrations. Exactly. So, SWQL Studio gets installed with the Orion SDK. Only runs on Windows. Only runs on Windows. You can pull it up from the start menu like that. Hey, that looks like an Orion logon. It is an Orion logon. So, we're going to put in the same VM that I was working with on the Linux side. And I'm going to put in my username and password, which you don't get to see this time. Yes, aren't you glad we blurred it now? All right. So that pulls up here, and we have this tree that shows us all of these name spaces, and then you can expand the name space and see the individual entities. So if I scroll down here, we can see nodes. And if you want, you can even say give me a select statement. And then I hit F5 and I get some results in a little data grid. Now, nodes has an awful lot of properties. It's just a little bit wide. It is a little bit wide. But that's okay; we can trim down to just the properties we want. It's just going to take a few. And we get a smaller result set. If I wanted to refer back to the list, here they are. You can see navigation properties and then verbs. Anyway, if I wanted to, let's say, count my nodes by vendor; I could do that pretty easily. Very much like SQL. Exactly. And now I see in my little test of mine I've got five Ciscos, one Meru that I was editing earlier, etc. And in this case, the aggregate and group by queries, you can see all of that in the SDK. There's documentation for all of that. Exactly, and it mostly works the same as SQL, so if you're familiar with SQL, this query language is very, very similar. And again, that's what's behind the scenes, the web interface, talking to information services, information services talking to remote polars, talking to agents. It's using this exact same language for everything they've done. That's the idea. Yeah, the other day I took SWQL Studio— that's easy for me to say—SWQL Studio and pointed it at virtualization manager on the interoperability port, and it lit up all the objects that are available, and you can see there how Orion is integrating to get the AppStack data from virtualization manager. Yes, exactly. And DPA is the latest product we've added to that stat. So you can get your database performance statistics through this interface, as well. Nice. Okay, and this has undos if you want. If you want to go back to a previous square, you can do that. If you want to pull status, we can pull that. And you see all of these nodes are one. One is up. There's even a status info entity if you need to look up what those numbers mean. That's really awesome. And it's a great way to start learning how to write the SWQL queries that you're going to need. But again, it's really, really easy and you'll probably spend—what would you say?— maybe a third of your time on the base scripts, and then maybe two-thirds of your time in here while you're learning how to actually get data back. Sure, it's a good way to explore. And then once you've gotten to know the schema a little bit—and again, the schema's not going to change when we update the database. This protects you from schema changes because the API schema doesn't change. Once you learn the schema and work with it a little bit, then you'll spend most of your time again working on scripting and making it work in ways that are really specific to your business and your operation. Right. Let's talk a bit how the PowerShell commands work. All right. And then we'll use that to unmanage a node, which is a common request. We will need to flip something into maintenance mode. I was actually talking to someone at VM World a couple of weeks ago, and he's doing the same thing. He's actually got his inventory management system set up so that when they go and add a new box or a new VM, it'll automatically add it to manage it. And then they've got some other things where they put them in out-of-service mode or they'll have planned service outages. They'll set them to manage for a little while and then bring them back in programmatically. Yep, exactly. Okay, so to do that, you need to have the Orion SDK installed to get the PowerShell Snapin. Okay. But once that's installed, you can do add PS Snapin swissnapin. And now we have the information service commands available here. Okay, so first we need to get a connection with connect-Swis. Looks pretty familiar if you just grab your Python into PowerShell here. [Laughs] Yeah, yeah. It's kind of the same stuff in a little bit different syntax. Okay, so now we have a SWIS connection. Though I will note that, like on the Python demo… It's a definition. At this point, we haven't actually connected. But now we're going to do it. So does it connect and disconnect every time there's a request? It does some internal connection caching, but it won't open it until the first one. That's good. So if you update 100,000 objects, you're not going to create 100,000 connections. Yeah. In fact, you know what we're going to do? Let's copy that and paste it over here. And there's my data. And there it is. And in this case, it's formatted as PowerShell objects. Right. So if I wanted to… What do you like better, PowerShell objects, Python dictionaries? It all depends on where I'm working. Oh, that—you were Switzerland. [LAUGH] Get it? Switzerland? No, but seriously, that was very diplomatic. But again, you're returning the native object type so that you're not spending all of your time parsing or converting. Right. So now, I have them in an array, and I can, for example, get the first one. There's my first one—dot vendor. So you can work with these as PowerShell objects. Right. The great thing about PowerShell objects is you can use them in a pipeline. Yes. So you can select some objects and pipe them to some other command and into some other stuff. >>Okay. Let's talk about why that's important. And in this example, in terms of managing and unmanaging, once you get into things like—I gave an example a minute ago of adding a node or putting a node under management that hadn't been there before—you're effectively kicking off discovery. And then you're going to get back a list of objects and then have to choose what you want to add, just like if you were going through the Sonar, you would ask what interface it is, see everything else that you want to monitor. You're still going to have to create an object that's going to return that when you tell it to add that node for monitoring. Yeah, if you're trying to add new notes for management, that'll come into play. Yeah, so when we talk about pipelining and we talk about being able to quickly iterate through here, that's where that's really going to be helpful, when you get those more complex objects that come back. Like, you poll for the end of a discovery and then you walk through the discovery results to identify the one that maybe matched the IP address of something that you set in your IPAM or DHCP, and then automatically add that. To make it fully programmatic, you will do a little bit more scripting. Yeah exactly, exactly. Okay. So, let's see. Having gotten a node, let's go ahead and unmanage it. Okay, so invoke. Invoke -SwisVerb. And the verb we want to invoke is on the Orion.Nodes entity. The verb is called unmanage. Wow, it's complex. I know. Okay, so then we have to pass a list of arguments, and we have to pass them as a PowerShell array. All right. So unmanage takes work. Okay, the first one is the net object ID of the item we want to unmanage. And that's the same that you would see in the URL, if you were looking at it on the web browser where you'll have the end colon. Exactly, exactly. So, net object IDs for nodes start with end colon and the node ID, so end colon 1. Then the time that you want to begin the maintenance period. If you want to set up unmanage for a future time, you can specify that. Maintenance window. In order to start it now, you can start it now. SWIS works in UTC time. So for those of you in London that'll be easy. For the rest of us, we need to remember our offsets. Yeah, but ultimately you work so much of the time in server time in UTC anyway. This way you're also not going to worry if you've got operations in multiple time zones. Maybe you have geo-distributed administrators. You're going to make sure that your "manage and unmanage," and other object times that you're setting through the SWIS interface are going to be consistent. Yes, consistent and safe. All right. Not necessarily safe. Tell the presidents in the other daily executive wing, not safe. Yes. All right. So we're going to start the "unmanage" now. We'll end it in two hours. All right. And the last argument is whether that's a relative or absolute time. Okay. I would recommend you always use absolute time. So we'll just pass false there to say this is not relative. All right. So there's my result. And if you were to go in it and write that to a single line query, node Z. Node Z. It's real programming. Status will be unmanaged. Yeah, okay. Now it's unmanaged, status 9. Okay. And then you can go back in and ‘re-manage’ it with another verb. No unmanage? [Laughs] That works, no? Does that work Cisco? No. We'll do a dedicated one. We'll do re-manage. Yeah, Orion does not run on iOS. That would be interesting. And re-manage… Doesn't need anything. Yeah, doesn't need anything because it's going to re-manage it now. And really, what that does under the hood, is it just sets ‘the unmanage until time’ to now. And then it recovers on the next polling interval. And then on the next polling interval, it will go back to normal. Let's see. So what are you going to do next? So now, if we look at the status, now you see it's gone to zero, which is unknown, meaning we have scheduled it for polling and we don't know what the status is now. Pretty soon, we're going to know that it's still up, because I didn't actually do anything to it. But because it's an array and it's easy to get to, if you wanted to programmatically manage this, you could just go ahead and poll—you could actually poll this interface every now and then to make sure that it comes back up. Right, exactly. You could wait and see what is the actual status now that this maintenance window has ended. Well, that's just great. And it was really, really easy to do there using PowerShell. I think the Snapin in particular makes it pretty easy. But we saw also behind the scenes how it works. We saw it native, using Python and JSON. And then—do you say JSON or JSON? I say JSON. What do you think it is? Two to one? I like to think of it as my friend Jason. Your friend Jason? Well at least nobody's saying Jif. Okay, so tell us again where you would find this. So, you can go to www.github.com/solarwinds/orionsdk to get documentation, source code, and download the latest version. That's right, and then if you want to actually talk to us about this, then check us out on THWACK. I think the easiest way to find that page— you can find it through the navigation but I just Google solarwindssdk, and it'll take you right to that page. And it will tell you what the current version is; give you opportunities. It will encourage you to check out betas, which I think are different on this, in that you don't talk directly to the program manager or product manager who are in charge. You simply go into GitHub and you can participate in a beta right there. Yes, it's on GitHub, so the betas are there for public download just like anything else. That's awesome. We did all of this on one machine. Except for the SWQL Studio. We didn't have to technically do this on Windows. We could have done all of this on a Linux box directly. Yes, all of the same operations are available. It's just the SWQL Studio tool is a Windows tool. That's great. Let's see. What else did we cover? You talked about how to suppress the certificate errors—pretty straightforward. You would definitely want to—in the example script before with the update where it failed because you had a permissions limitation— you would probably want to go ahead and surface errors in a way that was a little bit easier to consume. Yes. Good scripts should always report the errors, so they're not just silently doing nothing and letting you think that they succeeded. But I think the script that is in the package for the download actually does some error handling. I hope so. I hope so. You'll have to let us know and pull it down. Just send us a poll request. Yeah, [LAUGHS] a poll request. Let's see. What else? So that's available again. Tim, thank you so much for doing this programming class. I mean, I've sort of touched on this before. It's just really great to have you come and do this. We have had—you guys have been asking for an actual programming class for—I don't know—a year and a half now. And if there's something else that you really want to see that's really deep dive, we have access with the success of this show into all of the gurus on the dev team now, so we'll spread it around. I want to get Carlos on next. Carlos is a hoot. He is a hoot, a tall hoot. But yes, so let us know in the feedback or the chat and on the page what you want to see. And again, this episode is completely driven by you guys so thank you very much. Well, that was fun. Yeah, I mean and I'm even okay with being totally out-geeked on SWIS. I don't think you could ever be out-geeked. I don't know if that's a compliment or not. It mostly is. Seriously, I'm really impressed with what our customers are doing with the SolarWinds SDK. Not just queries and basic data syncs but really using Orion as an automation platform. And admins who pick our products tend to like hacking when there's downtime. So it's not that much of a surprise. Yeah, that's absolutely true. And remember that this programming show, like all of our other ones, comes directly from requests from viewers like you—viewers like you. I just love to say that— not just questions that we have during the show chat, which you should see over here to the right, and if you don't, well then you should definitely sign up for a show reminder, so you can be there live and bug us online. But also from viewers who just woke up in a sweat in the middle of the night and they went to www.lab.solarwinds.com and gave us their suggestions for a topic. That's a ridiculous image I would rather not imagine. Well, thanks again for coming on the show. Remind everyone again where they can reach you. You can find me on the THWACK SDK forum. My handle is TDanner. Just look for the owl. Well, it was really great to have a real actual SDK guru on. We should do this again some time. Absolutely. I've definitely got some ideas. But unless you have anything else, you want to take us out? Sure. I'm Tim Danner. And I'm Patrick Hubbard. And thanks for watching SolarWinds Lab.