| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package WebService::Linode; | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | require 5.006000; | 
| 4 |  |  |  |  |  |  |  | 
| 5 | 1 |  |  | 1 |  | 1017 | use warnings; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 35 |  | 
| 6 | 1 |  |  | 1 |  | 5 | use strict; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 30 |  | 
| 7 |  |  |  |  |  |  |  | 
| 8 | 1 |  |  | 1 |  | 6 | use Carp; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 88 |  | 
| 9 | 1 |  |  | 1 |  | 5 | use List::Util qw(first); | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 88 |  | 
| 10 | 1 |  |  | 1 |  | 5 | use WebService::Linode::Base; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 484 |  | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | our $VERSION = '0.28'; | 
| 13 |  |  |  |  |  |  | our @ISA     = ("WebService::Linode::Base"); | 
| 14 |  |  |  |  |  |  | our $AUTOLOAD; | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | # beginvalidation | 
| 17 |  |  |  |  |  |  | my $validation = { | 
| 18 |  |  |  |  |  |  | account => { | 
| 19 |  |  |  |  |  |  | estimateinvoice => [ [ 'mode' ], [qw( linodeid paymentterm planid )] ], | 
| 20 |  |  |  |  |  |  | info => [ [], [] ], | 
| 21 |  |  |  |  |  |  | paybalance => [ [], [] ], | 
| 22 |  |  |  |  |  |  | updatecard => [ [qw( ccexpmonth ccexpyear ccnumber )], [] ], | 
| 23 |  |  |  |  |  |  | }, | 
| 24 |  |  |  |  |  |  | api => { | 
| 25 |  |  |  |  |  |  | spec => [ [], [] ], | 
| 26 |  |  |  |  |  |  | }, | 
| 27 |  |  |  |  |  |  | avail => { | 
| 28 |  |  |  |  |  |  | datacenters => [ [], [] ], | 
| 29 |  |  |  |  |  |  | distributions => [ [], [ 'distributionid' ] ], | 
| 30 |  |  |  |  |  |  | kernels => [ [], [ 'isxen', 'kernelid' ] ], | 
| 31 |  |  |  |  |  |  | linodeplans => [ [], [ 'planid' ] ], | 
| 32 |  |  |  |  |  |  | nodebalancers => [ [], [] ], | 
| 33 |  |  |  |  |  |  | stackscripts => [ [], [qw( distributionid distributionvendor keywords )] ], | 
| 34 |  |  |  |  |  |  | }, | 
| 35 |  |  |  |  |  |  | domain => { | 
| 36 |  |  |  |  |  |  | create => [ [ 'domain', 'type' ], [qw( axfr_ips description expire_sec lpm_displaygroup master_ips refresh_sec retry_sec soa_email status ttl_sec )] ], | 
| 37 |  |  |  |  |  |  | delete => [ [ 'domainid' ], [] ], | 
| 38 |  |  |  |  |  |  | list => [ [], [ 'domainid' ] ], | 
| 39 |  |  |  |  |  |  | update => [ [ 'domainid' ], [qw( axfr_ips description domain expire_sec lpm_displaygroup master_ips refresh_sec retry_sec soa_email status ttl_sec type )] ], | 
| 40 |  |  |  |  |  |  | }, | 
| 41 |  |  |  |  |  |  | domain_resource => { | 
| 42 |  |  |  |  |  |  | create => [ [ 'domainid', 'type' ], [qw( name port priority protocol target ttl_sec weight )] ], | 
| 43 |  |  |  |  |  |  | delete => [ [ 'domainid', 'resourceid' ], [] ], | 
| 44 |  |  |  |  |  |  | list => [ [ 'domainid' ], [ 'resourceid' ] ], | 
| 45 |  |  |  |  |  |  | update => [ [ 'resourceid' ], [qw( domainid name port priority protocol target ttl_sec weight )] ], | 
| 46 |  |  |  |  |  |  | }, | 
| 47 |  |  |  |  |  |  | image => { | 
| 48 |  |  |  |  |  |  | delete => [ [ 'imageid' ], [] ], | 
| 49 |  |  |  |  |  |  | list => [ [], [ 'imageid', 'pending' ] ], | 
| 50 |  |  |  |  |  |  | update => [ [ 'imageid' ], [ 'description', 'label' ] ], | 
| 51 |  |  |  |  |  |  | }, | 
| 52 |  |  |  |  |  |  | linode => { | 
| 53 |  |  |  |  |  |  | boot => [ [ 'linodeid' ], [ 'configid' ] ], | 
| 54 |  |  |  |  |  |  | clone => [ [qw( datacenterid linodeid planid )], [ 'hypervisor', 'paymentterm' ] ], | 
| 55 |  |  |  |  |  |  | create => [ [ 'datacenterid', 'planid' ], [ 'paymentterm' ] ], | 
| 56 |  |  |  |  |  |  | delete => [ [ 'linodeid' ], [ 'skipchecks' ] ], | 
| 57 |  |  |  |  |  |  | list => [ [], [ 'linodeid' ] ], | 
| 58 |  |  |  |  |  |  | mutate => [ [ 'linodeid' ], [] ], | 
| 59 |  |  |  |  |  |  | reboot => [ [ 'linodeid' ], [ 'configid' ] ], | 
| 60 |  |  |  |  |  |  | resize => [ [ 'linodeid', 'planid' ], [] ], | 
| 61 |  |  |  |  |  |  | shutdown => [ [ 'linodeid' ], [] ], | 
| 62 |  |  |  |  |  |  | update => [ [ 'linodeid' ], [qw( alert_bwin_enabled alert_bwin_threshold alert_bwout_enabled alert_bwout_threshold alert_bwquota_enabled alert_bwquota_threshold alert_cpu_enabled alert_cpu_threshold alert_diskio_enabled alert_diskio_threshold backupweeklyday backupwindow label lpm_displaygroup ms_ssh_disabled ms_ssh_ip ms_ssh_port ms_ssh_user watchdog )] ], | 
| 63 |  |  |  |  |  |  | webconsoletoken => [ [ 'linodeid' ], [] ], | 
| 64 |  |  |  |  |  |  | }, | 
| 65 |  |  |  |  |  |  | linode_config => { | 
| 66 |  |  |  |  |  |  | create => [ [qw( disklist kernelid label linodeid )], [qw( comments devtmpfs_automount helper_depmod helper_disableupdatedb helper_distro helper_network helper_xen ramlimit rootdevicecustom rootdevicenum rootdevicero runlevel virt_mode )] ], | 
| 67 |  |  |  |  |  |  | delete => [ [ 'configid', 'linodeid' ], [] ], | 
| 68 |  |  |  |  |  |  | list => [ [ 'linodeid' ], [ 'configid' ] ], | 
| 69 |  |  |  |  |  |  | update => [ [ 'configid' ], [qw( comments devtmpfs_automount disklist helper_depmod helper_disableupdatedb helper_distro helper_network helper_xen kernelid label linodeid ramlimit rootdevicecustom rootdevicenum rootdevicero runlevel virt_mode )] ], | 
| 70 |  |  |  |  |  |  | }, | 
| 71 |  |  |  |  |  |  | linode_disk => { | 
| 72 |  |  |  |  |  |  | create => [ [qw( label linodeid size type )], [qw( fromdistributionid isreadonly rootpass rootsshkey )] ], | 
| 73 |  |  |  |  |  |  | createfromdistribution => [ [qw( distributionid label linodeid rootpass size )], [ 'rootsshkey' ] ], | 
| 74 |  |  |  |  |  |  | createfromimage => [ [ 'imageid', 'linodeid' ], [qw( label rootpass rootsshkey size )] ], | 
| 75 |  |  |  |  |  |  | createfromstackscript => [ [qw( distributionid label linodeid rootpass size stackscriptid stackscriptudfresponses )], [ 'rootsshkey' ] ], | 
| 76 |  |  |  |  |  |  | delete => [ [ 'diskid', 'linodeid' ], [] ], | 
| 77 |  |  |  |  |  |  | duplicate => [ [ 'diskid', 'linodeid' ], [] ], | 
| 78 |  |  |  |  |  |  | imagize => [ [ 'diskid', 'linodeid' ], [ 'description', 'label' ] ], | 
| 79 |  |  |  |  |  |  | list => [ [ 'linodeid' ], [ 'diskid' ] ], | 
| 80 |  |  |  |  |  |  | resize => [ [qw( diskid linodeid size )], [] ], | 
| 81 |  |  |  |  |  |  | update => [ [ 'diskid' ], [qw( isreadonly label linodeid )] ], | 
| 82 |  |  |  |  |  |  | }, | 
| 83 |  |  |  |  |  |  | linode_ip => { | 
| 84 |  |  |  |  |  |  | addprivate => [ [ 'linodeid' ], [] ], | 
| 85 |  |  |  |  |  |  | addpublic => [ [ 'linodeid' ], [] ], | 
| 86 |  |  |  |  |  |  | list => [ [], [ 'ipaddressid', 'linodeid' ] ], | 
| 87 |  |  |  |  |  |  | setrdns => [ [ 'hostname', 'ipaddressid' ], [] ], | 
| 88 |  |  |  |  |  |  | swap => [ [ 'ipaddressid' ], [ 'tolinodeid', 'withipaddressid' ] ], | 
| 89 |  |  |  |  |  |  | }, | 
| 90 |  |  |  |  |  |  | linode_job => { | 
| 91 |  |  |  |  |  |  | list => [ [ 'linodeid' ], [ 'jobid', 'pendingonly' ] ], | 
| 92 |  |  |  |  |  |  | }, | 
| 93 |  |  |  |  |  |  | nodebalancer => { | 
| 94 |  |  |  |  |  |  | create => [ [ 'datacenterid' ], [ 'clientconnthrottle', 'label' ] ], | 
| 95 |  |  |  |  |  |  | delete => [ [ 'nodebalancerid' ], [] ], | 
| 96 |  |  |  |  |  |  | list => [ [], [ 'nodebalancerid' ] ], | 
| 97 |  |  |  |  |  |  | update => [ [ 'nodebalancerid' ], [ 'clientconnthrottle', 'label' ] ], | 
| 98 |  |  |  |  |  |  | }, | 
| 99 |  |  |  |  |  |  | nodebalancer_config => { | 
| 100 |  |  |  |  |  |  | create => [ [ 'nodebalancerid' ], [qw( algorithm check check_attempts check_body check_interval check_path check_timeout port protocol ssl_cert ssl_key stickiness )] ], | 
| 101 |  |  |  |  |  |  | delete => [ [ 'configid', 'nodebalancerid' ], [] ], | 
| 102 |  |  |  |  |  |  | list => [ [ 'nodebalancerid' ], [ 'configid' ] ], | 
| 103 |  |  |  |  |  |  | update => [ [ 'configid' ], [qw( algorithm check check_attempts check_body check_interval check_path check_timeout port protocol ssl_cert ssl_key stickiness )] ], | 
| 104 |  |  |  |  |  |  | }, | 
| 105 |  |  |  |  |  |  | nodebalancer_node => { | 
| 106 |  |  |  |  |  |  | create => [ [qw( address configid label )], [ 'mode', 'weight' ] ], | 
| 107 |  |  |  |  |  |  | delete => [ [ 'nodeid' ], [] ], | 
| 108 |  |  |  |  |  |  | list => [ [ 'configid' ], [ 'nodeid' ] ], | 
| 109 |  |  |  |  |  |  | update => [ [ 'nodeid' ], [qw( address label mode weight )] ], | 
| 110 |  |  |  |  |  |  | }, | 
| 111 |  |  |  |  |  |  | professionalservices_scope => { | 
| 112 |  |  |  |  |  |  | create => [ [], [qw( application_quantity content_management crossover current_provider customer_name database_server email_address linode_datacenter linode_plan mail_filtering mail_retrieval mail_transfer managed monitoring notes phone_number provider_access replication requested_service server_quantity system_administration ticket_number web_cache web_server webmail )] ], | 
| 113 |  |  |  |  |  |  | }, | 
| 114 |  |  |  |  |  |  | stackscript => { | 
| 115 |  |  |  |  |  |  | create => [ [qw( distributionidlist label script )], [qw( description ispublic rev_note )] ], | 
| 116 |  |  |  |  |  |  | delete => [ [ 'stackscriptid' ], [] ], | 
| 117 |  |  |  |  |  |  | list => [ [], [ 'stackscriptid' ] ], | 
| 118 |  |  |  |  |  |  | update => [ [ 'stackscriptid' ], [qw( description distributionidlist ispublic label rev_note script )] ], | 
| 119 |  |  |  |  |  |  | }, | 
| 120 |  |  |  |  |  |  | test => { | 
| 121 |  |  |  |  |  |  | echo => [ [], [] ], | 
| 122 |  |  |  |  |  |  | }, | 
| 123 |  |  |  |  |  |  | user => { | 
| 124 |  |  |  |  |  |  | getapikey => [ [ 'password', 'username' ], [qw( expires label token )] ], | 
| 125 |  |  |  |  |  |  | }, | 
| 126 |  |  |  |  |  |  | }; | 
| 127 |  |  |  |  |  |  | # endvalidation | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | sub AUTOLOAD { | 
| 130 | 0 |  |  | 0 |  |  | ( my $name = $AUTOLOAD ) =~ s/.+:://; | 
| 131 | 0 | 0 |  |  |  |  | return if $name eq 'DESTROY'; | 
| 132 | 0 | 0 |  |  |  |  | if ( $name =~ m/^(QUEUE_)?(.*?)_([^_]+)$/ ) { | 
| 133 | 0 |  |  |  |  |  | my ( $queue, $thing, $action ) = ( $1, $2, $3 ); | 
| 134 | 0 | 0 | 0 |  |  |  | if ( exists $validation->{$thing} && exists $validation->{$thing}{$action} ) | 
| 135 | 1 |  |  | 1 |  | 6 | {   no strict 'refs'; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 571 |  | 
| 136 | 0 |  |  |  |  |  | *{$AUTOLOAD} = sub { | 
| 137 | 0 |  |  | 0 |  |  | my ( $self, %args ) = @_; | 
| 138 | 0 |  |  |  |  |  | for my $req ( @{ $validation->{$thing}{$action}[0] } ) { | 
|  | 0 |  |  |  |  |  |  | 
| 139 | 0 | 0 |  |  |  |  | if ( !exists $args{$req} ) { | 
| 140 | 0 |  |  |  |  |  | carp | 
| 141 |  |  |  |  |  |  | "Missing required argument $req for ${thing}_${action}"; | 
| 142 | 0 |  |  |  |  |  | return; | 
| 143 |  |  |  |  |  |  | } | 
| 144 |  |  |  |  |  |  | } | 
| 145 | 0 |  |  |  |  |  | for my $given ( keys %args ) { | 
| 146 | 0 | 0 |  |  |  |  | if (!first { $_ eq $given } | 
|  | 0 |  |  |  |  |  |  | 
| 147 | 0 |  |  |  |  |  | @{ $validation->{$thing}{$action}[0] }, | 
|  | 0 |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | @{ $validation->{$thing}{$action}[1] } ) | 
| 149 | 0 |  |  |  |  |  | {   carp "Unknown argument $given for ${thing}_${action}"; | 
| 150 | 0 |  |  |  |  |  | return; | 
| 151 |  |  |  |  |  |  | } | 
| 152 |  |  |  |  |  |  | } | 
| 153 | 0 |  |  |  |  |  | ( my $apiAction = "${thing}_${action}" ) =~ s/_/./g; | 
| 154 | 0 | 0 |  |  |  |  | return $self->queue_request( api_action => $apiAction, %args ) if $queue; | 
| 155 | 0 |  |  |  |  |  | my $data = $self->do_request( api_action => $apiAction, %args ); | 
| 156 | 0 | 0 |  |  |  |  | return [ map { $self->_lc_keys($_) } @$data ] | 
|  | 0 |  |  |  |  |  |  | 
| 157 |  |  |  |  |  |  | if ref $data eq 'ARRAY'; | 
| 158 | 0 | 0 |  |  |  |  | return $self->_lc_keys($data) if ref $data eq 'HASH'; | 
| 159 | 0 |  |  |  |  |  | return $data; | 
| 160 | 0 |  |  |  |  |  | }; | 
| 161 | 0 |  |  |  |  |  | goto &{$AUTOLOAD}; | 
|  | 0 |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  | } | 
| 163 |  |  |  |  |  |  | else { | 
| 164 | 0 |  |  |  |  |  | carp "Can't call ${thing}_${action}"; | 
| 165 | 0 |  |  |  |  |  | return; | 
| 166 |  |  |  |  |  |  | } | 
| 167 | 0 |  |  |  |  |  | return; | 
| 168 |  |  |  |  |  |  | } | 
| 169 | 0 |  |  |  |  |  | croak "Undefined subroutine \&$AUTOLOAD called"; | 
| 170 |  |  |  |  |  |  | } | 
| 171 |  |  |  |  |  |  |  | 
| 172 |  |  |  |  |  |  | sub send_queued_requests { | 
| 173 | 0 |  |  | 0 | 1 |  | my $self = shift; | 
| 174 | 0 |  |  |  |  |  | my $items = shift; | 
| 175 |  |  |  |  |  |  |  | 
| 176 | 0 | 0 |  |  |  |  | if ( $self->list_queue == 0 ) { | 
| 177 | 0 |  |  |  |  |  | $self->_error( -1, "No queued items to send" ); | 
| 178 | 0 |  |  |  |  |  | return; | 
| 179 |  |  |  |  |  |  | } | 
| 180 |  |  |  |  |  |  |  | 
| 181 | 0 |  |  |  |  |  | my @responses; | 
| 182 | 0 |  |  |  |  |  | for my $data ( $self->process_queue( $items ) ) { | 
| 183 | 0 | 0 |  |  |  |  | if ( ref $data eq 'ARRAY' ) { | 
|  |  | 0 |  |  |  |  |  | 
| 184 | 0 |  |  |  |  |  | push @responses, [ map { $self->_lc_keys($_) } @$data ]; | 
|  | 0 |  |  |  |  |  |  | 
| 185 |  |  |  |  |  |  | } elsif( ref $data eq 'HASH' ) { | 
| 186 | 0 |  |  |  |  |  | push @responses, $self->_lc_keys($data); | 
| 187 |  |  |  |  |  |  | } else { | 
| 188 | 0 |  |  |  |  |  | push @responses, $data; | 
| 189 |  |  |  |  |  |  | } | 
| 190 |  |  |  |  |  |  | } | 
| 191 |  |  |  |  |  |  |  | 
| 192 | 0 |  |  |  |  |  | return @responses; | 
| 193 |  |  |  |  |  |  | } | 
| 194 |  |  |  |  |  |  |  | 
| 195 |  |  |  |  |  |  | 'mmm, cake'; | 
| 196 |  |  |  |  |  |  | __END__ |