Skip to content

Commit

Permalink
op-mode: T4038: Python rewrite of image tools
Browse files Browse the repository at this point in the history
  • Loading branch information
erkin committed Nov 20, 2023
1 parent 59b432b commit 1951f29
Show file tree
Hide file tree
Showing 7 changed files with 529 additions and 4 deletions.
86 changes: 86 additions & 0 deletions op-mode-definitions/file.xml.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?xml version="1.0"?>
<interfaceDefinition>
<node name="show">
<children>
<tagNode name="file">
<properties>
<help>Show the contents of a file, a directory or an image</help>
<completionHelp><imagePath/></completionHelp>
</properties>
<command>sudo ${vyos_op_scripts_dir}/file.py --show $3</command>
</tagNode>
</children>
</node>
<node name="copy">
<properties>
<help>Copy an object</help>
</properties>
<children>
<tagNode name="file">
<properties>
<help>Copy a file or a directory</help>
<completionHelp><imagePath/></completionHelp>
</properties>
<children>
<tagNode name="to">
<properties>
<help>Destination path</help>
<completionHelp><imagePath/></completionHelp>
</properties>
<command>sudo ${vyos_op_scripts_dir}/file.py --copy $3 $5
</command>
</tagNode>
</children>
</tagNode>
</children>
</node>
<node name="delete">
<properties>
<help>Delete an object</help>
</properties>
<children>
<tagNode name="file">
<properties>
<help>Delete a local file, possibly from an image</help>
<completionHelp><imagePath/></completionHelp>
</properties>
<command>sudo ${vyos_op_scripts_dir}/file.py --delete $3</command>
</tagNode>
</children>
</node>
<node name="clone">
<properties>
<help>Clone an object</help>
</properties>
<children>
<node name="system">
<properties>
<help>Clone a system object</help>
</properties>
<children>
<tagNode name="config">
<properties>
<help>Clone the current system configuration to an image</help>
<completionHelp>
<script>${vyos_completion_dir}/list_images.py --no-running</script>
</completionHelp>
</properties>
<command>sudo ${vyos_op_scripts_dir}/file.py --clone $4</command>
<children>
<tagNode name="from">
<properties>
<help>Clone system configuration from an image to another one</help>
<completionHelp>
<list>running</list>
<script>${vyos_completion_dir}/list_images.py</script>
</completionHelp>
</properties>
<command>sudo ${vyos_op_scripts_dir}/file.py --clone-from $6 $4</command>
</tagNode>
</children>
</tagNode>
</children>
</node>
</children>
</node>
</interfaceDefinition>
6 changes: 5 additions & 1 deletion python/vyos/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class InteractivePolicy(MissingHostKeyPolicy):
def missing_host_key(self, client, hostname, key):
print_error(f"Host '{hostname}' not found in known hosts.")
print_error('Fingerprint: ' + key.get_fingerprint().hex())
if is_interactive() and ask_yes_no('Do you wish to continue?'):
if sys.stdin.isatty() and ask_yes_no('Do you wish to continue?'):
if client._host_keys_filename\
and ask_yes_no('Do you wish to permanently add this host/key pair to known hosts?'):
client._host_keys.add(hostname, key.get_name(), key)
Expand Down Expand Up @@ -330,8 +330,10 @@ def download(local_path, urlstring, progressbar=False, check_space=False,
urlc(urlstring, progressbar, check_space, source_host, source_port, timeout).download(local_path)
except Exception as err:
print_error(f'Unable to download "{urlstring}": {err}')
sys.exit(1)
except KeyboardInterrupt:
print_error('\nDownload aborted by user.')
sys.exit(1)

def upload(local_path, urlstring, progressbar=False,
source_host='', source_port=0, timeout=10.0):
Expand All @@ -340,8 +342,10 @@ def upload(local_path, urlstring, progressbar=False,
urlc(urlstring, progressbar, source_host, source_port, timeout).upload(local_path)
except Exception as err:
print_error(f'Unable to upload "{urlstring}": {err}')
sys.exit(1)
except KeyboardInterrupt:
print_error('\nUpload aborted by user.')
sys.exit(1)

def get_remote_config(urlstring, source_host='', source_port=0):
"""
Expand Down
8 changes: 5 additions & 3 deletions schema/op-mode-definition.rnc
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,15 @@ command = element command

# completionHelp tags contain information about allowed values of a node that is used for generating
# tab completion in the CLI frontend and drop-down lists in GUI frontends
# It is only meaninful for leaf nodes
# It is only meaningful for leaf nodes
# Allowed values can be given as a fixed list of values (e.g. <list>foo bar baz</list>),
# as a configuration path (e.g. <path>interfaces ethernet</path>),
# or as a path to a script file that generates the list (e.g. <script>/usr/lib/foo/list-things</script>
# as a path to a script file that generates the list (e.g. <script>/usr/lib/foo/list-things</script>,
# or to enable built-in image path completion (<imagePath/>).
completionHelp = element completionHelp
{
(element list { text })* &
(element path { text })* &
(element script { text })*
(element script { text })* &
(element imagePath { empty })?
}
5 changes: 5 additions & 0 deletions schema/op-mode-definition.rng
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<text/>
</element>
</zeroOrMore>
<optional>
<element name="imagePath">
<empty/>
</element>
</optional>
</interleave>
</element>
</define>
Expand Down
7 changes: 7 additions & 0 deletions scripts/build-command-op-templates
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ def get_properties(p):
scripts = c.findall("script")
paths = c.findall("path")
lists = c.findall("list")
comptype = c.find("imagePath")

# Current backend doesn't support multiple allowed: tags
# so we get to emulate it
Expand All @@ -110,8 +111,12 @@ def get_properties(p):
comp_exprs.append("/bin/cli-shell-api listActiveNodes {0} | sed -e \"s/'//g\" && echo".format(i.text))
for i in scripts:
comp_exprs.append("{0}".format(i.text))
if comptype is not None:
props["comp_type"] = "imagefiles"
comp_exprs.append("echo -n \"<imagefiles>\"")
comp_help = " && ".join(comp_exprs)
props["comp_help"] = comp_help

except:
props["comp_help"] = []

Expand All @@ -127,6 +132,8 @@ def make_node_def(props, command):
help = props["help"]
help = fill(help, width=64, subsequent_indent='\t\t\t')
node_def += f'help: {help}\n'
if "comp_type" in props:
node_def += f'comptype: {props["comp_type"]}\n'
if "comp_help" in props:
node_def += f'allowed: {props["comp_help"]}\n'
if command is not None:
Expand Down
43 changes: 43 additions & 0 deletions src/completion/list_images.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env python3
#
# Copyright (C) 2023 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import argparse
import os
import re
import sys

parser = argparse.ArgumentParser(description='list available system images')
parser.add_argument('--no-running', action='store_true',
help='do not display the currently running image')

def get_current_image() -> str:
with open('/proc/cmdline', 'r') as f:
return re.match(r'BOOT_IMAGE=/boot/([^/]+)/vmlinuz', f.readline()).group(1)

def get_images(omit_running: bool = False) -> list[str]:
images = os.listdir("/lib/live/mount/persistence/boot")
# Check if we're running on a live disk
if os.path.isdir("/lib/live/mount/persistence/config") and not omit_running:
images += 'disk-install'
elif omit_running:
images.remove(get_current_image())
images.remove('grub')
return sorted(images)

if __name__ == '__main__':
args = parser.parse_args()
print("\n".join(get_images(omit_running=args.no_running)))
sys.exit(0)
Loading

0 comments on commit 1951f29

Please sign in to comment.