jgillman's Liquid Web Update Unofficial tips, tricks, and happenings from a Liquid Web sales engineer

21Aug/120

Utilizing the Stingray API

One of the benefits that a Managed Dedicated Load Balancing cluster provides is the ability to interact with it programmatically via a SOAP compliant API.

30Apr/120

Interactive Storm API Testing Script

What happens when I get bored? I code apparently.

Here's a piece of PHP code that runs purely command line. What it does is allow you to interactively work with the StormOnDemand API.

Although the output is just a straight print_r() of the returned data set, it does provide a nice easy way if you want to see the returns from various methods (or while feeding the same method different parameter/value pairs) in an expedient manner - all without having to write/replace code in a static script.

Enjoy!

 PHP | 
 
 copy code |
?

01
02
<?php
03
	/*
04
	 * Author: Jason Gillman Jr.
05
	 * Description: My attempt at writing a simple interactive CLI script for dumping raw data from Storm API returns.
06
	 * 				All you are going to get is print_r() of the returned array.
07
	 * 				Hope it's useful!
08
	 */
09
 
10
	require_once('StormAPI.class.php');
11
 
12
	// Initial information
13
	echo "\nAPI Username: "; $api_user = trim(fgets(STDIN));
14
	echo "Password: "; $api_pass = trim(fgets(STDIN));
15
	echo "Initial Method: "; $api_method = trim(fgets(STDIN));
16
 
17
	$storm = new StormAPI($api_user, $api_pass, $api_method);
18
 
19
	// Menu
20
	while(!isset($stop))
21
	{
22
		echo "\n\nPick your poison... \n";
23
		echo "1. Change method (will clear params) \n";
24
		echo "2. Add parameter \n";
25
		echo "3. Clear parameters \n";
26
		echo "4. Execute request and display \n";
27
		echo "5. Get me out of here \n";
28
		echo "Enter a number: "; fscanf(STDIN, "%d\n", $choice); // Get the choice
29
 
30
		switch($choice)
31
		{
32
			case 1:
33
				echo "\nEnter your new method: "; $api_method = trim(fgets(STDIN));
34
				$storm->new_method($api_method);
35
				break;
36
			case 2:
37
				echo "\nEnter the parameter: "; $parameter = trim(fgets(STDIN));
38
				echo "\nEnter the value: "; $value = trim(fgets(STDIN));
39
				$storm->add_param($parameter, $value);
40
				unset($parameter, $value);
41
				break;
42
			case 3:
43
				$storm->clear_params();
44
				break;
45
			case 4:
46
				print_r($storm->request());
47
				break;
48
			case 5:
49
				echo "\n\n";
50
				$stop = TRUE;
51
				break;
52
			default:
53
				echo "Really? How about you enter a valid value?";
54
				break;
55
		}
56
	}
57
?>
58

30Apr/120

StormOnDemand API Class update

I've yet again updated my StormOnDemand API PHP class.

For those who don't want to go to the PHP Classes site (which I highly recommend you do if you code OOP PHP - it's got a great collection of various PHP Classes), here is the source:

 PHP | 
 
 copy code |
?

01
02
<?php
03
	/*
04
	 * Author: Jason Gillman Jr.
05
	 * Description: This is my attempt at writing a PHP wrapper that will ease Storm API calls with PHP
06
	 * 				It will be designed to use the JSON format for talking with the API server.
07
	 * 				$api_method is as described in docs (Case doesn't matter)
08
	 * 				request() method returns an array generated from the API return
09
	 */
10
	class StormAPI
11
	{
12
		// Let's define attributes
13
		private $api_user, $api_pass, $base_url, $api_format, $api_full_uri, $api_request;
14
		private $api_request_body, $api_method, $api_params, $api_return; 
15
 
16
		function __construct($api_user, $api_pass, $api_method)
17
		{	
18
			$this->api_user = $api_user;
19
			$this->api_pass = $api_pass;
20
			$this->api_method = $api_method;
21
			$this->base_url = 'https://api.stormondemand.com/';
22
			$this->api_format = 'json';
23
 
24
			$this->api_full_uri = $this->base_url . $this->api_method . "." .$this->api_format;
25
			$this->api_request = curl_init($this->api_full_uri); // Instantiate
26
			curl_setopt($this->api_request, CURLOPT_RETURNTRANSFER, TRUE); // Don't dump directly to output
27
			curl_setopt($this->api_request, CURLOPT_SSL_VERIFYPEER, TRUE); // It does look like verification works now.
28
			curl_setopt($this->api_request, CURLOPT_USERPWD, "$this->api_user:$this->api_pass"); // Pass the creds
29
		}
30
 
31
		function add_param($parameter, $value)
32
		{
33
			$this->api_request_body['params'][$parameter] = $value;
34
		}
35
 
36
		function clear_params()
37
		{
38
			unset($this->api_request_body);
39
			curl_setopt($this->api_request, CURLOPT_HTTPGET, TRUE); //If the request was previously run with params, this cleans those out. Otherwise they go back with the request
40
		}
41
 
42
		function new_method($api_method, $clearparams = TRUE) // Clears out parameters by default, since they may not apply now
43
		{
44
			if($clearparams = TRUE)
45
			{
46
				unset($this->api_request_body);
47
				curl_setopt($this->api_request, CURLOPT_HTTPGET, TRUE); //If the request was previously run with params, this cleans those out. Otherwise they go back with the request
48
			}
49
 
50
			$this->api_method = $api_method; // New method, coming right up!
51
			$this->api_full_uri = $this->base_url . $this->api_method . "." .$this->api_format; // New URI since method change
52
			curl_setopt($this->api_request, CURLOPT_URL, $this->api_full_uri);
53
 
54
		}
55
 
56
		function request()
57
		{
58
			if(is_array($this->api_request_body)) // We have params
59
			{
60
				curl_setopt($this->api_request, CURLOPT_POST, TRUE); //POST method since we'll be feeding params
61
				curl_setopt($this->api_request, CURLOPT_HTTPHEADER, Array('Content-type: application/json')); // Since we'll be using JSON
62
				curl_setopt($this->api_request, CURLOPT_POSTFIELDS, json_encode($this->api_request_body)); // Insert the parameters
63
			}
64
 
65
			// Now send the request and get the return on investment
66
			try
67
			{
68
				return json_decode(curl_exec($this->api_request), TRUE); // Pull the trigger and get nice pretty arrays of returned data
69
			}
70
			catch (HTTP_Request2_Exception $e)
71
			{
72
				echo 'Error: ' . $e->getMessage();
73
			}
74
		}
75
	}
76
?>
77

Essentially, I added two new methods: clear_params() and new_method(). Both of these do what you might think - clearing existing set parameters and choosing a different API method.

Also, if you're so inclined, I believe you should be able to track updates to the PHP Classes project that I have with this RSS link. I've also added it to the right side of the page.

3Apr/120

Updated Storm On Demand API PHP Class

I just wanted to put out that I've updated my API class to use cURL instead of HTTP_REQUEST2 in my initial post.

Although it still utilizes YAML, this is my first move at getting away from third party packages.

Enjoy!

 PHP | 
 
 copy code |
?

01
02
<?php
03
	/*
04
	 * Author: Jason Gillman Jr.
05
	 * Description: This is my attempt at writing a PHP wrapper that will ease Storm API calls with PHP
06
	 * 				It will be designed to use the YAML format for talking with the API server.
07
	 * 				$api_method is as described in docs (Case matters)
08
	 * 				request() method returns an array generated from the API return
09
	 */
10
	class StormAPI
11
	{
12
		// Let's define attributes
13
		private $api_user, $api_pass, $base_url, $api_format, $api_full_uri, $api_request;
14
		private $api_request_body, $api_method, $api_params, $api_return; 
15
 
16
		function __construct($api_user, $api_pass, $api_method)
17
		{	
18
			$this->api_user = $api_user;
19
			$this->api_pass = $api_pass;
20
			$this->api_method = $api_method;
21
			$this->base_url = 'https://api.stormondemand.com/';
22
			$this->api_format = 'yaml';
23
 
24
			$this->api_full_uri = $this->base_url . $this->api_method . "." .$this->api_format;
25
			$this->api_request = curl_init($this->api_full_uri); // Instantiate
26
			curl_setopt($this->api_request, CURLOPT_RETURNTRANSFER, TRUE); // Don't dump directly to output
27
			curl_setopt($this->api_request, CURLOPT_SSL_VERIFYPEER, FALSE); // Apparently verification doesn't work with the API?
28
			curl_setopt($this->api_request, CURLOPT_USERPWD, "$this->api_user:$this->api_pass"); // Pass the creds
29
		}
30
 
31
		function add_param($parameter, $value)
32
		{
33
			$this->api_request_body['params'][$parameter] = $value;
34
		}
35
 
36
		function request()
37
		{
38
			if(isset($this->api_request_body)) // We have params
39
			{
40
				curl_setopt($this->api_request, CURLOPT_POST, TRUE); //POST method since we'll be feeding params
41
				curl_setopt($this->api_request, CURLOPT_HTTPHEADER, Array('Content-type: application/yaml')); // Since we'll be using YAML
42
				curl_setopt($this->api_request, CURLOPT_POSTFIELDS, yaml_emit($this->api_request_body)); // Insert the parameters
43
			}
44
 
45
			// Now send the request and get the return on investment
46
			try
47
			{
48
				return yaml_parse(curl_exec($this->api_request)); // Pull the trigger and get nice pretty arrays of returned data
49
			}
50
			catch (HTTP_Request2_Exception $e)
51
			{
52
				echo 'Error: ' . $e->getMessage();
53
			}
54
		}
55
	}
56
?>
57

Update on 4Apr12 @ 1300EDT
I have updated the class to utilize JSON instead of YAML. Code change was actually pretty straight forward. It is shown below:

 PHP | 
 
 copy code |
?

01
02
<?php
03
	/*
04
	 * Author: Jason Gillman Jr.
05
	 * Description: This is my attempt at writing a PHP wrapper that will ease Storm API calls with PHP
06
	 * 				It will be designed to use the YAML format for talking with the API server.
07
	 * 				$api_method is as described in docs (Case matters)
08
	 * 				request() method returns an array generated from the API return
09
	 */
10
	class StormAPI
11
	{
12
		// Let's define attributes
13
		private $api_user, $api_pass, $base_url, $api_format, $api_full_uri, $api_request;
14
		private $api_request_body, $api_method, $api_params, $api_return; 
15
 
16
		function __construct($api_user, $api_pass, $api_method)
17
		{	
18
			$this->api_user = $api_user;
19
			$this->api_pass = $api_pass;
20
			$this->api_method = $api_method;
21
			$this->base_url = 'https://api.stormondemand.com/';
22
			$this->api_format = 'json';
23
 
24
			$this->api_full_uri = $this->base_url . $this->api_method . "." .$this->api_format;
25
			$this->api_request = curl_init($this->api_full_uri); // Instantiate
26
			curl_setopt($this->api_request, CURLOPT_RETURNTRANSFER, TRUE); // Don't dump directly to output
27
			curl_setopt($this->api_request, CURLOPT_SSL_VERIFYPEER, FALSE); // Apparently verification doesn't work with the API?
28
			curl_setopt($this->api_request, CURLOPT_USERPWD, "$this->api_user:$this->api_pass"); // Pass the creds
29
		}
30
 
31
		function add_param($parameter, $value)
32
		{
33
			$this->api_request_body['params'][$parameter] = $value;
34
		}
35
 
36
		function request()
37
		{
38
			if(isset($this->api_request_body)) // We have params
39
			{
40
				curl_setopt($this->api_request, CURLOPT_POST, TRUE); //POST method since we'll be feeding params
41
				curl_setopt($this->api_request, CURLOPT_HTTPHEADER, Array('Content-type: application/json')); // Since we'll be using JSON
42
				curl_setopt($this->api_request, CURLOPT_POSTFIELDS, json_encode($this->api_request_body)); // Insert the parameters
43
			}
44
 
45
			// Now send the request and get the return on investment
46
			try
47
			{
48
				return json_decode(curl_exec($this->api_request), TRUE); // Pull the trigger and get nice pretty arrays of returned data
49
			}
50
			catch (HTTP_Request2_Exception $e)
51
			{
52
				echo 'Error: ' . $e->getMessage();
53
			}
54
		}
55
	}
56
?>
57

10Mar/120

Creating a Gluster Back End on Storm Servers

As described in a previous article, Gluster is a good way to provide centralized storage for a load balanced cluster on Storm.

More below the fold

6Feb/120

Load Balancing with Storm/SmartServers

One of the nice things about our cloud platform (Storm On Demand / Smart Servers) is the ability to easily provision load balancing between nodes. This can be used for a multitude of purposes, from increasing overall performance, to mitigating downtime due to server problems.

However, if you're considering going with a load balanced setup, there are a few key issues to be cognizant of.

More below the fold...

20Jul/110

Traditional Dedicated v. Cloud Based Dedicated

One question that I get asked a bit is why someone would go with a Storm BareMetal or Liquid Web SmartServer as compared to a traditional dedicated server. The answer that I give to that question is that it really depends.

Traditional dedicated and cloud based dedicated servers each have their advantages over the other type. That is why it is important to determine what your architectural requirements are when deciding.

Advantages of Cloud Dedicated Servers (SmartServers/Storm BareMetal) over Traditional Dedicated

Quick Deployment and Granular Billing
One of the most apparent advantages with a cloud based server is the fact that they are pre-racked, and can thus be provisioned within minutes. This, combined with the fact that billing is done daily (SmartServers) or Hourly (Storm BareMetal), make cloud based servers ideal for developers who may need to kick instances quickly and for a relatively short amount of time for a project.

Dynamic Resizing
Another advantage of a cloud based server is the ability to dynamically resize an instance. This is certainly beneficial for long term upgrades, as the migrations are completely automatic and transparent to the user. However, users who have cyclic periods of increased usage can really benefit from this feature (again, combined with daily/hourly billing as well).

For example, I was working with a customer who currently has an older traditional dedicated server. On certain nights (which are known), his traffic literally doubles, which has caused problems for that server. In this case, we decided that a SmartServer was an excellent choice - prior to the start of the busy time, he upsizes the server to handle the significantly increased load, and then when the busy time is done, he just resizes down, only paying for the time that he used. It was truly a win/win, as the customer is able to handle the increased load as needed, while saving money.

Automated Advanced Networking
The advanced networking features of our cloud based servers are another significant advantage over traditional dedicated servers. Through the interface, or the Storm API, you can setup load balancing, firewall rules, and a private network. This makes it easy to transition from say a single server which is both hosting static web content as well as the database, to a frontend-backend setup where the two servers are linked via private networking, as no physical cabling needs to be run, nor switches setup.

Creating Server Images
With Liquid Web's cloud based servers, you have the ability to create server images, which you can subsequently use to kick additional instances.

For example, say that you were anticipating building site with a load balanced architecture. One thing that you might do is create a base configuration that all nodes would have, and then create an image. That way, additional node creation is simply an issue of using that image when they are created.

Advantages of Traditional Servers over Cloud Servers

Hardware Customization
One of the key advantages that a traditional server has over a cloud based one is that you are able to customize various hardware components much more. For example, it's easy to add additional hard drive space or RAM with a traditional server. However, with a cloud based server, you have to upgrade the whole instance. Much more granularity is allowed with a traditional dedicated.

Operating System Selection
Another advantage that traditional dedicated servers have over cloud servers is that, for now, selection is limited to what is available. With a traditional dedicated, any operating system can be installed. Be on the lookout over the next couple of months though for Windows on Storm and Liquid Web SmartServers. Update:Windows on Storm is now available, and should be available soon for SmartServers

Partitioning
One thing that traditional servers can do that our cloud servers can not do is have a custom partitioning scheme. Although the partitioning scheme that comes with Storm and SmartServers is adequate for many, some may require a more customized scheme.

Final Thoughts

As can be seen, choosing between a cloud based server or a traditional is based largely on what your requirements are. If you're looking at just kicking a Debian box to do some code testing on, our cloud offerings would be ideal given the speed of deployment and granular billing. However, if you need things like custom partitioning schemes or operating systems not currently offered with our cloud products, a traditional server would be the right choice.

Of course, Liquid Web sales engineers, such as myself, are around 24x7 to answer any further questions to may have, or to advise you on what the right solution would be for your hosting needs. Don't hesitate to contact us!

18Jul/114

Utilizing the Storm API with PHP

One of most powerful features of StormOnDemand is the API.

With the API, you can do anything with your Storm account programmaticaly that you can in the regular web based interface. It's a powerful tool that would allow for things such as automatic instance resizing based on load, emailed load reports, etc. However, I think that the API isn't utilized as much because people might not know how to work with it. What follows is a primer for utilizing PHP to interface with the API (I know PHP much, much, much more than Perl).

Although the documentation might seem a little terse in regards to making calls to the API, it essentially boils down to HTTP POST methods utilizing one of the supported encodings, which are currently JSON, YAML, and XML. Making these calls procedurally can quickly turn your code into something that resembles Italian cuisine, which is why I cobbled together a class to take a more object oriented approach.

The class utilizes the YAML encoding method, as well as the HTTP_REQUEST2 PEAR package. Again, this is just something that I put together, and there are probably much better ways to approach this. But it works. Here is the source:

 PHP | 
 
 copy code |
?

01
<?php
02
	/*
03
	 * Author: Jason Gillman Jr.
04
	 * Description: This is my attempt at writing a PHP wrapper that will ease Storm API calls with PHP
05
	 * 				It will be designed to use the YAML format for talking with the API server.
06
	 * 				$api_method is as described in docs (Case matters)
07
	 * 				request() method returns an array generated from the API return
08
	 */
09
	class StormAPI
10
	{
11
		// Let's define attributes
12
		private $api_user, $api_pass, $base_url, $api_format, $api_full_uri, $api_request;
13
		private $api_request_body, $api_method, $api_params, $api_return; 
14
 
15
		function __construct($api_user, $api_pass, $api_method)
16
		{
17
			// Requires PEAR Package HTTP_Request2
18
			require_once('HTTP/Request2.php');
19
 
20
			$this->api_user = $api_user;
21
			$this->api_pass = $api_pass;
22
			$this->api_method = $api_method;
23
			$this->base_url = 'https://api.stormondemand.com/';
24
			$this->api_format = 'yaml';
25
 
26
			$this->api_full_uri = $this->base_url . $this->api_method . "." .$this->api_format;
27
		}
28
 
29
		function add_param($parameter, $value)
30
		{
31
			$this->api_request_body['params'][$parameter] = $value;
32
		}
33
 
34
		function request()
35
		{
36
			// HTTP Request goodness
37
			if(isset($this->api_request_body)) // We have params
38
			{
39
				$api_request = new HTTP_Request2($this->api_full_uri, HTTP_Request2::METHOD_POST); // Instantiate with POST method since we'll be feeding params
40
				$api_request->setHeader('Content-type: application/yaml'); // Specify what you're feeding it
41
				$api_request->setBody(yaml_emit($this->api_request_body));
42
			}
43
			else // No params
44
			{
45
				$api_request = new HTTP_Request2($this->api_full_uri, HTTP_Request2::METHOD_GET); // Instantiate with GET method since no params
46
			}
47
			$api_request->setAuth($this->api_user, $this->api_pass, HTTP_Request2::AUTH_BASIC); // Auth stuff
48
			$api_request->setConfig('ssl_verify_peer', FALSE); // This is needed, otherwise HTTP_Request errors last I checked
49
 
50
			// Now send the request and get the return on investment
51
			try
52
			{
53
				$api_return = $api_request->send();
54
				return yaml_parse($api_return->getBody()); // We now have a nice array of all the returned data
55
			}
56
			catch (HTTP_Request2_Exception $e)
57
			{
58
				echo 'Error: ' . $e->getMessage();
59
			}
60
		}
61
	}
62
?>

One thing that I should mention before continuing is that you need to create an API user. This is done in the interface through Account >> Users

Essentially, you instantiate the class by passing the API username, password, and the API method you are going to be using. The API method comes in the format "First/Second/third" or "First/second" depending on the method you want to use. You don't include the leading slash, and the methods as far as I know are case sensitive.

Once you instantiate the object, you would use the add_param() method in the format of (parameter, value).

Once you add all the parameters (if any), just run the request() method, which will return an array containing the data.

So let's look at a real simple example scenario where you wanted to get the Five Minute load average for a particular server with a uniq_id of '123ABC':

 PHP | 
 
 copy code |
?

01
<?php
02
 
03
require_once(StormAPI.class.php); // Assuming we put the class in this file
04
 
05
$api_user = 'user';
06
$api_pass = 'pass';
07
$api_method = 'Monitoring/Load/stats';
08
 
09
$get_load = new StormAPI($api_user, $api_pass, $api_method);
10
$get_load->add_param('uniq_id', '123ABC'); // Where we pass our uniq_id
11
$results = $get_load->request(); // Initial array grab
12
 
13
// Now to get the five minute load
14
echo "Five Minute Load Average is: " . $results['loadavg']['five'];
15
 
16
//Done
17
?>

That's it. Relatively simple if you have a nice class to use. In order to get the uniq_id for a server, you would use the Server/list method.

Of course you can do this either via a web based application, or a CLI ran PHP script, for example, that might belong in a cron job (for checking load every so often for example).

Hopefully this gives a good starting point for working with the API. If you have questions, just leave a comment!

Updated as of April 2012: The class has been updated to utilize cURL and JSON

   
FireStats icon Powered by FireStats
Optimization WordPress Plugins & Solutions by W3 EDGE