Using API in perl scripts on virtual hostings

DmitPet

Member
Mar 6, 2012
6
0
51
cPanel Access Level
Website Owner
Hi guys,

First of all sorry for my english, but I really need your help. I have several virtual hostings with cpanel, and I want to manage them (addon,delete new domains, make msql bases etc.) from my perl scripts. Is it possible for me? For example, I want to addon new domains. I tried something like that:
use API::CPanel;
Code:
API::CPanel::Domain::add_addon_domain({
    auth_user   => 'username', 
    auth_passwd => 'qwerty', 
    host        => '11.22.33.44',
    dir         => '/newdomain', 
    newdomain   => 'newdomain', 
    pass        => 'xxx',    
    subdomain   => 'ftp',
});
but without any success.
When I make request using browser https://myhost:2083/xml-api/functionname answer is: "<result>0</result><reason>Token denied</reason>".
Can you please show me the simple perl code, for example for addon new domain?
Look forward to your answer ...
 

cPDan

cPanel Staff
Staff member
Mar 9, 2004
721
13
243
Hello!


… I tried something like that:
use API::CPanel;
Code:
API::CPanel::…
You might also want to try a module that cPanel develops and maintains:
cPanel::PublicAPI - search.cpan.org

When I make request using browser https://myhost:2083/xml-api/functionname answer is: "<result>0</result><reason>Token denied</reason>".
That error message means that your request needs to incorporate the “Security Token”. How that works and how to do it is outlined here:

Making your script work with security tokens in cPanel & WHM - cPanel Integration
 

DmitPet

Member
Mar 6, 2012
6
0
51
cPanel Access Level
Website Owner
Thanks for answer, but when I try "https://myhost:2083/cpsess1471282806/xml-api/functionname" I have 404 error :( Is it mean that I cann't use API as simple user?
And about cPanel::PublicAPI. As I understand it is modul for cpanel owners. I am only user :( Am I wrong?
 

cPDan

cPanel Staff
Staff member
Mar 9, 2004
721
13
243
Thanks for answer, but when I try "https://myhost:2083/cpsess1471282806/xml-api/functionname" I have 404 error :(
It is either a legit 404 or your session is not valid (or not if it does not exist). That is documented at the URL I sent previously.

And about cPanel::PublicAPI. As I understand it is modul for cpanel owners. I am only user :( Am I wrong?
Non-resellers are unable to do WHM specific requests like the web interface.
 

KostonConsulting

Well-Known Member
Verifed Vendor
Jun 17, 2010
255
1
68
San Francisco, CA
cPanel Access Level
Root Administrator
Thanks for answer, but when I try "https://myhost:2083/cpsess1471282806/xml-api/functionname" I have 404 error :( Is it mean that I cann't use API as simple user?
And about cPanel::PublicAPI. As I understand it is modul for cpanel owners. I am only user :( Am I wrong?

You'll need to use the following format for cPanel API2 calls:

Code:
https://myhost:2083/cpsess1471282806/xml-api/cpanel?cpanel_xmlapi_module=MODULE&cpanel_xmlapi_func=FUNC&cpanel_xmlapi_apiversion=2
So for example, to add an addon domain, use:

Code:
https://myhost.com:2083/cpsessxxx/xml-api/cpanel?cpanel_xmlapi_module=AddonDomain&cpanel_xmlapi_func=addaddondomain&cpanel_xmlapi_apiversion=2&newdomain=addondomain.com&subdomain=addondomain.domain.com&dir=/home/user/addondomain

Here are the docs for AddonDomain::addaddondomain:

ApiAddonDomain < ApiDocs/Api2 < TWiki



I don't know what API::Cpanel is but it is not an official cPanel method to connect to their API.


If you're running the perl script on the cPanel server, you can just load up Cpanel::AddonDomain with:

Code:
BEGIN{
  unshift(@INC, '/usr/local/cpanel');
}
use Cpanel::AddonDomain ();

If you're not on a cPanel server, I'd recommend using Net::SSLeay and HTTP::Request::Common to craft your API requests.
 

DmitPet

Member
Mar 6, 2012
6
0
51
cPanel Access Level
Website Owner
Ok, thanks a lot. I've done everything I need.
Hm, I'am to fast :) I have one more problem. Everything work fine, but one virtual host "Bluehost" make me crazy :(
Sub that I made:
Code:
sub AddonDomain { 
 my ($host,$username,$password,$domain)[email protected]_;
 if ($domain=~/http\:\/\//) {$domain=~s/http\:\/\///}
 my $subdomain=$domain;
 $subdomain=~s/\.[^\n]+//;
 my $cp = cPanel::PublicAPI->new( 
       'user' => $username,
       'pass' => $password,
       'host' => $host,
       'debug' => 1,
     );

 my @result = $cp->cpanel_api2_request('cpanel',
    { 
        'module' => 'AddonDomain',
        'func' => 'addaddondomain',
    },
    {
        'dir' => "public_html/$domain",
        'newdomain' => $domain,
        'subdomain' => $subdomain,
    },
  );
 my $d = Data::Dumper->new(\@result);
 my $out=$d->Dump;
 if ($out=~/was successfully parked/) {return 1;} else {print "$out\n";return 0;}
}
but when I try to addon domain to bluehost I have answer from debug:
Code:
debug: Using user param from object creation
debug: Using pass param from object creation
debug: loaded serializer: JSON::Syck
debug: api_request: ( cPanel::PublicAPI=HASH(0x1977c030), cpanel, /json-api/cpanel, GET, HASH(0x1977bfa0),  )
debug: failed to load encoder: cPanel/CPAN/URI/Escape.pm
debug: loaded encoder: URI/Escape.pm
debug: Found port for service cpanel to be 2083 (usessl=1)
debug: GET /json-api/cpanel?cpanel_jsonapi_module=AddonDomain&subdomain=DOMAIN&newdomain=DOMAIN&cpanel_jsonapi_apiversion=2&cpanel_jsonapi_func=addaddondomain&dir=public_html%2FDOMAIN HTTP/1.1
Host: box706.bluehost.com
Connection: Close
User-Agent: cPanel::PublicAPI (perl) 1.002
Authorization: Basic xxxxxxxxxxxxxxxxxxxxxxxxx


debug: HTTP LINE[HTTP/1.1 200 OK
]
debug: HEADER[content-type]=[text/plain; charset="utf-8"]
debug: HEADER[connection]=[Keep-Alive]
debug: HEADER[keep-alive]=[timeout=70, max=200]
debug: HEADER[date]=[Wed, 07 Mar 2012 20:33:46 GMT]
debug: HEADER[x-keep-alive-count]=[1]
debug: HEADER[content-length]=[0]
debug: HEADER[server]=[cpsrvd/11.30.5.6]
debug: READ TYPE=content-length
There was an issue with parsing the following response from cPanel or WHM:

There was an issue with parsing the following response from cPanel or WHM:
I guess that problem is "debug: GET /json-api/cpanel?cpanel_jsonapi_module=AddonDomain&subdomain= ......" must be xml-api not json-api. Could you please tell me what must I do?
 
Last edited by a moderator:

cPanelDavidN

Well-Known Member
Staff member
Dec 17, 2009
571
3
68
Houston, TX
cPanel Access Level
Root Administrator
DmitPet,

I dont' know why you're receiving that error, but you can find out the raw response like so:
Code:
my $cp = cPanel::PublicAPI->new(
       'user' => $username,
       'pass' => $password,
       'host' => $host,
       'debug' => 1,
     );

 my $result = $cp->cpanel_api2_request('cpanel',
    {
        'module' => 'AddonDomain',
        'func' => 'addaddondomain',
    },
    {
        'dir' => "public_html/$domain",
        'newdomain' => $domain,
        'subdomain' => $subdomain,
    },
    'xml'
  );

# for illustration puposes
print Dumper $result;
By adding one more input argument to cpanel_api2_request, being either 'json' or 'xml', it will make the query with that requested format and return the raw response.

Normally, the queries are made with the 'json' format and then parsed and returned as a hash ref...which, if you're getting a valid response, is great; It would let you avoid (or at least provide a alternative to) the Dumper and the string pattern matching...you can just look with the data->result container

Example output from the above code block:
Code:
$VAR1 = '<?xml version="1.0" ?>
  <cpanelresult>
    <apiversion>2</apiversion>
    <data>
      <reason>Deleted domain: tester.blah.net
Bind reloading on myserver using rndc zone: [blah.net]
The subdomain, tester.blah.net has been removed.</reason>
      <result>1</result>
    </data>
    <event>
      <result>1</result>
    </event>
    <func>addaddondomain</func>
    <module>AddonDomain</module>
    <postevent>
      <result>1</result>
    </postevent>
    <preevent>
      <result>1</result>
    </preevent>
  </cpanelresult>
';
Regards,
-DavidN
 

DmitPet

Member
Mar 6, 2012
6
0
51
cPanel Access Level
Website Owner
Thanks cPanelDavidN, but I got $VAR1 = undef; in that case :(
Strange, very strange. If I try using another function, for example "$cp->cpanel_api2_request('cpanel',{'module' => 'AddonDomain','func' => 'listaddondomains ',},);" everything work fine.
 

cPanelDavidN

Well-Known Member
Staff member
Dec 17, 2009
571
3
68
Houston, TX
cPanel Access Level
Root Administrator
DmitPet,

That is strange. What response do you get if you manually use a browser?

Manual XML/JSON API queries via browser
  1. Login to cPanel in a browser
  2. Go to the address bar of your browser
  3. Erase everything after the cPanel token (cpsessxxxxx)
  4. Manually add the XML/JSON API URL and query parameters
    Example:
    Code:
    https://myhost.com:2083/cpsessxxx/xml-api/cpanel?cpanel_xmlapi_module=AddonDomain&cpanel_xmlapi_func=addaddondomain&cpanel_xmlapi_apiversion=2&newdomain=addondomain.com&subdomain=addondomain.domain.com&dir=/home/user/addondomain
  5. Send request in browser ('go' button, return key, etc)

-DavidN
 

KostonConsulting

Well-Known Member
Verifed Vendor
Jun 17, 2010
255
1
68
San Francisco, CA
cPanel Access Level
Root Administrator
Just a few quick comments. I'd definitely recommend using a reference for the data that you get back from PublicAPI as shown in David's code. If you're expecting an array and the data comes back as a scalar (which it should) or hash, you'll have problems. With a reference, you can check the datatype with ref() and then act accordingly:

Code:
my $result = $cp->cpanel_api2_request('cpanel',

The second is that I've also had issues acting after AddonDomain::addaddondomain because the function may give a result => 0 when it actually fails. Rather than checking for specific text to see if it has completed, you can check the list of Addons with AddonDomain::listaddondomains to see if the domain you expected to be added was. This will be more future proof, especially if cPanel allows for these error messages to be translated at some point in the future.


Finally, I'd recommend parsing the output from PublicAPI with XML::Simple before acting on it. You should be looking for some key parts of the response each time as if for some reason the output includes error messages or debug information, your code may not function as expected in the future. XML::Simple::XMLin($result) should load up the response into a hashref for you.