#
# Module: walk_op_mode.pl
# 
# **** License ****
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
# 
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
# 
# This code was originally developed by Vyatta, Inc.
# Portions created by Vyatta are Copyright (C) 2009-2010 Vyatta, Inc.
# All Rights Reserved.
# 
# Author: Stig Thormodsrud
# Date: August 2010
# Description: Script to use rest api to walk op mode commands.
# 
# **** End License ****
#

use strict;
use warnings;

use lib "/opt/vyatta/share/perl5/";

use POSIX;
use JSON;
use MIME::Base64;
use Getopt::Long;
use Data::Dumper;
use LWP::UserAgent;
use HTTP::Request;

my $target   = '127.0.0.1';
my $base_url = "https://$target/rest";
my $user     = "vyatta";
my $passwd   = "vyatta";
my $ua;

my $op_cmds_run     = 0;
my $op_cmds_skipped = 0;
my $op_cmds_stopped = 0;

sub read_op_output {
    my ($location) = @_;
    
    my $url = "https://$target/$location";
    my ($response, $output, $count);
    $count = 0;
    do {
        $response = $ua->get($url);
        if ($response->is_success) {
            $output = $response->content;
            $output =~ s/[\x00-\x08\x0B-\x1F\x7F-\xFF]//g;
            print $output;
            if ($output eq '') {
                if ($count++ > 10) {
                    print "No new output - Stopping\n";
                    $op_cmds_stopped++;
                    my $request = HTTP::Request->new(DELETE => $url);
                    $response = $ua->request($request);
                    return;
                }
            }
        } else {
            if ($response->code != 410) {
                print "Failed to GET [$url]: ", $response->status_line;
                return;
            }
        }
    } while ($response->code != 410);
}

sub run_op_cmd {
    my ($path) = @_;
    
    print "running [$path]\n";
    my $url = "$base_url/op/$path";
    my $response = $ua->post($url);
    if ($response->is_success) {
        my $location = $response->header('Location');
        if (defined $location) {
            read_op_output($location);
            print "\n";
            $op_cmds_run++;
        } else {
            print "No location found\n";
        }
    } else {
        print "Failed to GET [$url]: ", $response->status_line;        
    }
}

sub get_op_children {
    my ($path) = @_;

    my @empty = ();
    my $url  = "$base_url/op/$path/";
    my $response = $ua->get($url);
    if ($response->is_error) {
        return @empty if $response->code == 404;
        print "Failed to GET [$url]: ", $response->status_line;
        return @empty;
    }
     
    if ($response->header('content-type') eq 'application/json') {
        my $perl_scalar = decode_json($response->content);
        my $children = $perl_scalar->{children};
        my $action = $perl_scalar->{action};
        if (defined $action and $action eq "true") {
            if ($path =~ /\*/) {
                print "skipping [$path]\n\n";
                $op_cmds_skipped++;
            } else {
                run_op_cmd($path);
            }
        }
        return @$children if defined $children;
        return @empty;
    }
}

sub get_op_cmds {
    my ($path) = @_;

    my @outs = get_op_children($path);
    foreach my $out (@outs) {
        get_op_cmds("$path/$out");
    }
}  


# main

$target = $ARGV[0] if defined $ARGV[0];
$user   = $ARGV[1] if defined $ARGV[1];
$passwd = $ARGV[2] if defined $ARGV[2];
$base_url = "https://$target/rest";

print "target [$target] [$user:$passwd]\n\n";

$ua = LWP::UserAgent->new;
my $auth = encode_base64("$user:$passwd");
$ua->default_header('content-lenght' => 0);
$ua->default_header("authorization" => "Basic $auth");

get_op_cmds('show');   # do the real work

print "\nTotals:\n";
print   "=======\n";
print "Ran    : $op_cmds_run\n";
print "Skipped: $op_cmds_skipped\n";
print "Stopped: $op_cmds_stopped\n\n";

if ($op_cmds_run) {
    print "Check for left over processes\n";
    my $url = "$base_url/op";
    my $response = $ua->get($url);
    if ($response->is_success) {
        my $content = $response->content;
        if ($content ne '') {
            print $response->content;
        } else {
            print "No left over processes\n";
        }
    } else {
        print "Failed to GET [$url]: ", $response->status_line;        
    }
}

exit 0;
