File Coverage

lib/API/CPanel.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1             package API::CPanel;
2              
3 1     1   1814 use strict;
  1         3  
  1         51  
4 1     1   6 use warnings;
  1         3  
  1         57  
5 1     1   18 use lib qw(../..);
  1         2  
  1         9  
6              
7 1     1   1210 use Exporter::Lite;
  1         793  
  1         6  
8 1     1   1145 use LWP::UserAgent;
  1         112467  
  1         52  
9             #use XML::LibXML;
10 1     1   690 use XML::Simple;
  0            
  0            
11             use Data::Dumper;
12             use MIME::Base64;
13             # Main packages
14             use API::CPanel::Ip;
15             use API::CPanel::User;
16             use API::CPanel::Misc;
17             use API::CPanel::Package;
18             use API::CPanel::Domain;
19             use API::CPanel::Mysql;
20              
21              
22             our @EXPORT = qw/get_auth_hash refs is_success query_abstract is_ok get_error/;
23             our @EXPORT_OK = qw//;
24             our $VERSION = 0.09;
25             our $DEBUG = '';
26             our $FAKE_ANSWER = '';
27              
28             =head1 NAME
29              
30             API::CPanel - interface to the CPanel Hosting Panel API ( http://cpanel.net )
31              
32             =head1 SYNOPSIS
33              
34             use API::CPanel;
35            
36             my $connection_params = {
37             auth_user => 'username',
38             auth_passwd => 'qwerty',
39             host => '11.22.33.44',
40             };
41              
42             ### Get all panel IP
43             my $ip_list = API::CPanel::ip::list( $connection_params );
44              
45             unless ($ip_list && ref $ip_list eq 'ARRAY' && scalar @$ip_list) {
46             die 'Cannot get ip list from CPanel';
47             }
48              
49             my $ip = $ip_list->[0];
50             my $dname = 'perlaround.ru';
51             my $user_name = 'user1';
52              
53             my $client_creation_result = API::CPanel::user::create( {
54             %{ $connection_params },
55             username => $user_name,
56             password => 'user_password',
57             domain => $dname,
58             });
59              
60             # Switch off account:
61             my $suspend_result = API::CPanel::user::disable( {
62             %{ $connection_params },
63             user => $user_name,
64             } );
65              
66             unless ( $suspend_result ) {
67             die "Cannot suspend account";
68             }
69              
70              
71              
72             # Switch on account
73             my $resume_result = API::CPanel::user::enable( {
74             %{ $connection_params },
75             user => $user_name,
76             } );
77              
78             unless ( $resume_result ) {
79             die "Cannot resumeaccount";
80             }
81              
82              
83              
84             # Delete account
85             my $delete_result = API::CPanel::user::delete( {
86             %{ $connection_params },
87             user => $user_name,
88             } );
89              
90             unless ( $delete_result ) {
91             die "Cannot delete account";
92             }
93              
94              
95             =cut
96              
97             # Last raw answer from server
98             our $last_answer = '';
99              
100             # Public!
101             sub is_ok {
102             my $answer = shift;
103              
104             return 1 if $answer && ( ref $answer eq 'HASH' || ref $answer eq 'ARRAY' );
105             }
106              
107              
108             sub get_error {
109             my $answer = shift;
110              
111             return '' if is_success( $answer ); # ok == no error
112              
113             return Dumper( $answer->{statusmsg } );
114             }
115              
116             # Get data from @_
117             sub get_params {
118             my @params = @_;
119              
120             if (scalar @params == 1 && ref $params[0] eq 'HASH' ) {
121             return { %{ $params[0] } };
122             } else {
123             return { @params };
124             }
125             }
126              
127             # Make query string
128             # STATIC(HASHREF: params)
129             sub mk_query_string {
130             my $params = shift;
131              
132             return '' unless $params &&
133             ref $params eq 'HASH' && %$params ;
134              
135             my $result = join '&', map { "$_=$params->{$_}" } sort keys %$params;
136             warn $result if $DEBUG;
137              
138             return $result;
139             }
140              
141             # Kill slashes at start / end string
142             # STATIC(STRING:input_string)
143             sub kill_start_end_slashes {
144             my $str = shift;
145              
146             for ($str) {
147             s/^\/+//sgi;
148             s/\/+$//sgi;
149             }
150            
151             return $str;
152             }
153              
154             # Make full query string (with host, path and protocol)
155             # STATIC(HASHREF: params)
156             # params:
157             # host*
158             # path
159             # allow_http
160             # param1
161             # param2
162             # ...
163             sub mk_full_query_string {
164             my $params = shift;
165              
166             return '' unless
167             $params &&
168             ref $params eq 'HASH' &&
169             %$params &&
170             $params->{host} &&
171             $params->{func};
172              
173             my $host = delete $params->{host};
174             my $path = delete $params->{path} || '';
175             my $allow_http = delete $params->{allow_http} || '';
176             my $func = delete $params->{func};
177              
178             unless ($path) {
179             $path = 'xml-api';
180             }
181              
182             $path = kill_start_end_slashes( $path );
183             $host = kill_start_end_slashes( $host );
184             $func = kill_start_end_slashes( $func );
185              
186             my $query_path = ( $allow_http ? 'http' : 'https' ) . "://$host:2087/$path/$func";
187              
188             return %$params ? $query_path . '?' . mk_query_string( $params ) : $query_path;
189             }
190              
191              
192             # Make request to server and get answer
193             # STATIC (STRING: query_string)
194             sub mk_query_to_server {
195             my $auth_hash = shift;
196             my $query_string = shift;
197              
198             return '' unless ( $query_string && $auth_hash );
199             warn "Auth hash: $auth_hash\nQuery string: $query_string\n" if $DEBUG;
200              
201             my $ua = LWP::UserAgent->new;
202             my $request = HTTP::Request->new( GET => $query_string );
203             $request->header( Authorization => $auth_hash );
204             my $response = $ua->request( $request );
205              
206             my $content = $response->content;
207             if ($response->header('content-type') eq 'text/xml') {
208             warn $content if $DEBUG;
209             return $content;
210             } else {
211             return '';
212             }
213             }
214              
215             # Parse answer
216             # STATIC(HASHREF: params)
217             # params:
218             # STRING: answer
219             # HASHREF: xml_parser_params)
220             sub parse_answer {
221             my %params = @_;
222              
223             my $answer_string =
224             $params{answer};
225             my $parser_params =
226             $params{parser_params} || { };
227              
228             return '' unless $answer_string;
229              
230             my $deparsed = XMLin( $answer_string, %$parser_params );
231             warn Dumper $deparsed if $DEBUG;
232            
233             return $deparsed ? $deparsed : '';
234             }
235              
236             # Get + deparse
237             # STATIC(STRING: query_string)
238             sub process_query {
239             my %params = @_;
240              
241             my $auth_hash = $params{auth_hash};
242             my $query_string = $params{query_string};
243             my $xml_parser_params = $params{parser_params} || '';
244             my $fake_answer = $API::CPanel::FAKE_ANSWER || '';
245              
246             return '' unless $query_string;
247              
248             my $answer = $fake_answer ? $fake_answer : mk_query_to_server( $auth_hash, $query_string );
249             warn $answer if $answer && $DEBUG;
250              
251             return $answer ?
252             parse_answer(
253             answer => $answer,
254             parser_params => $xml_parser_params
255             ) : '';
256             }
257              
258             # Filter hash
259             # STATIC(HASHREF: hash, ARRREF: allowed_keys)
260             # RETURN: hashref only with allowed keys
261             sub filter_hash {
262             my ($hash, $allowed_keys) = @_;
263              
264             return unless ref $hash eq 'HASH' &&
265             ref $allowed_keys eq 'ARRAY';
266            
267             my $new_hash = { };
268              
269             foreach my $allowed_key (@$allowed_keys) {
270             if (exists $hash->{$allowed_key}) {
271             $new_hash->{$allowed_key} = $hash->{$allowed_key};
272             }
273             elsif (exists $hash->{lc $allowed_key}) {
274             $new_hash->{$allowed_key} = $hash->{lc $allowed_key};
275             };
276             }
277              
278             return $new_hash;
279             }
280              
281             # Get access key, time to live -- 30 minutes
282             # STATIC(HASHREF: params_hash)
283             # params_hash:
284             # - all elements from mk_full_query_string +
285             # - auth_user*
286             # - auth_passwd*
287             sub get_auth_hash {
288             my %params_raw = @_;
289              
290             warn 'get_auth_hash params: ' . Dumper(\%params_raw) if $DEBUG;
291              
292             my $params = filter_hash(
293             \%params_raw,
294             [ 'auth_user', 'auth_passwd' ]
295             );
296              
297             # Check this sub params
298             unless ($params->{auth_user} && $params->{auth_passwd}) {
299             return '';
300             }
301              
302             return "Basic " . MIME::Base64::encode( $params->{auth_user} . ":" . $params->{auth_passwd} );
303             }
304              
305             # Wrapper for "ref" on undef value, without warnings :)
306             # Possible very stupid sub :)
307             # STATIC(REF: our_ref)
308             sub refs {
309             my $ref = shift;
310              
311             return '' unless $ref;
312              
313             return ref $ref;
314             }
315              
316             # INTERNAL!!! Check server answer result
317             # STATIC(data_block)
318             sub is_success {
319             my $data_block = shift;
320             my $want_hash = shift;
321              
322             if ( $data_block &&
323             ref $data_block eq 'HASH' &&
324             (( $data_block->{status} &&
325             $data_block->{status} eq '1' ) ||
326             ( $data_block->{result} &&
327             $data_block->{result} eq '1' ))
328             ) {
329             return 1;
330             } else {
331             return $want_hash ? {} : '';
332             }
333             }
334              
335             # all params derived from get_auth_hash
336             sub query_abstract {
337             my %params = @_;
338              
339             my $params_raw = $params{params};
340             my $func_name = $params{func};
341             my $container = $params{container};
342              
343             my $fields = $params{allowed_fields} || '';
344              
345             my $allowed_fields;
346             warn 'query_abstract ' . Dumper( \%params ) if $DEBUG;
347              
348             return '' unless $params_raw && $func_name;
349              
350             $fields = "host path allow_http auth_user auth_passwd container $fields";
351             @$allowed_fields = split(' ', $fields);
352              
353             my $xml_parser_params = $params{parser_params};
354              
355             my $auth_hash = get_auth_hash( %$params_raw );
356             warn "Auth_hash: $auth_hash\n" if $DEBUG;
357              
358             if ( $auth_hash ) {
359             my $params = filter_hash( $params_raw, $allowed_fields );
360              
361             my $query_string = mk_full_query_string( {
362             func => $func_name,
363             %$params,
364             } );
365              
366             warn Dumper $query_string if $DEBUG;
367              
368             my $server_answer = process_query(
369             auth_hash => $auth_hash,
370             query_string => $query_string,
371             parser_params => $xml_parser_params,
372             );
373             warn Dumper $server_answer if $DEBUG;
374              
375             if ( $server_answer &&
376             $container &&
377             is_ok( $server_answer->{$container} )
378             ) {
379             $API::CPanel::last_answer = $server_answer->{$container};
380             return $server_answer->{$container};
381             }
382             elsif ( $server_answer &&
383             is_ok( $server_answer ) &&
384             ! $container ) {
385             $API::CPanel::last_answer = $server_answer;
386             return $server_answer;
387             }
388             else {
389             $API::CPanel::last_answer = $server_answer;
390             warn "wrong server answer" if $DEBUG;
391             return '';
392             };
393             } else {
394             $API::CPanel::last_answer = 'auth_hash not found';
395             warn "auth_hash not found" if $DEBUG;
396             return '';
397             }
398             }
399              
400             # Abstract sub for action methods
401             sub action_abstract {
402             my %params = @_;
403              
404             my $result = query_abstract(
405             params => $params{params},
406             func => $params{func},
407             container => $params{container},
408             allowed_fields => $params{allowed_fields},
409             );
410              
411             return $params{want_hash} && is_success( $result, $params{want_hash} ) ? $result : is_success( $result );
412             }
413              
414             # Abstract sub for fetch arrays
415             sub fetch_array_abstract {
416             my %params = @_;
417              
418             my $result_field = $params{result_field} || '';
419             my $result_list = [ ];
420             my $result = query_abstract(
421             params => $params{params},
422             func => $params{func},
423             container => $params{container},
424             allowed_fields => $params{allowed_fields},
425             );
426             return $result_list unless $result;
427             $result = [ $result ] if ref $result ne 'ARRAY';
428              
429             foreach my $elem ( @{ $result } ) {
430             push @$result_list, $result_field ? $elem->{$result_field} : $elem;
431             };
432              
433             return $result_list;
434             }
435              
436             # Abstract sub for fetch hash
437             sub fetch_hash_abstract {
438             my %params = @_;
439              
440             my $result = query_abstract(
441             params => $params{params},
442             func => $params{func},
443             container => $params{container},
444             allowed_fields => $params{allowed_fields},
445             );
446              
447             my $result_hash = {};
448             return $result_hash unless $params{key_field};
449             my $key_field = $params{key_field};
450             foreach my $each ( @$result ) {
451             $result_hash->{$each->{$key_field}} = $each;
452             }
453              
454             return $result_hash;
455             }
456              
457             1;