├── README ├── examples └── cgirdns │ ├── htaccess │ ├── rdns.pl │ └── userdb.txt ├── hetzner-robot.pl └── lib └── Hetzner ├── MetaRobot.pm ├── Robot.pm └── Robot ├── AuthException.pm ├── Boot.pm ├── Boot ├── Plesk.pm ├── Rescue.pm ├── VNC.pm └── Windows.pm ├── Exception.pm ├── Failover.pm ├── IP.pm ├── Item.pm ├── Item └── Enumerable.pm ├── NotFoundException.pm ├── RDNS.pm ├── Reset.pm ├── Server.pm ├── Subnet.pm └── WOL.pm /README: -------------------------------------------------------------------------------- 1 | Hetzner::Robot / hetzner-robot.pl 2 | by Stefan Tomanek 3 | 4 | http://github.com/wertarbyte/hetzner-robot-perl 5 | 6 | Control the Hetzner robot from your Perl scripts or console. 7 | 8 | The script hetzner-robot.pl can be used as a standalone program as well as an 9 | object oriented Perl module in your own scripts. It uses the JSON-Webservice 10 | deployed by Hetzner (http://wiki.hetzner.de/index.php/Robot_Webservice) and 11 | encapsulates it into a class/object structure. Many default operations are 12 | provided through a command line interface. 13 | 14 | == Examples for standalone operation == 15 | 16 | # retrieve reverse DNS entry for IP address 1.2.3.4 17 | 18 | hetzner-robot.pl --user "USERNAME" --password "PASSWORD" \ 19 | --mode rdns --get --addr 1.2.3.4 20 | 21 | # set reverse DNS entry for address 1.2.3.4 to "foobar.example.org" 22 | 23 | hetzner-robot.pl --user "USERNAME" --password "PASSWORD" \ 24 | --mode rdns --set --addr 1.2.3.4 --hostname foobar.example.org 25 | 26 | # instruct the hetzner robot to trigger a hardware reset at server 1.2.3.4 27 | 28 | hetzner-robot.pl --user "USERNAME" --password "PASSWORD" \ 29 | --mode reset --address 1.2.3.4 --method hw 30 | 31 | # enable the rescue system for server 1.2.3.4 32 | 33 | hetzner-robot.pl --user "USERNAME" --password "PASSWORD" \ 34 | --mode rescue --address 1.2.3.4 --system linux --arch 64 35 | 36 | # send Wake-On-LAN signal to system 1.2.3.4 37 | 38 | hetzner-robot.pl --user "USERNAME" --password "PASSWORD" \ 39 | --mode wol --address 1.2.3.4 40 | 41 | # switch failover address to server 1.2.3.4 42 | 43 | hetzner-robot.pl --user "USERNAME" --password "PASSWORD" \ 44 | --mode failover --address 5.6.7.8 --target 1.2.3.4 45 | 46 | # retrieve status of a failover address 47 | 48 | hetzner-robot.pl --user "USERNAME" --password "PASSWORD" \ 49 | --mode failover --address 5.6.7.8 --status 50 | 51 | # to hide the password from the command line, it can be read from stdin: 52 | 53 | echo "passphrase" | hetzner-robot.pl --user "USERNAME" --readpw ... 54 | 55 | == Examples for use in scripts == 56 | 57 | #!/usr/bin/perl 58 | # load module 59 | use Hetzner::Robot; 60 | 61 | my $robot = new Hetzner::Robot("username", "password"); 62 | my $serverA = $robot->server("1.2.3.4"); 63 | # enumerate subnets assigned to server 64 | for my $n ($serverA->subnets) { 65 | print $n->address."/".$n->netmask, "\n"; 66 | } 67 | 68 | # send WOL signal to all servers 69 | for my $sys ($robot->servers) { 70 | print "Waking up ".$sys->address."\n"; 71 | $sys->wol->execute; 72 | # $sys->reset->execute("sw"); # we could trigger a soft reboot as well ;-) 73 | } 74 | 75 | 76 | The examples directory also contains a simple CGI script to grant customers 77 | limited access to the reverse DNS capabilities of the robot; each customer 78 | can access the RDNS records of the addresses associated with their username. 79 | -------------------------------------------------------------------------------- /examples/cgirdns/htaccess: -------------------------------------------------------------------------------- 1 | AuthType Basic 2 | AuthName "CGIRDNS" 3 | AuthUserFile /var/cgirdns/htpasswd 4 | Require valid-user 5 | 6 | SetEnv RDNSUSERS "/var/cgirdns/userdb.txt" 7 | SetEnv ROBOT_USER "myrobotuser" 8 | SetEnv ROBOT_PASSWORD "myrobotpw" 9 | -------------------------------------------------------------------------------- /examples/cgirdns/rdns.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use CGI qw/:standard/; 5 | use IO::File; 6 | 7 | my $ADDRESS_FILE = $ENV{RDNSUSERS}; 8 | my $ROBOT_NAME = $ENV{ROBOT_USER}; 9 | my $ROBOT_PASSWORD = $ENV{ROBOT_PASSWORD}; 10 | 11 | # clear environment 12 | delete $ENV{ROBOT_USER}; 13 | delete $ENV{ROBOT_PASSWORD}; 14 | 15 | use Hetzner::Robot; 16 | use Hetzner::Robot::RDNS; 17 | 18 | my $robot = Hetzner::Robot->new($ROBOT_NAME, $ROBOT_PASSWORD); 19 | 20 | sub ptr { 21 | my ($addr, $name) = @_; 22 | my $rdns = new Hetzner::Robot::RDNS($robot, $addr); 23 | return $rdns->ptr($name); 24 | } 25 | 26 | sub addresses { 27 | my ($client) = @_; 28 | my @l; 29 | my $fh = new IO::File($ADDRESS_FILE, "r"); 30 | while (<$fh>) { 31 | s/#.*$//; 32 | my ($user, @addr) = split /[[:space:]]+/; 33 | if ($client eq $user) { 34 | push @l, @addr; 35 | } 36 | } 37 | $fh->close; 38 | return @l; 39 | } 40 | 41 | my $q = new CGI; 42 | 43 | print $q->header("text/html"); 44 | 45 | 46 | print start_html; 47 | 48 | print start_body; 49 | 50 | print $q->h1("Willkommen, ".$q->remote_user); 51 | 52 | print start_form; 53 | 54 | if ($q->param("change")) { 55 | for my $a (addresses($q->remote_user)) { 56 | my $new = $q->param("rdns-$a"); 57 | next unless defined $new; 58 | # entry changed? 59 | my $old = ptr($a); 60 | if ($old ne $new) { 61 | # set the new value 62 | ptr($a, $new); 63 | print p("Changed RDNS entry for $a from $old to $new"); 64 | } 65 | } 66 | } 67 | 68 | my $i = 0; 69 | print table ( 70 | { -border => 1 }, 71 | map {$i++; Tr( td( 72 | [$i, 73 | $_, 74 | textfield(-name=>"rdns-$_", -default=>ptr($_) )] 75 | ) ) 76 | } addresses($q->remote_user) 77 | ); 78 | print hidden(-name=>"change", -default=>"1"); 79 | print submit; 80 | print end_form; 81 | 82 | print end_body; 83 | print end_html; 84 | -------------------------------------------------------------------------------- /examples/cgirdns/userdb.txt: -------------------------------------------------------------------------------- 1 | # username address1 address2 address3... 2 | customerFoo 192.168.0.1 192.168.0.2 10.0.0.1 3 | customerBar 192.168.0.3 192.168.0.4 192.168.0.5 4 | -------------------------------------------------------------------------------- /hetzner-robot.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # 3 | # Perl interface for the webservice interface 4 | # provided by Hetzner 5 | # 6 | # by Stefan Tomanek 7 | # 8 | 9 | use strict; 10 | use lib "lib/"; 11 | 12 | ################################## 13 | 14 | package Hetzner::Robot::RDNS::main; 15 | use Hetzner::Robot::RDNS; 16 | use Getopt::Long; 17 | 18 | sub run { 19 | my ($robot) = @_; 20 | 21 | my ($get, $set, $del); 22 | my ($addr, $name); 23 | 24 | my $batch = 0; 25 | my $all = 0; 26 | 27 | GetOptions ( 28 | 'get|g' => \$get, 29 | 'all!' => \$all, 30 | 'set|s' => \$set, 31 | 'delete|del|d' => \$del, 32 | 'hostname|name|n=s' => \$name, 33 | 'address|addr|a=s' => \$addr, 34 | 'batch!' => \$batch 35 | ) || Hetzner::Robot::main::abort(); 36 | # check command line 37 | Hetzner::Robot::main::abort("No operation specified!") unless ($get ^ $set ^ $del ^ $batch); 38 | unless ($batch || ($get && $all)) { 39 | Hetzner::Robot::main::abort("No address specified!") if (($get||$set||$del) && (!defined $addr)); 40 | Hetzner::Robot::main::abort("No hostname specified!") if ($set && !defined $name); 41 | } 42 | 43 | if ($batch) { 44 | while () { 45 | s/[[:space:]]*#.*$//; 46 | next if (/^$/); 47 | my ($addr, $name) = split(/[[:space:]]+/); 48 | my $i = new Hetzner::Robot::RDNS($robot, $addr); 49 | if ($name ne "") { 50 | print STDERR "Setting RDNS entry for $addr to $name...\n"; 51 | $i->ptr($name); 52 | } else { 53 | print STDERR "Removing RDNS entry for $addr...\n"; 54 | $i->del; 55 | } 56 | print $i->address, "\t", $i->ptr, "\n"; 57 | } 58 | } elsif ($get && $all) { 59 | # dump all host entries 60 | print $_->address."\t".$_->ptr."\n" for Hetzner::Robot::RDNS->enumerate($robot); 61 | } else { 62 | # handle a single change 63 | my $rdns = new Hetzner::Robot::RDNS($robot, $addr); 64 | 65 | if ($get || $set) { 66 | if ($set) { 67 | print STDERR "Setting $addr to $name...\n"; 68 | $rdns->ptr($name); 69 | } 70 | print $rdns->address, "\t", $rdns->ptr, "\n"; 71 | } 72 | if ($del) { 73 | print STDERR "Removing RDNS entry for $addr...\n"; 74 | $rdns->del; 75 | } 76 | } 77 | } 78 | 79 | 1; 80 | 81 | package Hetzner::Robot::Failover::main; 82 | use Hetzner::Robot::Failover; 83 | use Getopt::Long; 84 | 85 | sub run { 86 | my ($robot) = @_; 87 | 88 | my $addr; 89 | my $target; 90 | my $status; 91 | 92 | GetOptions ( 93 | 'address|addr|a=s' => \$addr, 94 | 'target=s' => \$target, 95 | 'status' => \$status 96 | ) || Hetzner::Robot::main::abort(); 97 | Hetzner::Robot::main::abort("No failover address specified!") unless defined $addr; 98 | 99 | my $fo = new Hetzner::Robot::Failover($robot, $addr); 100 | if ($target) { 101 | my $t = $robot->server($target); 102 | $fo->target($t); 103 | } 104 | if ($status) { 105 | print "address:\t".$fo->address."\n"; 106 | print "netmask:\t".$fo->netmask."\n"; 107 | print "server:\t".$fo->server->address."\n"; 108 | print "target:\t".$fo->target->address."\n"; 109 | } 110 | } 111 | 112 | 1; 113 | 114 | package Hetzner::Robot::WOL::main; 115 | use Hetzner::Robot::WOL; 116 | use Getopt::Long; 117 | 118 | sub run { 119 | my ($robot) = @_; 120 | 121 | my $addr; 122 | 123 | GetOptions ( 124 | 'address|addr|a=s' => \$addr, 125 | ) || Hetzner::Robot::main::abort(); 126 | Hetzner::Robot::main::abort("No server address specified!") unless defined $addr; 127 | 128 | $robot->server($addr)->wol->execute; 129 | } 130 | 131 | 1; 132 | 133 | package Hetzner::Robot::Reset::main; 134 | use Hetzner::Robot::Reset; 135 | use Getopt::Long; 136 | 137 | sub run { 138 | my ($robot) = @_; 139 | 140 | my $addr; 141 | my $force = 0; 142 | my $method = 'sw'; 143 | 144 | GetOptions ( 145 | 'address|addr|a=s' => \$addr, 146 | 'method' => \$method, 147 | 'force!' => \$force 148 | ) || Hetzner::Robot::main::abort(); 149 | Hetzner::Robot::main::abort("No server address specified!") unless defined $addr; 150 | 151 | if ($force || confirm_reset($addr, $method)) { 152 | $robot->server($addr)->reset->execute($method); 153 | } 154 | } 155 | 156 | sub confirm_reset { 157 | my ($addr, $m) = @_; 158 | my $magic = "Do as I say!"; 159 | print STDERR "Are you sure you want to reboot the server <$addr> ($m)?\nPlease enter the sentence '$magic'\n> "; 160 | my $answer = ; 161 | chomp($answer); 162 | if (lc $answer eq lc $magic) { 163 | print STDERR "Thank you.\n"; 164 | return 1; 165 | } else { 166 | Hetzner::Robot::main::abort("Reset aborted."); 167 | } 168 | } 169 | 170 | 1; 171 | 172 | package Hetzner::Robot::Boot::Rescue::main; 173 | use Hetzner::Robot::Boot::Rescue; 174 | use Getopt::Long; 175 | 176 | sub run { 177 | my ($robot) = @_; 178 | 179 | my $enable; 180 | my $disable; 181 | my $status; 182 | my $addr; 183 | my $arch; 184 | my $sys; 185 | 186 | GetOptions ( 187 | 'enable' => \$enable, 188 | 'disable' => \$disable, 189 | 'status' => \$status, 190 | 'address|addr|a=s' => \$addr, 191 | 'architecture|arch=s' => \$arch, 192 | 'system|sys=s' => \$sys 193 | ) || Hetzner::Robot::main::abort(); 194 | Hetzner::Robot::main::abort("No server address specified!") unless defined $addr; 195 | Hetzner::Robot::main::abort("No action (disable/enable/status) specified!") unless ($enable || $disable || $status); 196 | 197 | my $rescue = $robot->server($addr)->rescue; 198 | if ($enable) { 199 | Hetzner::Robot::main::abort("No operating system specified!") unless defined $sys; 200 | Hetzner::Robot::main::abort("No architecture specified!") unless defined $arch; 201 | if ($rescue->enable($sys, $arch)) { 202 | print "Rescue system enabled, password is:\n"; 203 | print $rescue->password(), "\n"; 204 | } 205 | } 206 | if ($disable) { 207 | $rescue->disable; 208 | } 209 | if ($status) { 210 | my $r = $rescue; 211 | print "active:\t".$r->active."\n"; 212 | if ($r->active) { 213 | print "os:\t".$r->os."\n"; 214 | print "arch:\t".$r->arch."\n"; 215 | print "password:\t".$r->password."\n"; 216 | } else { 217 | print "archs:\t".join(" ", $r->available_arch)."\n"; 218 | print "systems:\t".join(" ", $r->available_os)."\n"; 219 | } 220 | } 221 | } 222 | 223 | 1; 224 | 225 | 226 | package Hetzner::Robot::main; 227 | use Hetzner::Robot; 228 | use Getopt::Long; 229 | 230 | sub abort { 231 | my ($msg) = @_; 232 | print STDERR $msg,"\n" if $msg; 233 | exit 1; 234 | } 235 | 236 | sub run { 237 | # available operation modes 238 | my %modes = ( 239 | rdns => "RDNS", 240 | failover => "Failover", 241 | wol => "WOL", 242 | reset => "Reset", 243 | rescue => "Boot::Rescue" 244 | ); 245 | 246 | my $p = new Getopt::Long::Parser; 247 | $p->configure("pass_through"); 248 | 249 | my ($user, $pass, $readpw, $mode); 250 | $p->getoptions ( 251 | 'username|user|u=s' => \$user, 252 | 'password|pass|p=s' => \$pass, 253 | 'readpw' => \$readpw, 254 | 'mode=s' => \$mode 255 | ) || abort; 256 | if ($readpw) { 257 | print STDERR "Reading password from STDIN: "; 258 | $pass = ; 259 | print STDERR "Thank you.\n"; 260 | } 261 | abort "No user credentials specified!" unless (defined $user && defined $pass); 262 | abort "No valid operation mode (".join("/", keys %modes).") specified!" unless defined $mode or defined $modes{lc $mode}; 263 | 264 | my $robot = new Hetzner::Robot($user, $pass); 265 | 266 | if (exists $modes{lc $mode}) { 267 | eval { 268 | no strict 'refs'; 269 | &{"Hetzner::Robot::".$modes{$mode}."::main::run"}($robot); 270 | }; 271 | die (ref($@) ? $@->msg."\n" : $@) if $@; 272 | } else { 273 | abort "Unknown mode '$mode'"; 274 | } 275 | } 276 | 277 | 1; 278 | 279 | package default; 280 | Hetzner::Robot::main::run(); 281 | -------------------------------------------------------------------------------- /lib/Hetzner/MetaRobot.pm: -------------------------------------------------------------------------------- 1 | package Hetzner::MetaRobot; 2 | use strict; 3 | 4 | use Hetzner::Robot; 5 | 6 | sub new { 7 | my ($this, $user, $password) = @_; 8 | my $cls = ref($this) || $this; 9 | my $self = { robots => [] }; 10 | my $me = bless $self, $cls; 11 | 12 | if ($user) { 13 | # initialize first sub-robot 14 | $me->add_credentials( $user, $password ); 15 | } 16 | 17 | return $me; 18 | } 19 | 20 | sub add_credentials { 21 | my ($self, $user, $password) = @_; 22 | my $r = new Hetzner::Robot($user, $password); 23 | push @{$self->{robots}}, $r; 24 | # return $self so the command can be chained 25 | return $self; 26 | } 27 | 28 | sub req { 29 | my ($self, @params) = @_; 30 | 31 | for my $r (@{ $self->{robots}}) { 32 | my $result = eval { 33 | $r->req(@params); 34 | }; 35 | # Not found? Try the next robot, otherwise rethrow exception. 36 | if ($@){ 37 | if (ref($@) ne "Hetzner::Robot::NotFoundException") { 38 | die $@; 39 | } else { 40 | next; 41 | } 42 | } else { 43 | return $result; 44 | } 45 | } 46 | } 47 | 48 | sub server { 49 | my ($self, $addr) = @_; 50 | for my $r (@{ $self->{robots}}) { 51 | my $s = $r->server($addr); 52 | return $s if $s->is_valid; 53 | } 54 | # Fallback 55 | return new Hetzner::Robot::Server($self, $addr); 56 | } 57 | 58 | sub servers { 59 | my ($self) = @_; 60 | return map {$_->servers} @{ $self->{robots} }; 61 | } 62 | 63 | 1; 64 | -------------------------------------------------------------------------------- /lib/Hetzner/Robot.pm: -------------------------------------------------------------------------------- 1 | package Hetzner::Robot; 2 | use strict; 3 | 4 | =head1 NAME 5 | 6 | Hetzner::Robot - Access the webservice of the Hetzner Robot 7 | 8 | =head1 SYNOPSIS 9 | 10 | use Hetzner::Robot; 11 | my $robot = new Hetzner::Robot("user", "password"); 12 | print $_->address, "\n" for $robot->servers; 13 | 14 | =head1 DESCRIPTION 15 | 16 | C encapsulates the access credentials to the Hetzner 17 | webservice and provides methods to communicate with it. In case of 18 | faulty credentials or invalid requests, the object may generate 19 | a variety of exceptions. 20 | 21 | =cut 22 | 23 | use Hetzner::Robot::Server; 24 | use Hetzner::Robot::Exception; 25 | use Hetzner::Robot::AuthException; 26 | use Hetzner::Robot::NotFoundException; 27 | 28 | use LWP::UserAgent; 29 | use JSON; 30 | use HTTP::Request; 31 | use HTTP::Status qw(:constants); 32 | use URI::Escape; 33 | 34 | our $BASEURL = "https://robot-ws.your-server.de"; 35 | 36 | =head2 METHODS 37 | 38 | =over 4 39 | 40 | =item Hetzner::Robot->new( $username, $password ) 41 | 42 | Returns a new object holding the supplied credentials. 43 | 44 | =cut 45 | 46 | sub new { 47 | my ($this, $user, $password) = @_; 48 | my $class = ref($this) || $this; 49 | my $self = { user => $user, pass => $password }; 50 | $self->{ua} = new LWP::UserAgent(); 51 | $self->{ua}->env_proxy; 52 | bless $self, $class; 53 | } 54 | 55 | sub req { 56 | my ($self, $type, $url, $data) = @_; 57 | my $req = new HTTP::Request($type => $BASEURL.$url); 58 | $req->authorization_basic($self->{user}, $self->{pass}); 59 | if ($data) { 60 | my @token = map( { uri_escape($_)."=".uri_escape($data->{$_}) } keys %$data ); 61 | $req->content_type('application/x-www-form-urlencoded'); 62 | $req->content( join("&", @token) ); 63 | } 64 | my $res = $self->{ua}->request($req); 65 | if ($res->is_success) { 66 | if ($res->decoded_content) { 67 | return from_json($res->decoded_content); 68 | } else { 69 | return 1; 70 | } 71 | } else { 72 | # something bad happened, throw an exception 73 | if ($res->code == HTTP_UNAUTHORIZED) { 74 | die Hetzner::Robot::AuthException->new(); 75 | } 76 | if ($res->code == HTTP_NOT_FOUND) { 77 | die Hetzner::Robot::NotFoundException->new($url); 78 | } 79 | # what else might try to ruin our day? 80 | die Hetzner::Robot::Exception->new("Unable to access ".$url.": [".$res->code."]".$res->status_line); 81 | } 82 | } 83 | 84 | =item $robot->server( $addr ) 85 | 86 | Returns a C object representing the server 87 | with the supplied main address 88 | 89 | =cut 90 | 91 | sub server { 92 | my ($self, $addr) = @_; 93 | return Hetzner::Robot::Server->new($self, $addr); 94 | } 95 | 96 | =item $robot->servers 97 | 98 | Returns a list of all server objects known to the robot account. 99 | 100 | =cut 101 | 102 | sub servers { 103 | my ($self) = @_; 104 | return Hetzner::Robot::Server->enumerate($self); 105 | } 106 | 107 | 1; 108 | 109 | =back 110 | 111 | =head1 SEE ALSO 112 | 113 | L, 114 | L, 115 | L, 116 | L 117 | -------------------------------------------------------------------------------- /lib/Hetzner/Robot/AuthException.pm: -------------------------------------------------------------------------------- 1 | package Hetzner::Robot::AuthException; 2 | use base "Hetzner::Robot::Exception"; 3 | use strict; 4 | 5 | sub new { 6 | my ($this) = @_; 7 | my $cls = ref($this) || $this; 8 | return $cls->SUPER::new("Authentication failed"); 9 | } 10 | 11 | 1; 12 | -------------------------------------------------------------------------------- /lib/Hetzner/Robot/Boot.pm: -------------------------------------------------------------------------------- 1 | package Hetzner::Robot::Boot; 2 | use base "Hetzner::Robot::Item"; 3 | use strict; 4 | 5 | sub active { 6 | return ( $_[0]->__info->{active} ? 1 : 0 ); 7 | } 8 | 9 | sub password { 10 | return $_[0]->__info->{password}; 11 | } 12 | 13 | sub arch { 14 | return $_[0]->__info->{arch}; 15 | } 16 | 17 | sub disable { 18 | my ($self) = @_; 19 | return $self->req("DELETE", $self->__url); 20 | } 21 | 22 | sub __aslist { 23 | my ($self, $ref) = @_; 24 | if ($ref) { 25 | return @$ref; 26 | } else { 27 | return (); 28 | } 29 | } 30 | 31 | 1; 32 | -------------------------------------------------------------------------------- /lib/Hetzner/Robot/Boot/Plesk.pm: -------------------------------------------------------------------------------- 1 | package Hetzner::Robot::Boot::Plesk; 2 | use base "Hetzner::Robot::Boot"; 3 | use strict; 4 | 5 | =head1 NAME 6 | 7 | Hetzner::Robot::Boot::Plesk - Configure the Hetzner Plesk installer 8 | 9 | =head1 SYNOPSIS 10 | 11 | my $robot = new Hetzner::Robot( "user", "password" ); 12 | my $plesk = new Hetzner::Robot::Boot::Plesk( $robot, "1.2.3.4" ); 13 | 14 | # enable Plesk installation for server 1.2.3.4 15 | $plesk->enable( "Debian 5.0 minimal", 64, "de", "foo.hostname.example" ); 16 | print "Password is: ", $plesk->password, "\n"; 17 | 18 | =head1 METHODS 19 | 20 | =over 21 | 22 | =item Hetzner::Robot::Boot::Plesk->new( $robot, $address ) 23 | 24 | Returns the Plesk installer handle for the specified server address. 25 | 26 | =item $plesk->active 27 | 28 | Returns whether the Plesk installation is activated. 29 | 30 | =item $plesk->password 31 | 32 | Returns the password generated for the activated Pleask installer. 33 | 34 | =item $plesk->dist 35 | 36 | =item $plesk->arch 37 | 38 | =item $plesk->lang 39 | 40 | Returns the set distribution, architecture or language of the active installer. 41 | 42 | =cut 43 | 44 | sub dist { 45 | return $_[0]->__info->{dist}; 46 | } 47 | 48 | sub arch { 49 | return $_[0]->__info->{arch}; 50 | } 51 | 52 | 53 | sub lang { 54 | return $_[0]->__info->{lang}; 55 | } 56 | 57 | =item $plesk->available_dist 58 | 59 | =item $plesk->available_arch 60 | 61 | =item $plesk->available_lang 62 | 63 | Returns a list of all available distributions, architectures or languages. 64 | 65 | =cut 66 | 67 | sub available_dist { 68 | return $_[0]->__aslist( $_[0]->__info->{dist} ); 69 | } 70 | 71 | sub available_arch { 72 | return $_[0]->__aslist( $_[0]->__info->{arch} ); 73 | } 74 | 75 | sub available_lang { 76 | return $_[0]->__aslist( $_[0]->__info->{lang} ); 77 | } 78 | 79 | =item $plesk->enable( $dist, $arch, $lang, $hostname ) 80 | 81 | Activate the Plesk installer. 82 | 83 | =cut 84 | 85 | sub enable { 86 | my ($self, $dist, $arch, $lang, $hostname) = @_; 87 | return $self->__conf(dist => $dist, arch => $arch, lang => $lang, hostname => $hostname); 88 | } 89 | 90 | =item $plesk->disable 91 | 92 | Disable the Plesk installer. 93 | 94 | =back 95 | =cut 96 | 1; 97 | -------------------------------------------------------------------------------- /lib/Hetzner/Robot/Boot/Rescue.pm: -------------------------------------------------------------------------------- 1 | package Hetzner::Robot::Boot::Rescue; 2 | use base "Hetzner::Robot::Boot"; 3 | use strict; 4 | 5 | =head1 NAME 6 | 7 | Hetzner::Robot::Boot::Rescue - Configure the Hetzner rescue system 8 | 9 | =head1 SYNOPSIS 10 | 11 | my $robot = new Hetzner::Robot( "user", "password" ); 12 | my $rescue = new Hetzner::Robot::Boot::Rescue( $robot, "1.2.3.4" ); 13 | 14 | # enable rescue system for server 1.2.3.4 15 | $rescue->enable( "linux", "64" ); 16 | print "Password is: ", $rescue->password, "\n"; 17 | 18 | =head1 METHODS 19 | 20 | =over 21 | 22 | =item Hetzner::Robot::Boot::Rescue->new( $robot, $address ) 23 | 24 | Returns the rescue system handle for the specified server address. 25 | 26 | =item $rescue->active 27 | 28 | Returns whether the rescue system is activated. 29 | 30 | =item $rescue->password 31 | 32 | Returns the password generated for the activatede rescue system. 33 | 34 | =item $rescue->os 35 | 36 | =item $rescue->arch 37 | 38 | Returns the set operating system or architecture. 39 | 40 | =cut 41 | 42 | sub os { 43 | return $_[0]->__info->{os}; 44 | } 45 | 46 | =item $rescue->available_os 47 | 48 | =item $rescue->available_arch 49 | 50 | Returns a list of all available operating systems or architectures. 51 | 52 | =cut 53 | 54 | sub available_os { 55 | return $_[0]->__aslist( $_[0]->__info->{os} ); 56 | } 57 | 58 | sub available_arch { 59 | return $_[0]->__aslist( $_[0]->__info->{arch} ); 60 | } 61 | 62 | =item $rescue->enable( $os, $arch ) 63 | 64 | Prepare the rescue system with the specified OS and architecture. 65 | 66 | =cut 67 | 68 | sub enable { 69 | my ($self, $os, $arch) = @_; 70 | return $self->__conf(os => $os, arch => $arch); 71 | } 72 | 73 | =item $rescue->disable 74 | 75 | Disable the rescue system. 76 | 77 | =back 78 | =cut 79 | 1; 80 | -------------------------------------------------------------------------------- /lib/Hetzner/Robot/Boot/VNC.pm: -------------------------------------------------------------------------------- 1 | package Hetzner::Robot::Boot::VNC; 2 | use base "Hetzner::Robot::Boot"; 3 | use strict; 4 | 5 | =head1 NAME 6 | 7 | Hetzner::Robot::Boot::VNC - Configure the Hetzner VNC installation 8 | 9 | =head1 SYNOPSIS 10 | 11 | my $robot = new Hetzner::Robot( "user", "password" ); 12 | my $vnc = new Hetzner::Robot::Boot::VNC( $robot, "1.2.3.4" ); 13 | 14 | # enable VNC installation for server 1.2.3.4 15 | $vnc->enable( "centOS-5.0", "64", "de_DE" ); 16 | print "Password is: ", $vnc->password, "\n"; 17 | 18 | =head1 METHODS 19 | 20 | =over 21 | 22 | =item Hetzner::Robot::Boot::VNC->new( $robot, $address ) 23 | 24 | Returns the VNC installer handle for the specified server address. 25 | 26 | =item $vnc->active 27 | 28 | Returns whether the VNC installation is activated. 29 | 30 | =item $vnc->password 31 | 32 | Returns the password generated for the activated VNC installer 33 | 34 | =item $vnc->dist 35 | 36 | =item $vnc->arch 37 | 38 | =item $vnc->lang 39 | 40 | Returns the set distribution, architecture and language 41 | 42 | =cut 43 | 44 | sub dist { 45 | return $_[0]->__info->{dist}; 46 | } 47 | 48 | sub lang { 49 | return $_[0]->__info->{lang}; 50 | } 51 | 52 | =item $vnc->available_dist 53 | 54 | =item $vnc->available_arch 55 | 56 | Returns a list of all available distributions, architectures or languages. 57 | 58 | =cut 59 | 60 | sub available_dist { 61 | return $_[0]->__aslist( $_[0]->__info->{dist} ); 62 | } 63 | 64 | sub available_arch { 65 | return $_[0]->__aslist( $_[0]->__info->{arch} ); 66 | } 67 | 68 | sub available_lang { 69 | return $_[0]->__aslist( $_[0]->__info->{lang} ); 70 | } 71 | 72 | =item $vnc->enable( $os, $arch, $lang ) 73 | 74 | Prepare the VNC installation with the specified distribution, architecture 75 | and language. 76 | 77 | =cut 78 | 79 | sub enable { 80 | my ($self, $dist, $arch, $lang) = @_; 81 | return $self->__conf(dist => $dist, arch => $arch, lang => $lang); 82 | } 83 | 84 | =item $vnc->disable 85 | 86 | Disable the VNC installer. 87 | 88 | =back 89 | =cut 90 | 1; 91 | -------------------------------------------------------------------------------- /lib/Hetzner/Robot/Boot/Windows.pm: -------------------------------------------------------------------------------- 1 | package Hetzner::Robot::Boot::Windows; 2 | use base "Hetzner::Robot::Boot"; 3 | use strict; 4 | 5 | =head1 NAME 6 | 7 | Hetzner::Robot::Boot::Windows - Configure the Hetzner Windows installation 8 | 9 | =head1 SYNOPSIS 10 | 11 | my $robot = new Hetzner::Robot( "user", "password" ); 12 | my $win = new Hetzner::Robot::Boot::Windows( $robot, "1.2.3.4" ); 13 | 14 | # enable Windows installation for server 1.2.3.4 15 | $win->enable( "de" ); 16 | print "Password is: ", $win->password, "\n"; 17 | 18 | =head1 METHODS 19 | 20 | =over 21 | 22 | =item Hetzner::Robot::Boot::Windows->new( $robot, $address ) 23 | 24 | Returns the Windows installer handle for the specified server address. 25 | 26 | =item $win->active 27 | 28 | Returns whether the Windows installation is activated. 29 | 30 | =item $win->password 31 | 32 | Returns the password generated for the activated Windows installer. 33 | 34 | =item $win->dist 35 | 36 | =item $win->lang 37 | 38 | Returns the set distribution or language of the active installer. 39 | 40 | =cut 41 | 42 | sub dist { 43 | return $_[0]->__info->{dist}; 44 | } 45 | 46 | sub lang { 47 | return $_[0]->__info->{lang}; 48 | } 49 | 50 | =item $win->available_dist 51 | 52 | =item $win->available_lang 53 | 54 | Returns a list of all available distributions or languages. 55 | 56 | =cut 57 | 58 | sub available_dist { 59 | return $_[0]->__aslist( $_[0]->__info->{dist} ); 60 | } 61 | 62 | sub available_lang { 63 | return $_[0]->__aslist( $_[0]->__info->{lang} ); 64 | } 65 | 66 | =item $win->enable( $lang ) 67 | 68 | Activate the Windows installer the specified language. 69 | 70 | =cut 71 | 72 | sub enable { 73 | my ($self, $lang) = @_; 74 | return $self->__conf(lang => $lang); 75 | } 76 | 77 | =item $win->disable 78 | 79 | Disable the Windows installer. 80 | 81 | =back 82 | =cut 83 | 1; 84 | -------------------------------------------------------------------------------- /lib/Hetzner/Robot/Exception.pm: -------------------------------------------------------------------------------- 1 | package Hetzner::Robot::Exception; 2 | use strict; 3 | use overload '""' => \&msg; 4 | 5 | sub new { 6 | my ($this, $msg) = @_; 7 | my $cls = ref($this) || $this; 8 | bless {msg=>$msg}, $cls; 9 | } 10 | 11 | sub msg { 12 | return shift->{msg}; 13 | } 14 | 15 | 1; 16 | -------------------------------------------------------------------------------- /lib/Hetzner/Robot/Failover.pm: -------------------------------------------------------------------------------- 1 | package Hetzner::Robot::Failover; 2 | use base "Hetzner::Robot::Item::Enumerable"; 3 | use strict; 4 | 5 | =head1 NAME 6 | 7 | Hetzner::Robot::Failover - Direct failover addresses 8 | 9 | =head1 SYNOPSIS 10 | 11 | my $robot = new Hetzner::Robot("user", "password); 12 | # get object for failover network 10.10.5.1 13 | my $failover = new Hetzner::Failover( $robot, "10.10.5.1" ); 14 | print "Current destination: ".$failover->target; 15 | # redirect failover network to other server 16 | $failover->target( "1.2.3.5" ); 17 | 18 | =head1 METHODS 19 | 20 | =over 21 | 22 | =item Hetzner::Robot::Failover->new( $robot, $address ) 23 | 24 | Returns the object reference to the failover address. 25 | 26 | =item Hetzner::Robot::Failover->enumerate( $robot ) 27 | 28 | Returns a list of all failover addresses known to the robot instance. 29 | 30 | =cut 31 | 32 | sub __idkey { return "ip"; } 33 | 34 | =item $failover->address 35 | 36 | Returns the address of a failover object. 37 | 38 | =cut 39 | 40 | sub address { 41 | my ($self) = @_; 42 | return $self->key; 43 | } 44 | 45 | =item $failover->netmask 46 | 47 | Returns the network mask in CIDR notation. 48 | 49 | =cut 50 | 51 | sub netmask { 52 | my ($self) = @_; 53 | return $self->__info->{netmask}; 54 | } 55 | 56 | =item $failover->server 57 | 58 | Returns the L object the address belongs to. 59 | 60 | =cut 61 | 62 | sub server { 63 | my ($self) = @_; 64 | my $addr = $self->__info->{server_ip}; 65 | return $self->robot->server($addr); 66 | } 67 | 68 | =item $failover->target 69 | 70 | =item $failover->target( $new_server ) 71 | 72 | Sets or retrieves the L object the failover 73 | address points to. 74 | 75 | =cut 76 | 77 | sub target { 78 | my ($self, $route) = @_; 79 | if ($route) { 80 | $self->__conf( active_server_ip => $route->address ); 81 | } 82 | my $addr = $self->__info->{active_server_ip}; 83 | return $self->robot->server($addr); 84 | } 85 | 86 | 1; 87 | 88 | =back 89 | -------------------------------------------------------------------------------- /lib/Hetzner/Robot/IP.pm: -------------------------------------------------------------------------------- 1 | package Hetzner::Robot::IP; 2 | use base "Hetzner::Robot::Item::Enumerable"; 3 | use strict; 4 | 5 | =head1 NAME 6 | 7 | Hetzner::Robot:IP - Single addresses assigned to Hetzner servers 8 | 9 | =head1 SYNOPSIS 10 | 11 | my $robot = new Hetzner::Robot( "user", "password" ); 12 | # print all known addresses with their assigned servers 13 | for my $ip ( enumerate Hetzner::Robot::IP( $robot ) ) { 14 | print $ip->address, "\t", $ip->server->address, "\n"; 15 | } 16 | 17 | # print traffic warning limit for a single address 18 | my $addr = new Hetzner::Robot::IP( $robot, "1.2.3.4" ); 19 | print $addr->traffic_hourly, "\n"; 20 | 21 | =head1 METHODS 22 | 23 | =over 24 | 25 | =item Hetzner::Robot::IP->new( $robot, $address ) 26 | 27 | Returns a reference to the IP object representing 28 | the IP address. 29 | 30 | =item Hetzner::Robot::IP->enumerate( $robot ) 31 | 32 | Returns a list containing all IP objects known to 33 | the robot account. 34 | 35 | =cut 36 | 37 | sub __idkey { return "ip"; } 38 | 39 | =item $ip->address 40 | 41 | Returns the IP address of the object. 42 | 43 | =cut 44 | 45 | sub address { 46 | my ($self) = @_; 47 | return $self->key; 48 | } 49 | 50 | =item $ip->server 51 | 52 | Returns a reference to the server object the address is assigned to. 53 | 54 | =cut 55 | 56 | sub server { 57 | my ($self) = @_; 58 | return $self->robot->server($self->__info->{server_ip}); 59 | } 60 | 61 | =item $ip->is_locked 62 | 63 | Indicates whether the address is locked. 64 | 65 | =cut 66 | 67 | sub is_locked { 68 | my ($self) = @_; 69 | return $self->__info->{locked}; 70 | } 71 | 72 | sub __trafficconf { 73 | my ($self, $var, $val) = @_; 74 | if (defined $val) { 75 | return $self->__conf($var => $val)->{$var}; 76 | } else { 77 | return $self->__info->{$var}; 78 | } 79 | } 80 | 81 | =item $ip->traffic_warnings 82 | 83 | =item $ip->traffic_hourly 84 | 85 | =item $ip->traffic_daily 86 | 87 | =item $ip->traffic_monthly 88 | 89 | Set or get values that indicate whether and at which level traffic warnings are 90 | send. 91 | 92 | =cut 93 | 94 | sub traffic_warnings { 95 | return $_[0]->__trafficconf("traffic_warnings", $_[1] ? "true" : "false"); 96 | } 97 | 98 | sub traffic_hourly { 99 | return $_[0]->__trafficconf("traffic_hourly", $_[1]); 100 | } 101 | 102 | sub traffic_daily { 103 | return $_[0]->__trafficconf("traffic_daily", $_[1]); 104 | } 105 | 106 | sub traffic_monthly { 107 | return $_[0]->__trafficconf("traffic_monthly", $_[1]); 108 | } 109 | 110 | 1; 111 | 112 | =back 113 | -------------------------------------------------------------------------------- /lib/Hetzner/Robot/Item.pm: -------------------------------------------------------------------------------- 1 | package Hetzner::Robot::Item; 2 | use strict; 3 | 4 | sub new { 5 | my ($this, $robot, $key) = @_; 6 | my $class = ref($this) || $this; 7 | my $self = { robot => $robot, key => $key }; 8 | bless $self, $class; 9 | } 10 | sub req { 11 | my ($self, @params) = @_; 12 | $self->robot->req(@params); 13 | } 14 | sub robot { 15 | my ($self) = @_; 16 | return $self->{robot}; 17 | } 18 | sub key { 19 | my ($self) = @_; 20 | return $self->{key}; 21 | } 22 | 23 | sub __section { 24 | my ($self) = @_; 25 | # extract section name from class name 26 | my @c = split /::/, ( ref($self) || $self ); 27 | return lc $c[2]; 28 | } 29 | 30 | sub __subsection { 31 | my ($self) = @_; 32 | my @c = split /::/, ( ref($self) || $self ); 33 | return lc $c[3]; 34 | } 35 | 36 | # root item in retrieved data structures 37 | sub __root { 38 | my ($self) = @_; 39 | return $self->__subsection || $self->__section; 40 | } 41 | 42 | sub __url { 43 | my ($self) = @_; 44 | my $url = "/".$self->__section."/".$self->key; 45 | if ($self->__subsection) { 46 | $url .= "/".$self->__subsection; 47 | } 48 | return $url; 49 | } 50 | 51 | sub __info { 52 | my ($self) = @_; 53 | return $self->req("GET", $self->__url)->{$self->__root}; 54 | } 55 | 56 | sub __conf { 57 | my ($self, %vars) = @_; 58 | return $self->req("POST", $self->__url, \%vars)->{$self->__root}; 59 | } 60 | 61 | sub is_valid { 62 | my ($self) = @_; 63 | eval { 64 | $self->__info(); 65 | }; 66 | if ($@) { # Exception! 67 | if(ref($@) eq "Hetzner::Robot::NotFoundException") { 68 | # the item has not been found, so we assume 69 | # the key is invalid 70 | return 0; 71 | } 72 | # any other exception we just pass on 73 | die $@; 74 | } 75 | # No exception? Nice, our object looks valid 76 | return 1; 77 | } 78 | 79 | 1; 80 | -------------------------------------------------------------------------------- /lib/Hetzner/Robot/Item/Enumerable.pm: -------------------------------------------------------------------------------- 1 | package Hetzner::Robot::Item::Enumerable; 2 | use base "Hetzner::Robot::Item"; 3 | use strict; 4 | 5 | # enumerate all instances of an object type 6 | sub enumerate { 7 | my ($this, $robot) = @_; 8 | my $cls = ref($this) || $this; 9 | my $l = $robot->req("GET", "/".$cls->__section); 10 | return map { $cls->new($robot, $_->{$cls->__section}{$cls->__idkey}) } @$l; 11 | } 12 | 13 | # the id item in a returned data structure 14 | sub __idkey { 15 | my ($this) = @_; 16 | my $class = ref($this) || $this; 17 | die "Method __idkey has to be overridden by $class"; 18 | } 19 | 20 | 1; 21 | -------------------------------------------------------------------------------- /lib/Hetzner/Robot/NotFoundException.pm: -------------------------------------------------------------------------------- 1 | package Hetzner::Robot::NotFoundException; 2 | use base "Hetzner::Robot::Exception"; 3 | use strict; 4 | 5 | sub new { 6 | my ($this, $doc) = @_; 7 | my $cls = ref($this) || $this; 8 | my $self = $cls->SUPER::new("Ressource not found"); 9 | $self->{doc} = $doc; 10 | return $self; 11 | } 12 | 13 | sub msg { 14 | my $self = shift; 15 | return $self->SUPER::msg.": ".$self->{doc}; 16 | } 17 | 18 | 1; 19 | -------------------------------------------------------------------------------- /lib/Hetzner/Robot/RDNS.pm: -------------------------------------------------------------------------------- 1 | package Hetzner::Robot::RDNS; 2 | use base "Hetzner::Robot::Item::Enumerable"; 3 | use strict; 4 | 5 | =head1 NAME 6 | 7 | Hetzner::Robot::RDNS - Class representing RDNS entries 8 | 9 | =head1 SYNOPSIS 10 | 11 | use Hetzner::Robot; 12 | use Hetzner::Robot::RDNS; 13 | my $robot = new Hetzner::Robot("user", "password"); 14 | my $entry = new Hetzner::Robot::RDNS($robot, "1.2.3.4"); 15 | # get rdns entry 16 | print $entry->ptr; 17 | # set entry 18 | $entry->ptr("myhost.example.org"); 19 | 20 | =head1 DESCRIPTION 21 | 22 | This class encapsulates access to a rdns object as provided by the 23 | webservice. 24 | 25 | =head1 METHODS 26 | 27 | =over 28 | 29 | =item Hetzner::Robot::RDNS->new( $robot, $address ) 30 | 31 | Instantiates a new RDNS object by specifying the Hetzner::Robot object 32 | and the IP address. 33 | 34 | =item Hetzner::Robot::RDNS->enumerate( $robot ) 35 | 36 | Returns a list of all reverse DNS entries known to the L 37 | account. 38 | 39 | =item $entry->address 40 | 41 | Returns the IP address of the entry. 42 | 43 | =cut 44 | 45 | sub address { 46 | my ($self) = @_; 47 | return $self->key; 48 | } 49 | 50 | # overload __info method 51 | sub __info { 52 | my ($self) = @_; 53 | my $res = { ip => $self->address, ptr => undef }; 54 | eval { 55 | # try to retrieve the real results 56 | $res = $self->SUPER::__info(@_); 57 | }; 58 | if ($@ && ref($@) ne "Hetzner::Robot::NotFoundException") { 59 | # in case of this exception, the RDNS entry 60 | # probably has not been created yet, so we 61 | # return an empty "dummy" result; 62 | # otherwise, just re-die the exception 63 | die $@ 64 | } 65 | return $res; 66 | } 67 | 68 | sub __idkey { return "ip"; } 69 | 70 | =item $entry->ptr 71 | 72 | =item $entry->ptr( $hostname ) 73 | 74 | Gets or sets the reverse entry. 75 | 76 | =cut 77 | 78 | sub ptr { 79 | my ($self, $val) = @_; 80 | if (defined $val) { 81 | $self->__conf( ptr => $val ); 82 | } 83 | return $self->__info->{ptr}; 84 | } 85 | 86 | =item $entry->del 87 | 88 | Delete the reverse entry. 89 | 90 | =cut 91 | 92 | sub del { 93 | my ($self) = @_; 94 | return $self->req("DELETE", $self->__url); 95 | } 96 | 1; 97 | 98 | =back 99 | -------------------------------------------------------------------------------- /lib/Hetzner/Robot/Reset.pm: -------------------------------------------------------------------------------- 1 | package Hetzner::Robot::Reset; 2 | use base "Hetzner::Robot::Item::Enumerable"; 3 | use strict; 4 | 5 | =head1 NAME 6 | 7 | Hetzner::Robot::Reset - Trigger resets of Hetzner servers 8 | 9 | =head1 SYNOPSIS 10 | 11 | my $robot = new Hetzner::Robot( "user", "password" ); 12 | my $reset = new Hetzner::Robot::Reset( $robot, "1.2.3.4" ); 13 | # trigger a software reset 14 | $reset->execute( "sw" ); 15 | 16 | # alternative path to trigger hardware reset 17 | $robot->server( "1.2.3.4" )->reset->execute( "hw" ); 18 | 19 | =head1 METHODS 20 | 21 | =over 22 | 23 | =item Hetzner::Robot::Reset->new( $robot, $address ) 24 | 25 | Returns a handle to the resetter for the specified server. 26 | 27 | =item Hetzner::Robot::Reset->enumerate( $robot ) 28 | 29 | Returns a list of all known resetters. 30 | 31 | =cut 32 | 33 | sub __idkey { return "server_ip"; } 34 | 35 | =item $reset->available_methods 36 | 37 | Returns a list of known reset methods for the server. 38 | 39 | =cut 40 | 41 | sub available_methods { 42 | my ($self) = @_; 43 | return $self->__info->{"type"}; 44 | } 45 | 46 | =item $reset->execute( $method ) 47 | 48 | Triggers a reset using the supplied method; if no method 49 | is specified, "sw" is assumed. 50 | 51 | =cut 52 | 53 | sub execute { 54 | my ($self, $method) = @_; 55 | $method = "sw" unless $method; 56 | return $self->__conf(type=>$method); 57 | } 58 | 1; 59 | 60 | =back 61 | -------------------------------------------------------------------------------- /lib/Hetzner/Robot/Server.pm: -------------------------------------------------------------------------------- 1 | package Hetzner::Robot::Server; 2 | use base "Hetzner::Robot::Item::Enumerable"; 3 | use strict; 4 | 5 | =head1 NAME 6 | 7 | Hetzner::Robot::Server - Representation of a single server 8 | 9 | =head1 SYNOPSIS 10 | 11 | use Hetzner::Robot; 12 | use Hetzner::Robot::Server; 13 | my $robot = new Hetzner::Robot("user", "password"); 14 | my $server = new Hetzner::Robot::Server($robot, "1.2.3.4"); 15 | print $server->product; 16 | 17 | =head1 DESCRIPTION 18 | 19 | C encapsulates access to a server object as 20 | provided by the webservice. 21 | 22 | =cut 23 | 24 | use Hetzner::Robot::WOL; 25 | use Hetzner::Robot::Reset; 26 | use Hetzner::Robot::Boot::Rescue; 27 | use Hetzner::Robot::Subnet; 28 | use Hetzner::Robot::IP; 29 | 30 | sub __idkey { return "server_ip"; } 31 | 32 | =head1 METHODS 33 | 34 | =over 35 | 36 | =item Hetzner::Robot::Server->new( $robot, $address ) 37 | 38 | Instantiates a new object by specifying the 39 | L object and the server main address. 40 | 41 | =item Hetzner::Robot::Server->enumerate( $robot ) 42 | 43 | Returns a list of all server objects known to the L 44 | account. 45 | 46 | =item $server->address 47 | 48 | Returns the primary address of the server. 49 | 50 | =cut 51 | 52 | sub address { 53 | my ($self) = @_; 54 | return $self->key; 55 | } 56 | 57 | =item $server->name 58 | 59 | =item $server->name("foo") 60 | 61 | Returns or sets the custom server nickname. 62 | 63 | =cut 64 | 65 | sub name { 66 | my ($self, $nick) = @_; 67 | if (defined $nick) { 68 | $self->__conf( "server_name" => $nick ); 69 | } 70 | return $self->__info->{server_name}; 71 | } 72 | 73 | =item $server->wol 74 | 75 | =item $server->reset 76 | 77 | =item $server->rescue 78 | 79 | Returns the WOL/Reset/Rescue controller object assigned to the server. 80 | 81 | =cut 82 | 83 | sub wol { 84 | my ($self) = @_; 85 | return new Hetzner::Robot::WOL($self->robot, $self->key); 86 | } 87 | 88 | sub reset { 89 | my ($self) = @_; 90 | return new Hetzner::Robot::Reset($self->robot, $self->key); 91 | } 92 | 93 | sub rescue { 94 | my ($self) = @_; 95 | return new Hetzner::Robot::Boot::Rescue($self->robot, $self->key); 96 | } 97 | 98 | =item $server->addresses 99 | 100 | =item $server->subnets 101 | 102 | Returns a list of IP addresses (L) or subnets 103 | (L) assigned to the server. 104 | 105 | =cut 106 | 107 | sub addresses { 108 | my ($self) = @_; 109 | return map { Hetzner::Robot::IP->new($self->robot, $_) } @{$self->__info()->{ip}}; 110 | } 111 | 112 | sub subnets { 113 | my ($self) = @_; 114 | return map { Hetzner::Robot::Subnet->new($self->robot, $_->{ip}) } @{$self->__info()->{subnet}}; 115 | } 116 | 117 | =item $server->product 118 | 119 | =item $server->datacenter 120 | 121 | =item $server->paid_until 122 | 123 | =item $server->throtteled 124 | 125 | =item $server->throtteled 126 | 127 | Theses methods return various information about the server. 128 | 129 | =cut 130 | 131 | sub product { return shift->__info()->{product}; } 132 | sub datacenter { return shift->__info()->{dc}; } 133 | sub paid_until { return shift->__info()->{paid_until}; } 134 | sub throtteled { return shift->__info()->{throtteled}; } 135 | sub included_traffic { return shift->__info()->{traffic}; } 136 | 137 | 1; 138 | 139 | =back 140 | 141 | =head1 SEE ALSO 142 | 143 | L, 144 | L, 145 | L, 146 | L, 147 | L, 148 | L 149 | -------------------------------------------------------------------------------- /lib/Hetzner/Robot/Subnet.pm: -------------------------------------------------------------------------------- 1 | package Hetzner::Robot::Subnet; 2 | use base "Hetzner::Robot::IP"; 3 | use strict; 4 | 5 | =head1 NAME 6 | 7 | Hetzner::Robot::Subnet - Subnets assigned to Hetzner servers 8 | 9 | =head1 SYNOPSIS 10 | 11 | my $robot = new Hetzner::Robot( "user", "password" ); 12 | my $subnet = new Hetzner::Robot::Subnet( $robot, "10.5.2.0" ); 13 | # deactivate traffic warnings 14 | $subnet->traffic_warnings( 0 ); 15 | 16 | =head1 DESCRIPTION 17 | 18 | C is a subclass of C, thus 19 | inheriting all of its methods and constructors. 20 | 21 | =cut 22 | 23 | use Hetzner::Robot::Failover; 24 | 25 | =head1 METHODS 26 | 27 | Additionally to the methods defined in C, two additional 28 | methods are added by this class: 29 | 30 | =over 31 | 32 | =item $subnet->netmask 33 | 34 | Returns the network mask in CIDR notation. 35 | 36 | =cut 37 | 38 | sub netmask { 39 | my ($self) = @_; 40 | return $self->__info->{mask}; 41 | } 42 | 43 | =item $subnet->failover 44 | 45 | Returns the C object associated if the network 46 | is a failover address; otherwise, it returns a false value. 47 | 48 | =cut 49 | 50 | sub failover { 51 | my ($self) = @_; 52 | if ($self->__info->{failover}) { 53 | return Hetzner::Robot::Failover->new($self->address); 54 | } else { 55 | return undef; 56 | } 57 | } 58 | 59 | 1; 60 | 61 | =back 62 | 63 | =head1 SEE ALSO 64 | 65 | L, 66 | L 67 | -------------------------------------------------------------------------------- /lib/Hetzner/Robot/WOL.pm: -------------------------------------------------------------------------------- 1 | package Hetzner::Robot::WOL; 2 | use base "Hetzner::Robot::Item"; 3 | use strict; 4 | 5 | =head1 NAME 6 | 7 | Hetzner::Robot::WOL - Wake-On-Lan trigger for Hetzner servers 8 | 9 | =head1 SYNOPSIS 10 | 11 | my $robot = new Hetzner::Robot("user", "password"); 12 | my $wol = new Hetzner::Robot::WOL( $robot, "1.2.3.4"); 13 | # send wakup signal to server 1.2.3.4 14 | $wol->execute(); 15 | 16 | =head1 METHODS 17 | 18 | =over 19 | 20 | =item Hetzner::Robot::WOL->new( $robot, $address ); 21 | 22 | Returns a WOL object for the server with the supplied address. 23 | 24 | =item $wol->execute() 25 | 26 | Triggers the wakeup signal for the server. 27 | 28 | =back 29 | 30 | =cut 31 | 32 | sub execute { 33 | my ($self) = @_; 34 | return $self->__conf(); 35 | } 36 | 1; 37 | --------------------------------------------------------------------------------