title: Fortigate automation with perl or python
body: <p><strong>Goal</strong><br />
  I'm trying to automate a fortigate configuration change for a couple dozen routers and am not winning. Have tried Python's paramiko library, Python fabric and Perl's expect and Rex interfaces/libraries.</p>
  
  <p><strong>Other info</strong><br />
  * Routers: Fortigate 60D <br />
  * Firmware: v5.0,build0252 (GA Patch 5)<br />
  * SSH enabled: True</p>
  
  <p>I can log in over SSH and run these commands manually!</p>
  
  <p>I used the perl expect library with Fortigate 60B's in the past but it no longer works. Before I share the code I want to ask:</p>
  
  <p>Is there some new feature in Fortigate's that prevents this type of automation?</p>
  
  <p>A simple and harmless command to test [ list current dhcp leases ]:</p>
  
  <pre><code>execute dhcp lease-list wifi
  </code></pre>
  
  <p><strong>Code</strong><br />
  Perl/Expect:</p>
  
  <pre><code>my $timeout = 10; 
  
  $ssh-&gt;expect($timeout, [ qr/password: /i ]); 
  $ssh-&gt;send("$passwd\r\n"); 
  $ssh-&gt;expect($timeout, [ qr/#/i ]); 
  $ssh-&gt;send("execute dhcp lease-list wifi\r"); 
  $ssh-&gt;expect($timeout, [ qr/#/i ]); 
  $ssh-&gt;send("exit\r"); 
  
  $ssh-&gt;soft_close();
  </code></pre>
  
  <p>Output: none</p>
  
  <p>Perl/Rex:</p>
  
  <pre><code>desc "List all dhcp leases";
  task "leases", group =&gt; "forti", sub {
      my $output = run "execute dhcp lease-list wifi";
      say $output;
  };
  </code></pre>
  
  <p>Output:<br /></p>
  
  <pre>
  [2014-02-11 13:14:48] (30011) - INFO - Running task: leases
  [2014-02-11 13:14:48] (30022) - INFO - Connecting to 10.10.10.2 (admin)
  [2014-02-11 13:14:49] (30022) - INFO - Connected to 10.10.10.2, trying to authenticate.
  Fortigate # Unknown action 0
  
  Fortigate # 
  </pre>
  
  <p>Python/paramiko:</p>
  
  <pre><code>ssh = paramiko.SSHClient()
  ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  ssh.connect('10.10.10.2',username='fake_root',password='fake_pass') 
  stdin, stdout, stderr=ssh.exec_command("execute dhcp lease-list wifi")
  stdout.readlines()
  ssh.close()
  </code></pre>
  
  <p>Output: none</p>
  
  <p>Python/Fabric:</p>
  
  <pre><code>def view_dhcp_leases():
          print("Viewing dhcp leases")
          run("execute dhcp lease-list wifi")
  </code></pre>
  
  <p>Output:</p>
  
  <pre>
  
  [10.10.10.2] Executing task 'view_dhcp_leases'
  Viewing dhcp leases
  [10.10.10.2] run: execute dhcp lease-list wifi
  [10.10.10.2] out: Fortigate # Unknown action 0
  [10.10.10.2] out: 
  [10.10.10.2] out: Fortigate # 
  
  Done.
  Disconnecting from 10.10.10.2 ... done.
  </pre>
  
  <p><strong>Conclusions ...so far</strong><br /></p>
  
  <p><code>Unknown action 0</code> means, "I don't know this command [ in this context ]". This command <strong><em>can</em></strong> be run manually at the first prompt. Also, as you can see in the fabric and rex examples: it <strong><em>does</em></strong> authenticate and connect! I conclude that this is by design for security reasons ...and more likely to sell their proprietary management crap.</p>