summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--interface-definitions/https.xml2
-rw-r--r--interface-definitions/interfaces-bonding.xml2
-rw-r--r--interface-definitions/snmp.xml4
-rw-r--r--op-mode-definitions/wireguard.xml2
-rw-r--r--python/vyos/config.py25
-rw-r--r--python/vyos/configtree.py14
-rw-r--r--python/vyos/ifconfig.py98
-rw-r--r--python/vyos/interface.py150
-rwxr-xr-xscripts/build-command-templates2
-rwxr-xr-xsrc/completion/list_interfaces.py3
-rwxr-xr-xsrc/conf_mode/snmp.py49
-rwxr-xr-xsrc/op_mode/wireguard.py6
-rwxr-xr-xsrc/services/vyos-http-api-server14
-rwxr-xr-xsrc/utils/vyos-config-to-json40
14 files changed, 218 insertions, 193 deletions
diff --git a/interface-definitions/https.xml b/interface-definitions/https.xml
index 2fb3bf082..403d4ecb0 100644
--- a/interface-definitions/https.xml
+++ b/interface-definitions/https.xml
@@ -27,7 +27,7 @@
<constraint>
<validator name="ipv4-address"/>
<validator name="ipv6-address"/>
- <regex>^\\*$</regex>
+ <regex>^\*$</regex>
</constraint>
</properties>
<children>
diff --git a/interface-definitions/interfaces-bonding.xml b/interface-definitions/interfaces-bonding.xml
index c71482d9c..ba1acfff6 100644
--- a/interface-definitions/interfaces-bonding.xml
+++ b/interface-definitions/interfaces-bonding.xml
@@ -159,7 +159,7 @@
<description>combine IP address and port to make hash</description>
</valueHelp>
<constraint>
- <regex>(layer2\\+3|layer3\\+4|layer2)</regex>
+ <regex>(layer2\+3|layer3\+4|layer2)</regex>
</constraint>
<constraintErrorMessage>hash-policy must be layer2 layer2+3 or layer3+4</constraintErrorMessage>
</properties>
diff --git a/interface-definitions/snmp.xml b/interface-definitions/snmp.xml
index 14aad90a0..bdfbd4ab6 100644
--- a/interface-definitions/snmp.xml
+++ b/interface-definitions/snmp.xml
@@ -552,7 +552,7 @@
<properties>
<help>Specifies the oid</help>
<constraint>
- <regex>^[0-9]+(\\.[0-9]+)*$</regex>
+ <regex>^[0-9]+(\.[0-9]+)*$</regex>
</constraint>
<constraintErrorMessage>OID must start from a number</constraintErrorMessage>
</properties>
@@ -566,7 +566,7 @@
<properties>
<help>Defines a bit-mask that is indicating which subidentifiers of the associated subtree OID should be regarded as significant</help>
<constraint>
- <regex>^[0-9a-f]{2}([\\.:][0-9a-f]{2})*$</regex>
+ <regex>^[0-9a-f]{2}([\.:][0-9a-f]{2})*$</regex>
</constraint>
<constraintErrorMessage>MASK is a list of hex octets, separated by '.' or ':'</constraintErrorMessage>
</properties>
diff --git a/op-mode-definitions/wireguard.xml b/op-mode-definitions/wireguard.xml
index e52d0ad76..1795fb820 100644
--- a/op-mode-definitions/wireguard.xml
+++ b/op-mode-definitions/wireguard.xml
@@ -73,7 +73,7 @@
<script>${vyos_completion_dir}/list_interfaces.py --type wireguard</script>
</completionHelp>
</properties>
- <command>sudo ${vyos_op_scripts_dir}/wireguard.py "$4"</command>
+ <command>sudo ${vyos_op_scripts_dir}/wireguard.py --showinterface "$4"</command>
<children>
<leafNode name="allowed-ips">
<properties>
diff --git a/python/vyos/config.py b/python/vyos/config.py
index 7f65a9397..5bd8fb072 100644
--- a/python/vyos/config.py
+++ b/python/vyos/config.py
@@ -65,6 +65,7 @@ In operational mode, all functions return values from the running config.
import os
import re
+import json
import subprocess
import vyos.configtree
@@ -104,12 +105,10 @@ class Config(object):
running_config_text = f.read()
# Session config ("active") only exists in conf mode.
- # Trying to obtain it from op mode will cause a fatal cli-shell-api error.
- # If that happens, we assume that a script is running from op mode and use the running config
- # for the "session config" variable as well.
- try:
+ # In op mode, we'll just use the same running config for both active and session configs.
+ if self.in_session():
session_config_text = self._run([self._cli_shell_api, '--show-working-only', '--show-show-defaults', 'showConfig'])
- except VyOSError:
+ else:
session_config_text = running_config_text
self._session_config = vyos.configtree.ConfigTree(session_config_text)
@@ -224,21 +223,33 @@ class Config(object):
except VyOSError:
return False
- def show_config(self, path='', default=None):
+ def show_config(self, path=[], default=None):
"""
Args:
- path (str): Configuration tree path, or empty
+ path (str list): Configuration tree path, or empty
default (str): Default value to return
Returns:
str: working configuration
"""
+ if isinstance(path, list):
+ path = " ".join(path)
try:
out = self._run(self._make_command('showConfig', path))
return out
except VyOSError:
return(default)
+ def get_config_dict(self, path=[], effective=False):
+ """
+ Args: path (str list): Configuration tree path, can be empty
+ Returns: a dict representation of the config
+ """
+ res = self.show_config(self._make_path(path))
+ config_tree = vyos.configtree.ConfigTree(res)
+ config_dict = json.loads(config_tree.to_json())
+ return config_dict
+
def is_multi(self, path):
"""
Args:
diff --git a/python/vyos/configtree.py b/python/vyos/configtree.py
index 8832a5a63..77cffe90b 100644
--- a/python/vyos/configtree.py
+++ b/python/vyos/configtree.py
@@ -105,6 +105,14 @@ class ConfigTree(object):
self.__to_commands.argtypes = [c_void_p]
self.__to_commands.restype = c_char_p
+ self.__to_json = self.__lib.to_json
+ self.__to_json.argtypes = [c_void_p]
+ self.__to_json.restype = c_char_p
+
+ self.__to_json_ast = self.__lib.to_json_ast
+ self.__to_json_ast.argtypes = [c_void_p]
+ self.__to_json_ast.restype = c_char_p
+
self.__set_add_value = self.__lib.set_add_value
self.__set_add_value.argtypes = [c_void_p, c_char_p, c_char_p]
self.__set_add_value.restype = c_int
@@ -184,6 +192,12 @@ class ConfigTree(object):
def to_commands(self):
return self.__to_commands(self.__config).decode()
+ def to_json(self):
+ return self.__to_json(self.__config).decode()
+
+ def to_json_ast(self):
+ return self.__to_json_ast(self.__config).decode()
+
def set(self, path, value=None, replace=True):
"""Set new entry in VyOS configuration.
path: configuration path e.g. 'system dns forwarding listen-address'
diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py
index 3470b3aa6..df86e3c93 100644
--- a/python/vyos/ifconfig.py
+++ b/python/vyos/ifconfig.py
@@ -17,12 +17,20 @@ import os
import re
import jinja2
import json
+import glob
+import time
+import vyos.interfaces
from vyos.validate import *
+from vyos.config import Config
from ipaddress import IPv4Network, IPv6Address
from netifaces import ifaddresses, AF_INET, AF_INET6
from subprocess import Popen, PIPE, STDOUT
from time import sleep
+from os.path import isfile
+from tabulate import tabulate
+from hurry.filesize import size,alternative
+from datetime import timedelta
dhclient_base = r'/var/lib/dhcp/dhclient_'
dhcp_cfg = """
@@ -671,6 +679,31 @@ class Interface:
if os.path.isfile(self._dhcpv6_lease_file):
os.remove(self._dhcpv6_lease_file)
+ def op_show_interface_stats(self):
+ stats = self.get_interface_stats()
+ rx = [['bytes','packets','errors','dropped','overrun','mcast'],[stats['rx_bytes'],stats['rx_packets'],stats['rx_errors'],stats['rx_dropped'],stats['rx_over_errors'],stats['multicast']]]
+ tx = [['bytes','packets','errors','dropped','carrier','collisions'],[stats['tx_bytes'],stats['tx_packets'],stats['tx_errors'],stats['tx_dropped'],stats['tx_carrier_errors'],stats['collisions']]]
+ output = "RX: \n"
+ output += tabulate(rx,headers="firstrow",numalign="right",tablefmt="plain")
+ output += "\n\nTX: \n"
+ output += tabulate(tx,headers="firstrow",numalign="right",tablefmt="plain")
+ print(' '.join(('\n'+output.lstrip()).splitlines(True)))
+
+ def get_interface_stats(self):
+ interface_stats = dict()
+ devices = [f for f in glob.glob("/sys/class/net/**/statistics")]
+ for dev_path in devices:
+ metrics = [f for f in glob.glob(dev_path +"/**")]
+ dev = re.findall(r"/sys/class/net/(.*)/statistics",dev_path)[0]
+ dev_dict = dict()
+ for metric_path in metrics:
+ metric = metric_path.replace(dev_path+"/","")
+ if isfile(metric_path):
+ data = open(metric_path, 'r').read()[:-1]
+ dev_dict[metric] = int(data)
+ interface_stats[dev] = dev_dict
+
+ return interface_stats[self._ifname]
class LoopbackIf(Interface):
@@ -1371,7 +1404,6 @@ class BondIf(VLANIf):
return self._write_sysfs('/sys/class/net/{}/bonding/mode'
.format(self._ifname), mode)
-
class WireGuardIf(Interface):
"""
Wireguard interface class, contains a comnfig dictionary since
@@ -1447,6 +1479,70 @@ class WireGuardIf(Interface):
cmd = "wg set {0} peer {1} remove".format(
self._ifname, str(peerkey))
return self._cmd(cmd)
+
+ def op_show_interface(self):
+ wgdump = vyos.interfaces.wireguard_dump().get(self._ifname,None)
+
+ c = Config()
+ c.set_level(["interfaces","wireguard",self._ifname])
+ description = c.return_effective_value(["description"])
+ ips = c.return_effective_values(["address"])
+
+ print ("interface: {}".format(self._ifname))
+ if (description):
+ print (" description: {}".format(description))
+
+ if (ips):
+ print (" address: {}".format(", ".join(ips)))
+ print (" public key: {}".format(wgdump['public_key']))
+ print (" private key: (hidden)")
+ print (" listening port: {}".format(wgdump['listen_port']))
+ print ()
+
+ for peer in c.list_effective_nodes(["peer"]):
+ if wgdump['peers']:
+ pubkey = c.return_effective_value(["peer",peer,"pubkey"])
+ if pubkey in wgdump['peers']:
+ wgpeer = wgdump['peers'][pubkey]
+
+ print (" peer: {}".format(peer))
+ print (" public key: {}".format(pubkey))
+
+ """ figure out if the tunnel is recently active or not """
+ status = "inactive"
+ if (wgpeer['latest_handshake'] is None):
+ """ no handshake ever """
+ status = "inactive"
+ else:
+ if int(wgpeer['latest_handshake']) > 0:
+ delta = timedelta(seconds=int(time.time() - wgpeer['latest_handshake']))
+ print (" latest handshake: {}".format(delta))
+ if (time.time() - int(wgpeer['latest_handshake']) < (60*5)):
+ """ Five minutes and the tunnel is still active """
+ status = "active"
+ else:
+ """ it's been longer than 5 minutes """
+ status = "inactive"
+ elif int(wgpeer['latest_handshake']) == 0:
+ """ no handshake ever """
+ status = "inactive"
+ print (" status: {}".format(status))
+
+ if wgpeer['endpoint'] is not None:
+ print (" endpoint: {}".format(wgpeer['endpoint']))
+
+ if wgpeer['allowed_ips'] is not None:
+ print (" allowed ips: {}".format(",".join(wgpeer['allowed_ips']).replace(",",", ")))
+
+ if wgpeer['transfer_rx'] > 0 or wgpeer['transfer_tx'] > 0:
+ rx_size =size(wgpeer['transfer_rx'],system=alternative)
+ tx_size =size(wgpeer['transfer_tx'],system=alternative)
+ print (" transfer: {} received, {} sent".format(rx_size,tx_size))
+
+ if wgpeer['persistent_keepalive'] is not None:
+ print (" persistent keepalive: every {} seconds".format(wgpeer['persistent_keepalive']))
+ print()
+ super().op_show_interface_stats()
class VXLANIf(Interface, ):
diff --git a/python/vyos/interface.py b/python/vyos/interface.py
deleted file mode 100644
index cc726e5cc..000000000
--- a/python/vyos/interface.py
+++ /dev/null
@@ -1,150 +0,0 @@
-# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io>
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library. If not, see <http://www.gnu.org/licenses/>.
-
-import vyos
-from vyos.config import Config
-import vyos.interfaces
-import vyos.ioctl
-from vyos.iflag import IFlag
-
-import re
-import json
-
-import subprocess
-import time
-from datetime import timedelta
-import glob
-from os.path import isfile
-from tabulate import tabulate
-from hurry.filesize import size,alternative
-
-class Interface():
-
- intf = None
- intf_type = None
- valid = False
- flags = None
-
- def __init__(self,intf):
- self.intf = intf
- self.intf_type = vyos.interfaces.get_type_of_interface(self.intf)
- self.valid = (self.intf in vyos.interfaces.list_interfaces())
- if (self.valid):
- self.flags = vyos.ioctl.get_interface_flags(intf)
-
- def up(self):
- """ return whether interface is up or not """
- return self.flags & IFlag.IFF_UP
-
- def print_interface(self):
-
- if not self.valid:
- print("Invalid interface [{}]".format(self.intf))
- return
-
- if (self.intf_type == 'wireguard'):
- self.print_wireguard_interface()
-
- self.print_interface_stats()
-
- def print_interface_stats(self):
- stats = self.get_interface_stats()
- rx = [['bytes','packets','errors','dropped','overrun','mcast'],[stats['rx_bytes'],stats['rx_packets'],stats['rx_errors'],stats['rx_dropped'],stats['rx_over_errors'],stats['multicast']]]
- tx = [['bytes','packets','errors','dropped','carrier','collisions'],[stats['tx_bytes'],stats['tx_packets'],stats['tx_errors'],stats['tx_dropped'],stats['tx_carrier_errors'],stats['collisions']]]
- output = "RX: \n"
- output += tabulate(rx,headers="firstrow",numalign="right",tablefmt="plain")
- output += "\n\nTX: \n"
- output += tabulate(tx,headers="firstrow",numalign="right",tablefmt="plain")
- print(' '.join(('\n'+output.lstrip()).splitlines(True)))
-
- def get_interface_stats(self):
- interface_stats = dict()
- devices = [f for f in glob.glob("/sys/class/net/**/statistics")]
- for dev_path in devices:
- metrics = [f for f in glob.glob(dev_path +"/**")]
- dev = re.findall(r"/sys/class/net/(.*)/statistics",dev_path)[0]
- dev_dict = dict()
- for metric_path in metrics:
- metric = metric_path.replace(dev_path+"/","")
- if isfile(metric_path):
- data = open(metric_path, 'r').read()[:-1]
- dev_dict[metric] = int(data)
- interface_stats[dev] = dev_dict
-
- return interface_stats[self.intf]
-
- def print_wireguard_interface(self):
-
- wgdump = vyos.interfaces.wireguard_dump().get(self.intf,None)
-
- c = Config()
- c.set_level("interfaces wireguard {}".format(self.intf))
- description = c.return_effective_value("description")
- ips = c.return_effective_values("address")
-
- print ("interface: {}".format(self.intf))
- if (description):
- print (" description: {}".format(description))
-
- if (ips):
- print (" address: {}".format(", ".join(ips)))
- print (" public key: {}".format(wgdump['public_key']))
- print (" private key: (hidden)")
- print (" listening port: {}".format(wgdump['listen_port']))
- print ()
-
- for peer in c.list_effective_nodes(' peer'):
- if wgdump['peers']:
- pubkey = c.return_effective_value("peer {} pubkey".format(peer))
- if pubkey in wgdump['peers']:
- wgpeer = wgdump['peers'][pubkey]
-
- print (" peer: {}".format(peer))
- print (" public key: {}".format(pubkey))
-
- """ figure out if the tunnel is recently active or not """
- status = "inactive"
- if (wgpeer['latest_handshake'] is None):
- """ no handshake ever """
- status = "inactive"
- else:
- if int(wgpeer['latest_handshake']) > 0:
- delta = timedelta(seconds=int(time.time() - wgpeer['latest_handshake']))
- print (" latest handshake: {}".format(delta))
- if (time.time() - int(wgpeer['latest_handshake']) < (60*5)):
- """ Five minutes and the tunnel is still active """
- status = "active"
- else:
- """ it's been longer than 5 minutes """
- status = "inactive"
- elif int(wgpeer['latest_handshake']) == 0:
- """ no handshake ever """
- status = "inactive"
- print (" status: {}".format(status))
-
- if wgpeer['endpoint'] is not None:
- print (" endpoint: {}".format(wgpeer['endpoint']))
-
- if wgpeer['allowed_ips'] is not None:
- print (" allowed ips: {}".format(",".join(wgpeer['allowed_ips']).replace(",",", ")))
-
- if wgpeer['transfer_rx'] > 0 or wgpeer['transfer_tx'] > 0:
- rx_size =size(wgpeer['transfer_rx'],system=alternative)
- tx_size =size(wgpeer['transfer_tx'],system=alternative)
- print (" transfer: {} received, {} sent".format(rx_size,tx_size))
-
- if wgpeer['persistent_keepalive'] is not None:
- print (" persistent keepalive: every {} seconds".format(wgpeer['persistent_keepalive']))
- print()
diff --git a/scripts/build-command-templates b/scripts/build-command-templates
index ba80eadb2..4fcdb8ade 100755
--- a/scripts/build-command-templates
+++ b/scripts/build-command-templates
@@ -125,7 +125,7 @@ def get_properties(p):
regexes = []
regex_elements = vce.findall("regex")
if regex_elements is not None:
- regexes = list(map(lambda e: e.text.strip(), regex_elements))
+ regexes = list(map(lambda e: e.text.strip().replace('\\','\\\\'), regex_elements))
if "" in regexes:
print("Warning: empty regex, node will be accepting any value")
diff --git a/src/completion/list_interfaces.py b/src/completion/list_interfaces.py
index 5e444ef78..84d17f89f 100755
--- a/src/completion/list_interfaces.py
+++ b/src/completion/list_interfaces.py
@@ -34,7 +34,8 @@ elif args.bridgeable:
openvpn = vyos.interfaces.list_interfaces_of_type("openvpn")
vxlan = vyos.interfaces.list_interfaces_of_type("vxlan")
wireless = vyos.interfaces.list_interfaces_of_type("wireless")
- interfaces = eth + bond + l2tpv3 + openvpn + vxlan + wireless
+ tunnel = vyos.interfaces.list_interfaces_of_type("tunnel")
+ interfaces = eth + bond + l2tpv3 + openvpn + vxlan + wireless + tunnel
elif args.bondable:
eth = vyos.interfaces.list_interfaces_of_type("ethernet")
diff --git a/src/conf_mode/snmp.py b/src/conf_mode/snmp.py
index 74c17fff6..b64cccbfa 100755
--- a/src/conf_mode/snmp.py
+++ b/src/conf_mode/snmp.py
@@ -16,19 +16,18 @@
import sys
import os
-import shutil
import stat
import pwd
-import time
-
import jinja2
-import random
-import binascii
import re
import vyos.version
import vyos.validate
+from binascii import hexlify
+from shutil import move
+from time import sleep
+from stat import S_IRWXU,S_IXGRP,S_IXOTH
from vyos.config import Config
from vyos import ConfigError
@@ -203,7 +202,7 @@ group {{ u.group }} usm {{ u.name }}
{% if script_ext %}
# extension scripts
{%- for ext in script_ext|sort %}
-extend\t{{ext}}\t{{script_ext[ext]}}
+extend {{ ext.name }} {{ ext.script }}
{%- endfor %}
{% endif %}
"""
@@ -239,7 +238,7 @@ default_config_data = {
'v3_traps': [],
'v3_users': [],
'v3_views': [],
- 'script_ext': {}
+ 'script_ext': []
}
def rmfile(file):
@@ -257,10 +256,10 @@ def get_config():
version_data = vyos.version.get_version_data()
snmp['version'] = version_data['version']
- # create an internal snmpv3 user of the form 'vyattaxxxxxxxxxxxxxxxx'
+ # create an internal snmpv3 user of the form 'vyosxxxxxxxxxxxxxxxx'
# os.urandom(8) returns 8 bytes of random data
- snmp['vyos_user'] = 'vyatta' + binascii.hexlify(os.urandom(8)).decode('utf-8')
- snmp['vyos_user_pass'] = binascii.hexlify(os.urandom(16)).decode('utf-8')
+ snmp['vyos_user'] = 'vyos' + hexlify(os.urandom(8)).decode('utf-8')
+ snmp['vyos_user_pass'] = hexlify(os.urandom(16)).decode('utf-8')
if conf.exists('community'):
for name in conf.list_nodes('community'):
@@ -348,9 +347,13 @@ def get_config():
# 'set service snmp script-extensions'
#
if conf.exists('script-extensions'):
- for extname in conf.list_nodes('script-extensions extension-name'):
- snmp['script_ext'][extname] = '/config/user-data/' + conf.return_value('script-extensions extension-name ' + extname + ' script')
+ for extname in conf.list_nodes('script-extensions extension-name'):
+ extension = {
+ 'name': extname,
+ 'script' : conf.return_value('script-extensions extension-name {} script'.format(extname))
+ }
+ snmp['script_ext'].append(extension)
#########################################################################
# ____ _ _ __ __ ____ _____ #
@@ -545,15 +548,11 @@ def verify(snmp):
### check if the configured script actually exist under /config/user-data
if snmp['script_ext']:
- for ext in snmp['script_ext']:
- if not os.path.isfile(snmp['script_ext'][ext]):
- print ("WARNING: script: " + snmp['script_ext'][ext] + " doesn\'t exist")
- else:
- os.chmod(snmp['script_ext'][ext], 0o555)
-
- # bail out early if SNMP v3 is not configured
- if not snmp['v3_enabled']:
- return None
+ for ext in snmp['script_ext']:
+ if not os.path.isfile(ext['script']):
+ print ("WARNING: script: {} doesn't exist".format(ext['script']))
+ else:
+ os.chmod(ext['script'], S_IRWXU|S_IXGRP|S_IXOTH)
for listen in snmp['listen_address']:
addr = listen[0]
@@ -573,6 +572,10 @@ def verify(snmp):
else:
print('WARNING: SNMP listen address {0} not configured!'.format(addr))
+ # bail out early if SNMP v3 is not configured
+ if not snmp['v3_enabled']:
+ return None
+
if 'v3_groups' in snmp.keys():
for group in snmp['v3_groups']:
#
@@ -723,7 +726,7 @@ def apply(snmp):
if os.path.exists(volatiledir) and os.path.isdir(volatiledir):
files = os.listdir(volatiledir)
for f in files:
- shutil.move(volatiledir + '/' + f, nonvolatiledir)
+ move(volatiledir + '/' + f, nonvolatiledir)
os.chmod(nonvolatiledir + '/' + f, stat.S_IWUSR | stat.S_IRUSR)
os.rmdir(volatiledir)
@@ -744,7 +747,7 @@ def apply(snmp):
snmpReady = False
while not snmpReady:
while not os.path.exists(config_file_user):
- time.sleep(1)
+ sleep(1)
with open(config_file_user, 'r') as f:
for line in f:
diff --git a/src/op_mode/wireguard.py b/src/op_mode/wireguard.py
index 6860aa3ea..38c061cf4 100755
--- a/src/op_mode/wireguard.py
+++ b/src/op_mode/wireguard.py
@@ -24,7 +24,7 @@ import subprocess
import syslog as sl
import re
-from vyos.interface import Interface
+from vyos.ifconfig import WireGuardIf
from vyos import ConfigError
from vyos.config import Config
@@ -150,8 +150,8 @@ if __name__ == '__main__':
if args.listkdir:
list_key_dirs()
if args.showinterface:
- intf = Interface(args.showinterface)
- intf.print_interface()
+ intf = WireGuardIf(args.showinterface)
+ intf.op_show_interface()
if args.delkdir:
if args.location:
del_key_dir(args.location)
diff --git a/src/services/vyos-http-api-server b/src/services/vyos-http-api-server
index 04c44c2be..571ec1258 100755
--- a/src/services/vyos-http-api-server
+++ b/src/services/vyos-http-api-server
@@ -207,11 +207,21 @@ def get_value():
elif op == 'exists':
res = config.exists(path)
elif op == 'showConfig':
- config_format = 'raw'
+ config_format = 'json'
if 'configFormat' in command:
config_format = command['configFormat']
- res = session.show_config(command['path'], format=config_format)
+ res = session.show_config(path=command['path'])
+ if config_format == 'json':
+ config_tree = vyos.configtree.ConfigTree(res)
+ res = json.loads(config_tree.to_json())
+ elif config_format == 'json_ast':
+ config_tree = vyos.configtree.ConfigTree(res)
+ res = json.loads(config_tree.to_json_ast())
+ elif config_format == 'raw':
+ pass
+ else:
+ return error(400, "\"{0}\" is not a valid config format")
else:
return error(400, "\"{0}\" is not a valid operation".format(op))
except VyOSError as e:
diff --git a/src/utils/vyos-config-to-json b/src/utils/vyos-config-to-json
new file mode 100755
index 000000000..e03fd6a59
--- /dev/null
+++ b/src/utils/vyos-config-to-json
@@ -0,0 +1,40 @@
+#!/usr/bin/python3
+
+import sys
+import json
+
+from signal import signal, SIGPIPE, SIG_DFL
+from vyos.configtree import ConfigTree
+
+signal(SIGPIPE,SIG_DFL)
+
+config_string = None
+if (len(sys.argv) == 1):
+ # If no argument given, act as a pipe
+ config_string = sys.stdin.read()
+else:
+ file_name = sys.argv[1]
+ try:
+ with open(file_name, 'r') as f:
+ config_string = f.read()
+ except OSError as e:
+ print("Could not read config file {0}: {1}".format(file_name, e), file=sys.stderr)
+
+# This script is usually called with the output of "cli-shell-api showCfg", which does not
+# escape backslashes. "ConfigTree()" expects escaped backslashes when parsing a config
+# string (and also prints them itself). Therefore this script would fail.
+# Manually escape backslashes here to handle backslashes in any configuration strings
+# properly. The alternative would be to modify the output of "cli-shell-api showCfg",
+# but that may be break other things who rely on that specific output.
+config_string = config_string.replace("\\", "\\\\")
+
+try:
+ config = ConfigTree(config_string)
+ json_str = config.to_json()
+ # Pretty print
+ json_str = json.dumps(json.loads(json_str), indent=4, sort_keys=True)
+except ValueError as e:
+ print("Could not parse the config file: {0}".format(e), file=sys.stderr)
+ sys.exit(1)
+
+print(json_str)