PageRenderTime 45ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Rex/Commands/Cloud.pm

http://github.com/krimdomu/Rex
Perl | 598 lines | 514 code | 77 blank | 7 comment | 11 complexity | 0e7e8a605bc4277989ecc7e0fec91641 MD5 | raw file
Possible License(s): GPL-3.0, Apache-2.0
  1. #
  2. # (c) Jan Gehring <jan.gehring@gmail.com>
  3. #
  4. # vim: set ts=2 sw=2 tw=0:
  5. # vim: set expandtab:
  6. =head1 NAME
  7. Rex::Commands::Cloud - Cloud Management Commands
  8. =head1 DESCRIPTION
  9. With this Module you can manage different Cloud services. Currently it supports Amazon EC2, Jiffybox and OpenStack.
  10. Version <= 1.0: All these functions will not be reported.
  11. =head1 SYNOPSIS
  12. use Rex::Commands::Cloud;
  13. cloud_service "Amazon";
  14. cloud_auth "your-access-key", "your-private-access-key";
  15. cloud_region "ec2.eu-west-1.amazonaws.com";
  16. task "list", sub {
  17. print Dumper cloud_instance_list;
  18. print Dumper cloud_volume_list;
  19. };
  20. task "create", sub {
  21. my $vol_id = cloud_volume create => { size => 1, zone => "eu-west-1a", };
  22. cloud_instance create => {
  23. image_id => "ami-xxxxxxx",
  24. name => "test01",
  25. key => "my-key",
  26. volume => $vol_id,
  27. zone => "eu-west-1a",
  28. };
  29. };
  30. task "destroy", sub {
  31. cloud_volume detach => "vol-xxxxxxx";
  32. cloud_volume delete => "vol-xxxxxxx";
  33. cloud_instance terminate => "i-xxxxxxx";
  34. };
  35. =head1 EXPORTED FUNCTIONS
  36. =cut
  37. package Rex::Commands::Cloud;
  38. use strict;
  39. use warnings;
  40. # VERSION
  41. require Rex::Exporter;
  42. use base qw(Rex::Exporter);
  43. use vars qw(@EXPORT $cloud_service $cloud_region @cloud_auth);
  44. use Rex::Logger;
  45. use Rex::Config;
  46. use Rex::Cloud;
  47. use Rex::Group::Entry::Server;
  48. @EXPORT = qw(cloud_instance cloud_volume cloud_network
  49. cloud_instance_list cloud_volume_list cloud_network_list
  50. cloud_service cloud_auth cloud_region
  51. get_cloud_instances_as_group get_cloud_regions get_cloud_availability_zones
  52. get_cloud_plans
  53. get_cloud_operating_systems
  54. cloud_image_list
  55. cloud_object
  56. get_cloud_floating_ip
  57. cloud_upload_key);
  58. Rex::Config->register_set_handler(
  59. "cloud" => sub {
  60. my ( $name, @options ) = @_;
  61. my $sub_name = "cloud_$name";
  62. if ( $name eq "service" ) {
  63. cloud_service(@options);
  64. }
  65. if ( $name eq "auth" ) {
  66. cloud_auth(@options);
  67. }
  68. if ( $name eq "region" ) {
  69. cloud_region(@options);
  70. }
  71. }
  72. );
  73. =head2 cloud_service($cloud_service)
  74. Define which cloud service to use.
  75. =over 4
  76. =item Services
  77. =over 4
  78. =item Amazon
  79. =item Jiffybox
  80. =item OpenStack
  81. =back
  82. =back
  83. =cut
  84. sub cloud_service {
  85. ($cloud_service) = @_;
  86. # set retry counter to a higher value
  87. if ( Rex::Config->get_max_connect_fails() < 5 ) {
  88. Rex::Config->set_max_connect_fails(15);
  89. }
  90. }
  91. =head2 cloud_auth($param1, $param2, ...)
  92. Set the authentication for the cloudservice.
  93. For example for Amazon it is:
  94. cloud_auth($access_key, $secret_access_key);
  95. For JiffyBox:
  96. cloud_auth($auth_key);
  97. For OpenStack:
  98. cloud_auth(
  99. tenant_name => 'tenant',
  100. username => 'user',
  101. password => 'password',
  102. );
  103. =cut
  104. sub cloud_auth {
  105. @cloud_auth = @_;
  106. }
  107. =head2 cloud_region($region)
  108. Set the cloud region.
  109. =cut
  110. sub cloud_region {
  111. ($cloud_region) = @_;
  112. }
  113. =head2 cloud_instance_list
  114. Get all instances of a cloud service.
  115. task "list", sub {
  116. for my $instance (cloud_instance_list()) {
  117. say "Arch : " . $instance->{"architecture"};
  118. say "IP : " . $instance->{"ip"};
  119. say "ID : " . $instance->{"id"};
  120. say "State : " . $instance->{"state"};
  121. }
  122. };
  123. There are some parameters for this function that can change the gathering of ip addresses for some cloud providers (like OpenStack).
  124. task "list", sub {
  125. my @instances = cloud_instance_list
  126. private_network => 'private',
  127. public_network => 'public',
  128. public_ip_type => 'floating',
  129. private_ip_type => 'fixed';
  130. };
  131. =cut
  132. sub cloud_instance_list {
  133. return cloud_object()->list_instances(@_);
  134. }
  135. =head2 cloud_volume_list
  136. Get all volumes of a cloud service.
  137. task "list-volumes", sub {
  138. for my $volume (cloud_volume_list()) {
  139. say "ID : " . $volume->{"id"};
  140. say "Zone : " . $volume->{"zone"};
  141. say "State : " . $volume->{"state"};
  142. say "Attached : " . $volume->{"attached_to"};
  143. }
  144. };
  145. =cut
  146. sub cloud_volume_list {
  147. return cloud_object()->list_volumes();
  148. }
  149. =head2 cloud_network_list
  150. Get all networks of a cloud service.
  151. task "network-list", sub {
  152. for my $network (cloud_network_list()) {
  153. say "network : " . $network->{network};
  154. say "name : " . $network->{name};
  155. say "id : " . $network->{id};
  156. }
  157. };
  158. =cut
  159. sub cloud_network_list {
  160. return cloud_object()->list_networks();
  161. }
  162. =head2 cloud_image_list
  163. Get a list of all available cloud images.
  164. =cut
  165. sub cloud_image_list {
  166. return cloud_object()->list_images();
  167. }
  168. =head2 cloud_upload_key
  169. Upload public SSH key to cloud provider
  170. private_key '~/.ssh/mykey
  171. public_key '~/.ssh/mykey.pub';
  172. task "cloudprovider", sub {
  173. cloud_upload_key;
  174. cloud_instance create => {
  175. ...
  176. };
  177. };
  178. =cut
  179. sub cloud_upload_key {
  180. return cloud_object()->upload_key();
  181. }
  182. =head2 get_cloud_instances_as_group
  183. Get a list of all running instances of a cloud service. This can be used for a I<group> definition.
  184. group fe => "fe01", "fe02", "fe03";
  185. group ec2 => get_cloud_instances_as_group();
  186. =cut
  187. sub get_cloud_instances_as_group {
  188. # return funcRef
  189. return sub {
  190. my @list = cloud_object()->list_running_instances();
  191. my @ret;
  192. for my $instance (@list) {
  193. push( @ret, Rex::Group::Entry::Server->new( name => $instance->{"ip"} ) );
  194. }
  195. return @ret;
  196. };
  197. }
  198. =head2 cloud_instance($action, $data)
  199. This function controls all aspects of a cloud instance.
  200. =cut
  201. sub cloud_instance {
  202. my ( $action, $data ) = @_;
  203. my $cloud = cloud_object();
  204. if ( $action eq "list" ) {
  205. return $cloud->list_running_instances();
  206. }
  207. =head2 create
  208. Create a new instance.
  209. cloud_instance create => {
  210. image_id => "ami-xxxxxx",
  211. key => "ssh-key",
  212. name => "fe-ec2-01", # name is not necessary
  213. volume => "vol-yyyyy", # volume is not necessary
  214. zone => "eu-west-1a", # zone is not necessary
  215. floating_ip => "89.39.38.160" # floating_ip is not necessary
  216. };
  217. =cut
  218. elsif ( $action eq "create" ) {
  219. my %data_hash = (
  220. # image_id => $data->{"image_id"},
  221. # name => $data->{"name"} || undef,
  222. # key => $data->{"key"} || undef,
  223. # zone => $data->{"zone"} || undef,
  224. # volume => $data->{"volume"} || undef,
  225. # password => $data->{"password"} || undef,
  226. # plan_id => $data->{"plan_id"} || undef,
  227. # type => $data->{"type"} || undef,
  228. # security_group => $data->{"security_group"} || undef,
  229. %{$data},
  230. );
  231. $cloud->run_instance(%data_hash);
  232. }
  233. =head2 start
  234. Start an existing instance
  235. cloud_instance start => "instance-id";
  236. =cut
  237. elsif ( $action eq "start" ) {
  238. $cloud->start_instance( instance_id => $data );
  239. }
  240. =head2 stop
  241. Stop an existing instance
  242. cloud_instance stop => "instance-id";
  243. =cut
  244. elsif ( $action eq "stop" ) {
  245. $cloud->stop_instance( instance_id => $data );
  246. }
  247. =head2 terminate
  248. Terminate an instance. This will destroy all data and remove the instance.
  249. cloud_instance terminate => "i-zzzzzzz";
  250. =cut
  251. elsif ( $action eq "terminate" ) {
  252. $cloud->terminate_instance( instance_id => $data );
  253. }
  254. }
  255. =head2 get_cloud_regions
  256. Returns all regions as an array.
  257. =cut
  258. sub get_cloud_regions {
  259. return cloud_object()->get_regions;
  260. }
  261. =head2 cloud_volume($action , $data)
  262. This function controlls all aspects of a cloud volume.
  263. =cut
  264. sub cloud_volume {
  265. my ( $action, @_data ) = @_;
  266. my $data;
  267. if ( @_data == 1 ) {
  268. if ( ref $_data[0] ) {
  269. $data = $_data[0];
  270. }
  271. else {
  272. $data = { id => $_data[0] };
  273. }
  274. }
  275. else {
  276. $data = { "id", @_data };
  277. }
  278. my $cloud = cloud_object();
  279. =head2 create
  280. Create a new volume. Size is in Gigabytes.
  281. task "create-vol", sub {
  282. my $vol_id = cloud_volume create => { size => 1, zone => "eu-west-1a", };
  283. };
  284. =cut
  285. if ( $action eq "create" ) {
  286. $cloud->create_volume(
  287. size => $data->{"size"} || 1,
  288. %{$data},
  289. );
  290. }
  291. =head2 attach
  292. Attach a volume to an instance.
  293. task "attach-vol", sub {
  294. cloud_volume attach => "vol-xxxxxx", to => "server-id";
  295. };
  296. =cut
  297. elsif ( $action eq "attach" ) {
  298. my $vol_id = $data->{id};
  299. my $srv_id = $data->{to};
  300. $cloud->attach_volume(
  301. volume_id => $vol_id,
  302. server_id => $srv_id,
  303. device_name => $data->{device}
  304. );
  305. }
  306. =head2 detach
  307. Detach a volume from an instance.
  308. task "detach-vol", sub {
  309. cloud_volume detach => "vol-xxxxxx", from => "server-id";
  310. };
  311. =cut
  312. elsif ( $action eq "detach" ) {
  313. my $vol_id = $data->{id};
  314. my $srv_id = $data->{from};
  315. $cloud->detach_volume(
  316. volume_id => $vol_id,
  317. server_id => $srv_id,
  318. attach_id => $data->{attach_id}
  319. );
  320. }
  321. =head2 delete
  322. Delete a volume. This will destroy all data.
  323. task "delete-vol", sub {
  324. cloud_volume delete => "vol-xxxxxx";
  325. };
  326. =cut
  327. elsif ( $action eq "delete" ) {
  328. $cloud->delete_volume( volume_id => $data->{id} );
  329. }
  330. elsif ( $action eq "list" ) {
  331. return $cloud->list_volumes();
  332. }
  333. }
  334. =head2 get_cloud_floating_ip
  335. Returns first available floating IP
  336. task "get_floating_ip", sub {
  337. my $ip = get_cloud_floating_ip;
  338. my $instance = cloud_instance create => {
  339. image_id => 'edffd57d-82bf-4ffe-b9e8-af22563741bf',
  340. name => 'instance1',
  341. plan_id => 17,
  342. floating_ip => $ip
  343. };
  344. };
  345. =cut
  346. sub get_cloud_floating_ip {
  347. return cloud_object()->get_floating_ip;
  348. }
  349. =head2 cloud_network
  350. =cut
  351. sub cloud_network {
  352. my ( $action, $data ) = @_;
  353. my $cloud = cloud_object();
  354. =head2 create
  355. Create a new network.
  356. task "create-net", sub {
  357. my $net_id = cloud_network create => { cidr => '192.168.0.0/24', name => "mynetwork", };
  358. };
  359. =cut
  360. if ( $action eq "create" ) {
  361. $cloud->create_network( %{$data} );
  362. }
  363. =head2 delete
  364. Delete a network.
  365. task "delete-net", sub {
  366. cloud_network delete => '18a4ccf8-f14a-a10d-1af4-4ac7fee08a81';
  367. };
  368. =cut
  369. elsif ( $action eq "delete" ) {
  370. $cloud->delete_network($data);
  371. }
  372. }
  373. =head2 get_cloud_availability_zones
  374. Returns all availability zones of a cloud services. If available.
  375. task "get-zones", sub {
  376. print Dumper get_cloud_availability_zones;
  377. };
  378. =cut
  379. sub get_cloud_availability_zones {
  380. return cloud_object()->get_availability_zones();
  381. }
  382. =head2 get_cloud_plans
  383. Retrieve information of the available cloud plans. If supported.
  384. =cut
  385. sub get_cloud_plans {
  386. return cloud_object()->list_plans;
  387. }
  388. =head2 get_cloud_operating_systems
  389. Retrieve information of the available cloud plans. If supported.
  390. =cut
  391. sub get_cloud_operating_systems {
  392. return cloud_object()->list_operating_systems;
  393. }
  394. =head2 cloud_object
  395. Returns the cloud object itself.
  396. =cut
  397. sub cloud_object {
  398. my $cloud = get_cloud_service($cloud_service);
  399. $cloud->set_auth(@cloud_auth);
  400. $cloud->set_endpoint($cloud_region);
  401. return $cloud;
  402. }
  403. 1;