Page Menu
Home
VyOS Platform
Search
Configure Global Search
Log In
Files
F117520771
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
14 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/op-mode-definitions/container.xml.in b/op-mode-definitions/container.xml.in
index ea515fe7c..372786424 100644
--- a/op-mode-definitions/container.xml.in
+++ b/op-mode-definitions/container.xml.in
@@ -1,206 +1,214 @@
<?xml version="1.0"?>
<interfaceDefinition>
<node name="add">
<children>
<node name="container">
<properties>
<help>Add container image</help>
</properties>
<children>
<tagNode name="image">
<properties>
<help>Pull a new image for container</help>
</properties>
<command>${vyos_op_scripts_dir}/container.py add_image --name "${4}"</command>
</tagNode>
</children>
</node>
</children>
</node>
<node name="connect">
<children>
<tagNode name="container">
<properties>
<help>Attach to a running container</help>
<completionHelp>
<path>container name</path>
</completionHelp>
</properties>
<command>podman exec --interactive --tty "$3" /bin/sh</command>
</tagNode>
</children>
</node>
<node name="delete">
<children>
<node name="container">
<properties>
<help>Delete container image</help>
</properties>
<children>
<tagNode name="image">
<properties>
<help>Delete container image</help>
<completionHelp>
<list>all</list>
<script>sudo bash -c 'podman image ls -q'</script>
</completionHelp>
</properties>
<command>${vyos_op_scripts_dir}/container.py delete_image --name "${4}"</command>
+ <children>
+ <leafNode name="force">
+ <properties>
+ <help>Force removal of container image</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/container.py delete_image --name "${4}" --force</command>
+ </leafNode>
+ </children>
</tagNode>
</children>
</node>
</children>
</node>
<node name="generate">
<children>
<node name="container">
<properties>
<help>Generate Container Image</help>
</properties>
<children>
<tagNode name="image">
<properties>
<help>Name of container image (tag)</help>
</properties>
<children>
<tagNode name="path">
<properties>
<help>Path to Dockerfile</help>
<completionHelp>
<list><filename></list>
</completionHelp>
</properties>
<command>podman build --net host --layers --force-rm --tag "$4" $6</command>
</tagNode>
</children>
</tagNode>
</children>
</node>
</children>
</node>
<node name="monitor">
<children>
<node name="log">
<children>
<tagNode name="container">
<properties>
<help>Monitor last lines of container log</help>
<completionHelp>
<path>container name</path>
</completionHelp>
</properties>
<command>${vyos_op_scripts_dir}/container.py show_log --follow --name "$4"</command>
</tagNode>
</children>
</node>
</children>
</node>
<node name="show">
<children>
<node name="container">
<properties>
<help>Show containers</help>
</properties>
<command>${vyos_op_scripts_dir}/container.py show_container</command>
<children>
<node name="json">
<properties>
<help>Show containers in JSON format</help>
</properties>
<!-- no admin check -->
<command>${vyos_op_scripts_dir}/container.py show_container --raw</command>
</node>
<node name="image">
<properties>
<help>Show container image</help>
</properties>
<command>${vyos_op_scripts_dir}/container.py show_image</command>
<children>
<node name="json">
<properties>
<help>Show container image in JSON format</help>
</properties>
<!-- no admin check -->
<command>${vyos_op_scripts_dir}/container.py show_image --raw</command>
</node>
</children>
</node>
<tagNode name="log">
<properties>
<help>Show logs from a given container</help>
<completionHelp>
<path>container name</path>
</completionHelp>
</properties>
<command>${vyos_op_scripts_dir}/container.py show_log --name "$4"</command>
</tagNode>
<node name="network">
<properties>
<help>Show available container networks</help>
</properties>
<!-- no admin check -->
<command>${vyos_op_scripts_dir}/container.py show_network</command>
<children>
<node name="json">
<properties>
<help>Show available container networks in JSON format</help>
</properties>
<!-- no admin check -->
<command>${vyos_op_scripts_dir}/container.py show_network --raw</command>
</node>
</children>
</node>
</children>
</node>
<node name="log">
<children>
<tagNode name="container">
<properties>
<help>Show logs from a given container</help>
<completionHelp>
<path>container name</path>
</completionHelp>
</properties>
<command>${vyos_op_scripts_dir}/container.py show_log --name "$4"</command>
</tagNode>
</children>
</node>
</children>
</node>
<node name="restart">
<children>
<tagNode name="container">
<properties>
<help>Restart a given container</help>
<completionHelp>
<path>container name</path>
</completionHelp>
</properties>
<command>${vyos_op_scripts_dir}/container.py restart --name="$3"</command>
</tagNode>
</children>
</node>
<node name="update">
<properties>
<help>Update data for a service</help>
</properties>
<children>
<node name="container">
<properties>
<help>Update a container image</help>
</properties>
<children>
<tagNode name="image">
<properties>
<help>Update container image</help>
<completionHelp>
<path>container name</path>
</completionHelp>
</properties>
<command>bash -c 'if cli-shell-api existsActive container name "'$4'"; then podman pull $(cli-shell-api returnActiveValue container name "'$4'" image); else echo "Container '$4' does not exist"; fi'</command>
</tagNode>
</children>
</node>
</children>
</node>
</interfaceDefinition>
diff --git a/src/op_mode/container.py b/src/op_mode/container.py
index fe81636d2..feb9f41cc 100755
--- a/src/op_mode/container.py
+++ b/src/op_mode/container.py
@@ -1,162 +1,184 @@
#!/usr/bin/env python3
#
# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 typing
import json
import sys
import subprocess
from vyos.utils.process import cmd
from vyos.utils.process import rc_cmd
import vyos.opmode
def _get_json_data(command: str) -> list:
"""
Get container command format JSON
"""
return cmd(f'{command} --format json')
def _get_raw_data(command: str) -> list:
json_data = _get_json_data(command)
data = json.loads(json_data)
return data
def add_image(name: str):
""" Pull image from container registry. If registry authentication
is defined within VyOS CLI, credentials are used to login befroe pull """
from vyos.configquery import ConfigTreeQuery
conf = ConfigTreeQuery()
container = conf.get_config_dict(['container', 'registry'])
do_logout = False
if 'registry' in container:
for registry, registry_config in container['registry'].items():
if 'disable' in registry_config:
continue
if 'authentication' in registry_config:
do_logout = True
if {'username', 'password'} <= set(registry_config['authentication']):
username = registry_config['authentication']['username']
password = registry_config['authentication']['password']
cmd = f'podman login --username {username} --password {password} {registry}'
rc, out = rc_cmd(cmd)
if rc != 0: raise vyos.opmode.InternalError(out)
rc, output = rc_cmd(f'podman image pull {name}')
print(output)
if rc != 0:
raise vyos.opmode.InternalError(output)
if do_logout:
rc_cmd('podman logout --all')
-def delete_image(name: str):
+def delete_image(name: str, force: typing.Optional[bool] = False):
from vyos.utils.process import rc_cmd
if name == 'all':
# gather list of all images and pass them to the removal list
name = cmd('sudo podman image ls --quiet')
# If there are no container images left, we can not delete them all
if not name: return
# replace newline with whitespace
name = name.replace('\n', ' ')
- rc, output = rc_cmd(f'podman image rm {name}')
- if rc != 0:
- raise vyos.opmode.InternalError(output)
+ # convert to list
+ name = name.split()
+
+ for image in name:
+ # convert the truncated image ID to a full image ID
+ rc, ancestor = rc_cmd(f'podman inspect {image} --format "{{{{.Id}}}}"')
+ if rc != 0:
+ raise vyos.opmode.InternalError(ancestor)
+ # check if the image ID is an ancestor of any running container
+ rc, in_use = rc_cmd(f'podman ps --filter ancestor={ancestor} -q')
+ if rc != 0:
+ raise vyos.opmode.InternalError(in_use)
+
+ if bool(in_use):
+ error = f'Cannot delete image "{image}" because it is currently '\
+ f'being used by container "{in_use}"!'
+ raise vyos.opmode.InternalError(error)
+
+ tmp = f'podman image rm {image}'
+ if force: tmp += ' --force'
+
+ rc, output = rc_cmd(tmp)
+ if rc != 0:
+ raise vyos.opmode.InternalError(output)
def show_container(raw: bool):
command = 'podman ps --all'
container_data = _get_raw_data(command)
if raw:
return container_data
else:
return cmd(command)
def show_image(raw: bool):
command = 'podman image ls'
container_data = _get_raw_data('podman image ls')
if raw:
return container_data
else:
return cmd(command)
def show_network(raw: bool):
command = 'podman network ls'
container_data = _get_raw_data(command)
if raw:
return container_data
else:
return cmd(command)
def restart(name: str):
from vyos.utils.process import rc_cmd
rc, output = rc_cmd(f'systemctl restart vyos-container-{name}.service')
if rc != 0:
print(output)
return None
print(f'Container "{name}" restarted!')
return output
def show_log(name: str, follow: bool = False, raw: bool = False):
"""
Show or monitor logs for a specific container.
Use --follow to continuously stream logs.
"""
from vyos.configquery import ConfigTreeQuery
conf = ConfigTreeQuery()
container = conf.get_config_dict(['container', 'name', name], get_first_key=True, with_recursive_defaults=True)
log_type = container.get('log-driver')
if log_type == 'k8s-file':
if follow:
log_command_list = ['sudo', 'podman', 'logs', '--follow', '--names', name]
else:
log_command_list = ['sudo', 'podman', 'logs', '--names', name]
elif log_type == 'journald':
if follow:
log_command_list = ['journalctl', '--follow', '--unit', f'vyos-container-{name}.service']
else:
log_command_list = ['journalctl', '-e', '--no-pager', '--unit', f'vyos-container-{name}.service']
elif log_type == 'none':
print(f'Container "{name}" has disabled logs.')
return None
else:
raise vyos.opmode.InternalError(f'Unknown log type "{log_type}" for container "{name}".')
process = None
try:
process = subprocess.Popen(log_command_list,
stdout=sys.stdout,
stderr=sys.stderr)
process.wait()
except KeyboardInterrupt:
if process:
process.terminate()
process.wait()
return None
except Exception as e:
raise vyos.opmode.InternalError(f"Error starting logging command: {e} ")
return None
if __name__ == '__main__':
try:
res = vyos.opmode.run(sys.modules[__name__])
if res:
print(res)
except (ValueError, vyos.opmode.Error) as e:
print(e)
sys.exit(1)
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Sep 26, 12:09 PM (1 d, 20 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4285110
Default Alt Text
(14 KB)
Attached To
Mode
rVYOSONEX vyos-1x
Attached
Detach File
Event Timeline
Log In to Comment