Okay, I've confirmed nearly identical results on my test server as you.
The short answer is that cPAddons::mainpg() is one of the few calls that cannot be done via the xml-api.
The long answer is that there's a work around for this unique call: make a custom API call that CAN be call via xml-api. I discussed the matter with Matt, our key Integration developer. My hypothesis on resolving the issue completely jives with a solution that he's offered to others in the past.
The work around (brief):
1) Make a custom API module that works as a proxy and install any dependencies.
2) Extend the xml-api class with a custom query method.
3) Make our request with the custom query method.
The details!
The following are instructions from my conversation with Matt (and a simple test run using the WordPress cPAddon):
1)
A) Make a Perl module "/usr/local/cpanel/Cpanel/cPAddonsCustom.pm" with the following
Code:
package Cpanel::cPAddonsCustom;
BEGIN { unshift @INC, '/usr/local/cpanel', '/usr/local/cpanel/cpaddons', '/usr/local/cpanel/perl'; }
use Cpanel::cPAddons;
use IO::Scalar;
sub api2_mainpg {
my %OPTS = @_;
my $out;
tie *VAROUT, 'IO::Scalar', \$out;
select(VAROUT);
Cpanel::cPAddons::cPAddons_init();
Cpanel::cPAddons::cPAddons_mainpg(\%OPTS);
select(STDOUT);
return {'result' => $out};
}
sub api2 {
my $func = shift;
my %API = (
'mainpg' => {
'func' => 'api2_mainpg',
'engine' => 'hasharray'
}
);
return \%{ $API{$func} };
}
1;
This essentially allows us to pass the associative array (Perl hash) to the standard cPAddons::mainpg(). Most API1 calls take a simple array (ordered), however this one takes a hash (associative array). The xml-api binary can only take an ordered array for API1, plain and simple. This provides an intermediate step hand off data as this particular API1 is expecting it.
B) Install dependencies: Navigate into cPanel's Perl directory '/usr/local/cpanel/perl/IO' and get IO::Scalar and IO::WrapTie
'wget
http://cpansearch.perl.org/src/ERYQ/IO-stringy-2.109/lib/IO/Scalar.pm'
'wget
http://cpansearch.perl.org/src/DSKOLL/IO-stringy-2.110/lib/IO/WrapTie.pm'
2)
A) Extend the basic 'xmlapi' PHP class and add a custom method.
Code:
Class customXmlApi extends xmlapi{
/**
* This custom query is essentially an API2 query, only that we don't send 'cpanel_xmlapi_apiversion';
* Use the query for cPAddons::mainpg only:
* API1 normally takes ordered key parameters, API2 takes literal key parameters. Why
* cPAddons::mainpg is different, I don't know *shrug*
*
* @param string $user The username of the account to perform API1 actions on
* @param string $module The module of the API1 call to use
* @param string $function The function of the API1 call
* @param array $args An associative array containing the arguments for the API1 call
* @return mixed
*/
public function api1_custom_query($user, $module, $function, $args = array()) {
if (!isset($user) || !isset($module) || !isset($function) ) {
error_log("api1_custom_query requires that a username, module and function are passed to it");
return false;
}
if (!is_array($args)) {
error_log("api1_custom_query requires that an array is passed to it as the 4th parameter");
return false;
}
$module_type = 'cpanel_xmlapi_module';
$func_type = 'cpanel_xmlapi_func';
$api_type = 'cpanel_xmlapi_apiversion';
$cpuser = 'cpanel_xmlapi_user';
if ( $this->get_output() == 'json' ) {
$module_type = 'cpanel_jsonapi_module';
$func_type = 'cpanel_jsonapi_func';
$api_type = 'cpanel_jsonapi_apiversion';
$cpuser = 'cpanel_jsonapi_user';
}
$args[$cpuser] = $user;
$args[$module_type] = $module;
$args[$func_type] = $function;
// $args[$api_type] = '2'; //not passing for this custom call
return $this->xmlapi_query('cpanel', $args);
}
}
Note: the main difference here is the lack of the 'cpanel_xmlapi_apiversion' parameter. By not passing that, the xml-api binary does some default behavior that simulates an API2 call, but allows use to do API1 functionality (to put it simply). Technically, I *think* you can pass 'capnel_xmlapi_apiversion=2', in which case, you should be able to just use the standard 'api2_query()' method in the PHP client class. However for customization sake, it'd leave have the special method so that any change in cPanel code would directly reveal this issue...up to you; my testing only covers use with the custom method.
You can extend the PHP class however you need. From your post, it looks like you following my suggested blog post on extending the PHP class and postwwwacct scripts! You can simply add this method to your cpScriptsXmlApi class
3)
A) Now, in your postwwwacct file you'd make a call similar to this:
Code:
$xmlapi = new customXmlApi($ip);
$xmlapi->password_auth($root_user, $root_pass);
$xmlapi->set_port('2087');
$xmlapi->set_debug(1);
// Of course, the follow args are dependent on your Addon's needs //
$args = array(
'addon' => 'cPanel::Blogs::WordPress',
'action' => 'install',
'auser' => 'testadd',
'apass' => 'h-4}[email protected]/s~Wbc',
'apass2' => 'h-4}[email protected]/s~Wbc',
'email' => '[email protected]',
'installdir' => 'wordpress',
'table_prefix' => 'wp',
'existing_mysql' => '',
);
$xmlapi->api1_custom_query($account, 'cPAddonsCustom', 'mainpg', $args);
The query string should be something like this:
Code:
URL: https://10.0.0.1:2087/xml-api/cpanel
DATA: addon=cPanel%3A%3ABlogs%3A%3AWordPress&action=install&auser=testadd2&apass=h-4%7Dj%40%2Fs%7EWbc&apass2=h-4%7Dj%40%2Fs%7EWbc&email=dave%40cpanel.test&installdir=wordpress&table_prefix=wp&existing_mysql=&cpanel_xmlapi_user=blue&cpanel_xmlapi_module=cPAddonsCustom&cpanel_xmlapi_func=mainpg&cpanel_xmlapi_apiversion=2
My call would install the WordPress cPAddon (it's in Site Software for my cPanel test user).
The Results:
If you pass all the right variables for your particular cPAddon it should install!
A word of caution must be expressed here. This is a fairly customized solution, and therefore may be prone to breaking without notice. That being said, this type of customization is documented and not new; I don't foresee anything breaking, but it's something to keep in mind

Another thought I had: this solution has only been tested for expected functionality. No security or blackbox testing has been done: that's up to you

It should be sane, but i just needed to throw that out there.
Let me know how it works out.
-DavidN