The Community Forums

Interact with an entire community of cPanel & WHM users!
  1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

HELP! can't make postwwwacct work with cPAddon

Discussion in 'cPanel Developers' started by Britney, Jul 30, 2010.

  1. Britney

    Britney Member

    Joined:
    Jul 30, 2010
    Messages:
    5
    Likes Received:
    0
    Trophy Points:
    1
    Hi guys. I've been tearing my hair out with this.

    On my server, I've created a cPAddon for a CMS, and it works: I can create new instances of the CMS from a user's cPanel site software page.

    Now, I'm trying to get this cPAddon to install for every new user account created. I know I could install the CMS with my own code through the postwwwacct script, but I'd like to keep it a cPAddon so I can manage upgrades, list installation from WHM, etc...

    I thought that I could do this using a combination of postwwwacct, the PHP xmlapi wrapper script (since I know PHP) and cPanel API 1 (specifically, the cPAddons::mainpg) function. It seems like this SHOULD work but it's just not: all I ever get back from my xmlapi call is a listing of the installed cpAddons. I can never seem to submit the addon and action and extra parameters to the cpAddon in the proper way to get the cpAddon to install.

    Here is the sample code I'm using:

    PHP:
    $xmlapi = new cpScriptsXmlApi($argv,'127.0.0.1');
    $hash file_get_contents('/root/.accesshash');
    $xmlapi->set_debug(1);
    $xmlapi->set_user('root');
    $xmlapi->set_hash($hash);
    $xmlapi->set_port('2086');

    echo 
    "Installing the concrete5 cPAddon...";

    $cpargs = array('install''Concrete::CMS::concrete5');
    $r $xmlapi->api1_query($xmlapi->cliargs['user'],'cPAddons','mainpg',$cpargs);

    Can anyone help? I haven't been able to find much on this. I don't have to do this using a PHP script, either - I just really want a way to install my custom cPAddon whenever a new account is created.
     
  2. cPanelDavidN

    cPanelDavidN Integration Developer
    Staff Member

    Joined:
    Dec 17, 2009
    Messages:
    571
    Likes Received:
    1
    Trophy Points:
    18
    Location:
    Houston, TX
    cPanel Access Level:
    Root Administrator
    Hi Britney,

    Sounds like you got the basics in place. I don't see anything wrong with you code or with how you're using the PHP xml-api class or the API1 cPAddons::mainpg function call, according to the documentation.

    I haven't tried to install a cPAddon via xml-api before, but I'll give it a go in the next few days; see what I turn up.

    One suggestion I'd make is to install the API Tracer and use it to observe a manual install from the interface and an automated install via postwwwacct ala xml-api. Both methods should make the API1 cPAddons::mainpg call (eventually) and be present in the dump (log). CAVEAT EMPTOR: Do NOT install the Tracer on a production machine, as every API call and it's raw arguments will be logged!

    Last thought: there might be a bug with xml-api/cPAddons. If that happens to be the case, I should be able to pinpoint that during my testing in the next few days.

    Till then, keep fidgeting; give the Tracer a go and see what you can come up with.

    Regards,
    -DavidN
     
  3. Britney

    Britney Member

    Joined:
    Jul 30, 2010
    Messages:
    5
    Likes Received:
    0
    Trophy Points:
    1
    Thanks for responding over the weekend, David. I ran through this and I think it is proving useful. After installing the new logging files, I created an account and looked for the postwwwacct module. I found the relevant lines here:

    cpaddons:mainpg
    $apiv = 1
    $type = post
    -----
    $cfgref

    $VAR1 = {
    'param0' => 'install',
    'param1' => 'Concrete::CMS::concrete5'
    };
    -----

    That's what I was sending to the cPAddons::mainpg() function. This raised some flags with me because the cPAddon API1 documentation has a similar block of code, but instead of 'param0' and 'param1' it's sending named parameters like "addon" and "action" (along with anything else the cPAddon needs to work.)

    Next, I tried installing the cPAddon from cPanel's interface (which typically works just fine.) and I found this:


    cpaddons:mainpg
    $apiv = 1
    $type = pre
    -----
    $cfgref

    $VAR1 = {
    'addon' => 'Concrete::CMS::concrete5'
    };

    -----

    The named parameters (like in the documentation) are present. I wasn't able to get any further into installation with the Dumper.pm enabled, due to some strange issue I imagine is just part of the solution. Still, I think this is interesting. I tried modifying the PHP xmlapi library to pass named parameters instead of arg-1 and arg-2 but it wasn't doing anything: I imagine the change may have to be at a lower level?

    Thoughts? Thanks again for taking the time to get back to this over the weekend.
     
  4. cPanelDavidN

    cPanelDavidN Integration Developer
    Staff Member

    Joined:
    Dec 17, 2009
    Messages:
    571
    Likes Received:
    1
    Trophy Points:
    18
    Location:
    Houston, TX
    cPanel Access Level:
    Root Administrator
    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}j@/s~Wbc',
              'apass2' => 'h-4}j@/s~Wbc',
              'email' => 'dave@cpanel.test',
              '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
     
  5. Britney

    Britney Member

    Joined:
    Jul 30, 2010
    Messages:
    5
    Likes Received:
    0
    Trophy Points:
    1
    Thanks!

    This totally worked. Thanks. This has been a life saver.
     
Loading...

Share This Page