API-PureStorage

 view release on metacpan or  search on metacpan

lib/API/PureStorage.pm  view on Meta::CPAN

package API::PureStorage;

use Data::Dumper;
use REST::Client;
use JSON;
use Net::SSL;

use warnings;
use strict;

$API::PureStorage::VERSION = '0.03';

our %ENV;
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;

my $debug = 0;

sub new {
    my $class = shift @_;
    my $self = {
        cookie_file => '/tmp/cookies.txt',
        host => $_[0],
        token => $_[1]
    };
    bless $self, $class;

    my $client = REST::Client->new( follow => 1 );
    $client->setHost('https://'.$self->{host});

    $client->addHeader('Content-Type', 'application/json');

    $client->getUseragent()->cookie_jar({ file => $self->{cookie_file} });
    $client->getUseragent()->ssl_opts(verify_hostname => 0);

    $self->{client} = $client;

    # Check API compatibility

    my @versions = $self->version();

    my %api_versions;
    for my $version (@versions) {
        $api_versions{$version}++;
    }

    my $api_version = $api_versions{'1.4'} ? '1.4' :
                      $api_versions{'1.3'} ? '1.3' :
                      $api_versions{'1.1'} ? '1.1' :
                      $api_versions{'1.0'} ? '1.0' :
                      undef;

    unless ( $api_version ) {
      die "API version 1.3 or 1.4 is not supported by host: $self->{host}\n";
    }

    $self->{api_version} = $api_version;

    ### Set the Session Cookie

    my $ret = $self->_api_post("/api/$api_version/auth/session", { api_token => $self->{token} });

    return $self;
}

sub DESTROY {
  my $self = shift @_;
  my $ret = $self->{client}->DELETE("/api/$self->{api_version}/auth/session") if defined $self->{api_version};
  unlink $self->{cookie_file};
}

### Methods

sub array_info {
    my $self = shift @_;
    my $ref = $self->_api_get("/api/$self->{api_version}/array?space=true");
    return wantarray ? @$ref : $ref;
}

sub volume_detail {
    my $self = shift @_;
    my $name = shift @_;
    my $ref = $self->_api_get("/api/$self->{api_version}/volume/".$name);
    return wantarray ? @$ref : $ref;
}

sub volume_info {
    my $self = shift @_;
    my $ref = $self->_api_get("/api/$self->{api_version}/volume?space=true");
    return wantarray ? @$ref : $ref;
}

sub version {
    my $self = shift @_;
    my $ref = $self->_api_get('/api/api_version');
    return wantarray ? @{$ref->{version}} : $ref->{version};
}

### Subs

sub _api_get {
    my $self = shift @_;
    my $url = shift @_;
    my $ret = $self->{client}->GET($url);
    my $num = $ret->responseCode();
    my $con = $ret->responseContent();
    if ( $num == 500 ) {
        die "API returned error 500 for '$url' - $con\n";
    }
    if ( $num != 200 ) {
        die "API returned code $num for URL '$url'\n";
    }
    print 'DEBUG: GET ', $url, ' -> ', $num, ":\n", Dumper(from_json($con)), "\n" if $debug;
    return from_json($con);
}

sub _api_post {
    my $self = shift @_;
    my $url = shift @_;
    my $data = shift @_;
    my $ret = $self->{client}->POST($url, to_json($data));
    my $num = $ret->responseCode();
    my $con = $ret->responseContent();
    if ( $num == 500 ) {
        die "API returned error 500 for '$url' - $con\n";
    }
    if ( $num != 200 ) {
        die "API returned code $num for URL '$url'\n";
    }
    print 'DEBUG: POST ', $url, ' -> ', $num, ":\n", Dumper(from_json($con)), "\n" if $debug;
    return from_json($con);
}

1;
__END__
=head1 NAME

API::PureStorage - Interacting with Pure Storage devices

=head1 SYNOPSIS

  my $pure = new API::PureStorage ($host, $api_token);

  my $info = $pure->array_info();
  my $percent = sprintf('%0.2f', (100 * $info->{total} / $info->{capacity}));

  print "The array $host is currently $percent full\n";

  print "\nVolumes on host $host:\n";

  my $vol_info = $pure->volume_info();
  for my $vol (sort { lc($a->{name}) cmp lc($b->{name}) } @$vol_info) {
    my $detail = $pure->volume_detail($vol->{name});
    print join("\t", $detail->{name}, $detail->{serial}, $detail->{created}), "\n";
  }

=head1 DESCRIPTION

This module is a wrapper around the Pure Storage API for their devices.

It currently supports API v1.4 and earlier. It supports a limited set of
the available API commands: basic reading of volume and array information.

=head1 METHODS

=head2 array_info()

    my %volume_info = $pure->volume_info()
    my $volume_info_ref = $pure->volume_info()

Returns a hash or hasref (depending on requested context) of general array
information, including space usage.

=head3 Hash data reference:

* hostname - the configured hostname of the system

* total_reduction - The current overall data reduction multiple of the array. IE: A "2" here means "2:1" reduction.

* data_reduction - The reduction multiple of just data partitions.

Array-wide space usage info:

* volumes - bytes in use by active volume data

* shared_space - bytes recognized in use between multiple copies, volumes, snapshots, etc

* snapshots - bytes in use by snapshots

* system - bytes in use by system overhead. This can include recently allocated bytes



( run in 0.802 second using v1.01-cache-2.11-cpan-0bd6704ced7 )