summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--interface-definitions/include/policy/route-common.xml.i7
-rw-r--r--interface-definitions/include/rip/interface.xml.i7
-rw-r--r--interface-definitions/nat66.xml.in14
-rw-r--r--op-mode-definitions/show-interfaces.xml.in6
-rw-r--r--op-mode-definitions/show-vrf.xml.in14
-rw-r--r--python/vyos/ifconfig/interface.py14
-rwxr-xr-xsmoketest/scripts/cli/test_service_https.py102
-rwxr-xr-xsrc/op_mode/interfaces.py56
-rwxr-xr-xsrc/op_mode/pki.py14
9 files changed, 203 insertions, 31 deletions
diff --git a/interface-definitions/include/policy/route-common.xml.i b/interface-definitions/include/policy/route-common.xml.i
index 4405f9c26..b8581b03e 100644
--- a/interface-definitions/include/policy/route-common.xml.i
+++ b/interface-definitions/include/policy/route-common.xml.i
@@ -2,12 +2,7 @@
#include <include/policy/route-rule-action.xml.i>
#include <include/generic-description.xml.i>
#include <include/firewall/firewall-mark.xml.i>
-<leafNode name="disable">
- <properties>
- <help>Option to disable firewall rule</help>
- <valueless/>
- </properties>
-</leafNode>
+#include <include/generic-disable-node.xml.i>
<node name="fragment">
<properties>
<help>IP fragment match</help>
diff --git a/interface-definitions/include/rip/interface.xml.i b/interface-definitions/include/rip/interface.xml.i
index 8007f0208..7c64d0708 100644
--- a/interface-definitions/include/rip/interface.xml.i
+++ b/interface-definitions/include/rip/interface.xml.i
@@ -19,12 +19,7 @@
<help>Split horizon parameters</help>
</properties>
<children>
- <leafNode name="disable">
- <properties>
- <help>Disable split horizon on specified interface</help>
- <valueless/>
- </properties>
- </leafNode>
+ #include <include/generic-disable-node.xml.i>
<leafNode name="poison-reverse">
<properties>
<help>Disable split horizon on specified interface</help>
diff --git a/interface-definitions/nat66.xml.in b/interface-definitions/nat66.xml.in
index 2fd95e03a..1518de8bd 100644
--- a/interface-definitions/nat66.xml.in
+++ b/interface-definitions/nat66.xml.in
@@ -25,12 +25,7 @@
</properties>
<children>
#include <include/generic-description.xml.i>
- <leafNode name="disable">
- <properties>
- <help>Disable NAT66 rule</help>
- <valueless/>
- </properties>
- </leafNode>
+ #include <include/generic-disable-node.xml.i>
#include <include/nat-exclude.xml.i>
#include <include/firewall/log.xml.i>
#include <include/firewall/outbound-interface-no-group.xml.i>
@@ -141,12 +136,7 @@
</properties>
<children>
#include <include/generic-description.xml.i>
- <leafNode name="disable">
- <properties>
- <help>Disable NAT66 rule</help>
- <valueless/>
- </properties>
- </leafNode>
+ #include <include/generic-disable-node.xml.i>
#include <include/nat-exclude.xml.i>
<leafNode name="log">
<properties>
diff --git a/op-mode-definitions/show-interfaces.xml.in b/op-mode-definitions/show-interfaces.xml.in
index dc61a6f5c..b58e0efea 100644
--- a/op-mode-definitions/show-interfaces.xml.in
+++ b/op-mode-definitions/show-interfaces.xml.in
@@ -20,6 +20,12 @@
</properties>
<command>${vyos_op_scripts_dir}/interfaces.py show</command>
</leafNode>
+ <leafNode name="summary">
+ <properties>
+ <help>Show summary information of all interfaces</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/interfaces.py show_summary_extended</command>
+ </leafNode>
</children>
</node>
</children>
diff --git a/op-mode-definitions/show-vrf.xml.in b/op-mode-definitions/show-vrf.xml.in
index 9728eb1fa..c18649844 100644
--- a/op-mode-definitions/show-vrf.xml.in
+++ b/op-mode-definitions/show-vrf.xml.in
@@ -7,6 +7,14 @@
<help>Show VRF (Virtual Routing and Forwarding) information</help>
</properties>
<command>${vyos_op_scripts_dir}/vrf.py show</command>
+ <children>
+ <leafNode name="vni">
+ <properties>
+ <help>Show information on VRF/VXLAN VNI mapping</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+ </leafNode>
+ </children>
</node>
<tagNode name="vrf">
<properties>
@@ -23,6 +31,12 @@
</properties>
<command>ip vrf pids "$3"</command>
</leafNode>
+ <leafNode name="vni">
+ <properties>
+ <help>Show VXLAN VNI association</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+ </leafNode>
</children>
</tagNode>
</children>
diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py
index 050095364..1586710db 100644
--- a/python/vyos/ifconfig/interface.py
+++ b/python/vyos/ifconfig/interface.py
@@ -496,12 +496,12 @@ class Interface(Control):
from hashlib import sha256
# Get processor ID number
- cpu_id = self._cmd('sudo dmidecode -t 4 | grep ID | head -n1 | sed "s/.*ID://;s/ //g"')
+ cpu_id = self._cmd('sudo dmidecode -t 4 | grep ID | head -n1 | sed "s/.*ID://;s/ //g"')
# XXX: T3894 - it seems not all systems have eth0 - get a list of all
# available Ethernet interfaces on the system (without VLAN subinterfaces)
# and then take the first one.
- all_eth_ifs = [x for x in Section.interfaces('ethernet') if '.' not in x]
+ all_eth_ifs = Section.interfaces('ethernet', vlan=False)
first_mac = Interface(all_eth_ifs[0]).get_mac()
sha = sha256()
@@ -571,6 +571,16 @@ class Interface(Control):
self._cmd(f'ip link set dev {self.ifname} netns {netns}')
return True
+ def get_vrf(self):
+ """
+ Get VRF from interface
+
+ Example:
+ >>> from vyos.ifconfig import Interface
+ >>> Interface('eth0').get_vrf()
+ """
+ return self.get_interface('vrf')
+
def set_vrf(self, vrf: str) -> bool:
"""
Add/Remove interface from given VRF instance.
diff --git a/smoketest/scripts/cli/test_service_https.py b/smoketest/scripts/cli/test_service_https.py
index 1ae5c104c..a18e7dfac 100755
--- a/smoketest/scripts/cli/test_service_https.py
+++ b/smoketest/scripts/cli/test_service_https.py
@@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import unittest
+import json
from requests import request
from urllib3.exceptions import InsecureRequestWarning
@@ -138,6 +139,13 @@ class TestHTTPSService(VyOSUnitTestSHIM.TestCase):
# Must get HTTP code 401 on missing key (Unauthorized)
self.assertEqual(r.status_code, 401)
+ # Check path config
+ payload = {'data': '{"op": "showConfig", "path": ["system", "login"]}', 'key': f'{key}'}
+ r = request('POST', url, verify=False, headers=headers, data=payload)
+ response = r.json()
+ vyos_user_exists = 'vyos' in response.get('data', {}).get('user', {})
+ self.assertTrue(vyos_user_exists, "The 'vyos' user does not exist in the response.")
+
# GraphQL auth test: a missing key will return status code 400, as
# 'key' is a non-nullable field in the schema; an incorrect key is
# caught by the resolver, and returns success 'False', so one must
@@ -240,5 +248,99 @@ class TestHTTPSService(VyOSUnitTestSHIM.TestCase):
success = r.json()['data']['ShowVersion']['success']
self.assertTrue(success)
+ @ignore_warning(InsecureRequestWarning)
+ def test_api_show(self):
+ address = '127.0.0.1'
+ key = 'VyOS-key'
+ url = f'https://{address}/show'
+ headers = {}
+
+ self.cli_set(base_path + ['api', 'keys', 'id', 'key-01', 'key', key])
+ self.cli_commit()
+
+ payload = {
+ 'data': '{"op": "show", "path": ["system", "image"]}',
+ 'key': f'{key}',
+ }
+ r = request('POST', url, verify=False, headers=headers, data=payload)
+ self.assertEqual(r.status_code, 200)
+
+ @ignore_warning(InsecureRequestWarning)
+ def test_api_generate(self):
+ address = '127.0.0.1'
+ key = 'VyOS-key'
+ url = f'https://{address}/generate'
+ headers = {}
+
+ self.cli_set(base_path + ['api', 'keys', 'id', 'key-01', 'key', key])
+ self.cli_commit()
+
+ payload = {
+ 'data': '{"op": "generate", "path": ["macsec", "mka", "cak", "gcm-aes-256"]}',
+ 'key': f'{key}',
+ }
+ r = request('POST', url, verify=False, headers=headers, data=payload)
+ self.assertEqual(r.status_code, 200)
+
+ @ignore_warning(InsecureRequestWarning)
+ def test_api_configure(self):
+ address = '127.0.0.1'
+ key = 'VyOS-key'
+ url = f'https://{address}/configure'
+ headers = {}
+ conf_interface = 'dum0'
+ conf_address = '192.0.2.44/32'
+
+ self.cli_set(base_path + ['api', 'keys', 'id', 'key-01', 'key', key])
+ self.cli_commit()
+
+ payload_path = [
+ "interfaces",
+ "dummy",
+ f"{conf_interface}",
+ "address",
+ f"{conf_address}",
+ ]
+
+ payload = {'data': json.dumps({"op": "set", "path": payload_path}), 'key': key}
+
+ r = request('POST', url, verify=False, headers=headers, data=payload)
+ self.assertEqual(r.status_code, 200)
+
+ @ignore_warning(InsecureRequestWarning)
+ def test_api_config_file(self):
+ address = '127.0.0.1'
+ key = 'VyOS-key'
+ url = f'https://{address}/config-file'
+ headers = {}
+
+ self.cli_set(base_path + ['api', 'keys', 'id', 'key-01', 'key', key])
+ self.cli_commit()
+
+ payload = {
+ 'data': '{"op": "save"}',
+ 'key': f'{key}',
+ }
+ r = request('POST', url, verify=False, headers=headers, data=payload)
+ self.assertEqual(r.status_code, 200)
+
+ @ignore_warning(InsecureRequestWarning)
+ def test_api_reset(self):
+ address = '127.0.0.1'
+ key = 'VyOS-key'
+ url = f'https://{address}/reset'
+ headers = {}
+
+ self.cli_set(base_path + ['api', 'keys', 'id', 'key-01', 'key', key])
+ self.cli_commit()
+
+ payload = {
+ 'data': '{"op": "reset", "path": ["ip", "arp", "table"]}',
+ 'key': f'{key}',
+ }
+ r = request('POST', url, verify=False, headers=headers, data=payload)
+ self.assertEqual(r.status_code, 200)
+
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/op_mode/interfaces.py b/src/op_mode/interfaces.py
index 782e178c6..c626535b5 100755
--- a/src/op_mode/interfaces.py
+++ b/src/op_mode/interfaces.py
@@ -243,6 +243,9 @@ def _get_summary_data(ifname: typing.Optional[str],
res_intf['admin_state'] = interface.get_admin_state()
res_intf['addr'] = [_ for _ in interface.get_addr() if not _.startswith('fe80::')]
res_intf['description'] = interface.get_alias()
+ res_intf['mtu'] = interface.get_mtu()
+ res_intf['mac'] = interface.get_mac()
+ res_intf['vrf'] = interface.get_vrf()
ret.append(res_intf)
@@ -373,6 +376,51 @@ def _format_show_summary(data):
return 0
@catch_broken_pipe
+def _format_show_summary_extended(data):
+ headers = ["Interface", "IP Address", "MAC", "VRF", "MTU", "S/L", "Description"]
+ table_data = []
+
+ print('Codes: S - State, L - Link, u - Up, D - Down, A - Admin Down')
+
+ for intf in data:
+ if 'unhandled' in intf:
+ continue
+
+ ifname = intf['ifname']
+ oper_state = 'u' if intf['oper_state'] in ('up', 'unknown') else 'D'
+ admin_state = 'u' if intf['admin_state'] in ('up', 'unknown') else 'A'
+ addrs = intf['addr'] or ['-']
+ description = '\n'.join(_split_text(intf['description'], 0))
+ mac = intf['mac'] if intf['mac'] else 'n/a'
+ mtu = intf['mtu'] if intf['mtu'] else 'n/a'
+ vrf = intf['vrf'] if intf['vrf'] else 'default'
+
+ ip_addresses = '\n'.join(ip for ip in addrs)
+
+ # Create a row for the table
+ row = [
+ ifname,
+ ip_addresses,
+ mac,
+ vrf,
+ mtu,
+ f"{admin_state}/{oper_state}",
+ description,
+ ]
+
+ # Append the row to the table data
+ table_data.append(row)
+
+ for intf in data:
+ if 'unhandled' in intf:
+ string = {'C': 'u/D', 'D': 'A/D'}[intf['state']]
+ table_data.append([intf['ifname'], '', '', '', '', string, ''])
+
+ print(tabulate(table_data, headers))
+
+ return 0
+
+@catch_broken_pipe
def _format_show_counters(data: list):
data_entries = []
for entry in data:
@@ -408,6 +456,14 @@ def show_summary(raw: bool, intf_name: typing.Optional[str],
return data
return _format_show_summary(data)
+def show_summary_extended(raw: bool, intf_name: typing.Optional[str],
+ intf_type: typing.Optional[str],
+ vif: bool, vrrp: bool):
+ data = _get_summary_data(intf_name, intf_type, vif, vrrp)
+ if raw:
+ return data
+ return _format_show_summary_extended(data)
+
def show_counters(raw: bool, intf_name: typing.Optional[str],
intf_type: typing.Optional[str],
vif: bool, vrrp: bool):
diff --git a/src/op_mode/pki.py b/src/op_mode/pki.py
index 35c7ce0e2..6c854afb5 100755
--- a/src/op_mode/pki.py
+++ b/src/op_mode/pki.py
@@ -896,11 +896,15 @@ def show_certificate(name=None, pem=False):
cert_subject_cn = cert.subject.rfc4514_string().split(",")[0]
cert_issuer_cn = cert.issuer.rfc4514_string().split(",")[0]
cert_type = 'Unknown'
- ext = cert.extensions.get_extension_for_class(x509.ExtendedKeyUsage)
- if ext and ExtendedKeyUsageOID.SERVER_AUTH in ext.value:
- cert_type = 'Server'
- elif ext and ExtendedKeyUsageOID.CLIENT_AUTH in ext.value:
- cert_type = 'Client'
+
+ try:
+ ext = cert.extensions.get_extension_for_class(x509.ExtendedKeyUsage)
+ if ext and ExtendedKeyUsageOID.SERVER_AUTH in ext.value:
+ cert_type = 'Server'
+ elif ext and ExtendedKeyUsageOID.CLIENT_AUTH in ext.value:
+ cert_type = 'Client'
+ except:
+ pass
revoked = 'Yes' if 'revoke' in cert_dict else 'No'
have_private = 'Yes' if 'private' in cert_dict and 'key' in cert_dict['private'] else 'No'