Abort power setup if setting gainloss fails
[transportpce.git] / debug_tools / netconf_terminal.pl
1 #!/usr/bin/env perl
2 ##############################################################################
3 #Copyright (c) 2017 Orange, Inc. and others.  All rights reserved.
4 #
5 # This program and the accompanying materials are made available under the
6 # terms of the Eclipse Public License v1.0 which accompanies this distribution,
7 # and is available at http://www.eclipse.org/legal/epl-v10.html
8 ##############################################################################
9 #
10 # debian dependencies: apt-get install libnet-openssh-perl libio-pty-perl
11 #
12
13 use strict;
14 use warnings;
15
16 #use diagnostics;  #uncomment this line for more details when encountering warnings
17 use Net::OpenSSH;
18 use FileHandle;
19 use Getopt::Long qw(:config no_ignore_case bundling);
20
21 my ( $host, $help, $usage, $capabilities, $login, $password, $kidpid,
22     $hello_message );
23
24 GetOptions(
25     "h|help"           => \$help,
26     "C|capabilities=s" => \$capabilities
27 );
28 $usage = "
29 USAGE: netconf_terminal.pl [-h|--help] [-C|--capabilities <custom_hello_file.xml>] <[login[:password]@]host[:port]> [login] [password]
30
31 Simple netconf terminal client that can be used as an alternative to 'openssh [-p port] <[login@]host> -s netconf'.
32 The main difference is the built-in handshake phase with hello capabilties that can be loaded from an external file.
33 This is particularly useful to avoid timeouts.
34
35 OPTIONS :
36
37         -C or --capabilities     use the given file to advertise a hello message with customized capabilities
38         -h or --help             print this help
39
40 ";
41
42 if ($help) {
43     print $usage;
44     exit(0);
45 }
46
47 unless ( @ARGV >= 1 ) {
48     print $usage;
49     exit(0);
50 }
51
52 ( $host, $login, $password ) = @ARGV;
53
54 #netconf default port is no 22 but 830
55 if ( $host !~ /:[0-9]+$/ ) {
56     $host .= ':830';
57 }
58
59 my $connection_string = $host;
60 if ($password) {
61     $connection_string = $login . ":" . $password . "@" . $connection_string;
62 }
63 elsif ($login) {
64     $connection_string = $login . "@" . $connection_string;
65 }
66
67 #retrieving hello custom file if any
68 if ( defined($capabilities) ) {
69     open( CAPABILITIES, '<', $capabilities )
70       or die("can not open $capabilities");
71     while (<CAPABILITIES>) {
72         $hello_message .= $_;
73     }
74     chop $hello_message;    # removing EOF
75     $hello_message .= "\n]]>]]>\n";
76     close(CAPABILITIES);
77 }
78
79 #otherwise using a basic hello message
80 #EXI extension is not advertised by default since difficult to handle manually
81 else {
82     $hello_message = '<?xml version="1.0" encoding="utf-8"?>
83 <hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
84 <capabilities>
85 <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&amp;revision=2010-10-04</capability>
86 <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-notifications?module=ietf-netconf-notifications&amp;revision=2012-02-06</capability>
87 <capability>urn:ietf:params:xml:ns:netconf:base:1.0?module=ietf-netconf&amp;revision=2011-06-01</capability>
88 <capability>urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&amp;revision=2013-07-15</capability>
89 <capability>urn:ietf:params:netconf:capability:candidate:1.0</capability>
90 <capability>urn:ietf:params:xml:ns:netconf:notification:1.0?module=notifications&amp;revision=2008-07-14</capability>
91 <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring-extension?module=ietf-netconf-monitoring-extension&amp;revision=2013-12-10</capability>
92 <capability>urn:ietf:params:netconf:base:1.0</capability>
93 <capability>urn:ietf:params:xml:ns:yang:iana-afn-safi?module=iana-afn-safi&amp;revision=2013-07-04</capability>
94 <capability>urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&amp;revision=2013-07-15</capability>
95 </capabilities>
96 </hello>';
97     $hello_message .= "\n]]>]]>\n";
98 }
99
100 print STDERR "connecting to " . $connection_string . "\n";
101
102 my $ssh_handle = Net::OpenSSH->new(
103     $connection_string,
104     master_opts         => [ -o => 'StrictHostKeyChecking=no' ],
105     timeout             => 500,
106     kill_ssh_on_timeout => 500
107 );
108
109 #netconf requires a specific socket
110 my ( $ssh_subsocket, $pid ) =
111   $ssh_handle->open2socket( { ssh_opts => '-s' }, 'netconf' );
112 die "can't establish connection: exiting\n" unless defined($ssh_subsocket);
113
114 print STDERR "[Connected]\n";
115
116 # split the program into two processes, identical twins
117 die "can't fork: $!" unless defined( $kidpid = fork() );
118
119 # the if{} block runs only in the parent process (terminal output)
120 if ( !$kidpid ) {
121
122     $| = 1;
123
124     # copy the socket to standard output
125     my $buf;
126     my $nread;
127
128 #while (<$ssh_subsocket>) {
129 #buffer seems not totally flushed when using the syntax above (nor when using autoflush)
130     while ( $nread = sysread( $ssh_subsocket, $buf, 150 ) ) {
131         print $buf;
132         $ssh_subsocket->flush();
133     }
134
135     print;
136     kill( "TERM", $kidpid );    # send SIGTERM to child
137 }
138
139 # the else{} block runs only in the child process (terminal input)
140 else {
141
142     $ssh_subsocket->autoflush(1);
143     sleep 1;    # wait needed for ensuring STDOUT buffer is not melt
144
145     if ( defined($hello_message) ) {
146         print $ssh_subsocket $hello_message;
147         sleep 1;
148     }
149
150     while ( defined( my $line = <STDIN> ) ) {
151         print $ssh_subsocket $line;
152     }
153
154 }
155
156 sleep 2;
157 kill( "TERM", $kidpid );    # send SIGTERM to child
158 exit;