mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-11-01 18:32:13 +00:00
paste an oci-compose in the terminal
- "Install an image that is not in the catalog" also takes an oci-compose pasted in the terminal, next to reading it from a file or downloading it from an address. - oci/README.md and the documentation page of the option describe the three ways, and the README links to the thread for suggesting applications (#440). - oci/VALIDATION.md points to discussion #440 instead of the closed #360. - The oci-compose tests pass on a host set to another language and without python3-jsonschema.
This commit is contained in:
@@ -19,7 +19,7 @@ REVIEWERS = ROOT / ".github/oci-validation-reviewers"
|
|||||||
REPO = "https://github.com/MacRimi/ProxMenux"
|
REPO = "https://github.com/MacRimi/ProxMenux"
|
||||||
BOARD = "https://github.com/users/MacRimi/projects/1"
|
BOARD = "https://github.com/users/MacRimi/projects/1"
|
||||||
FORM = f"{REPO}/issues/new?template=oci-validation.yml"
|
FORM = f"{REPO}/issues/new?template=oci-validation.yml"
|
||||||
DISCUSSION = f"{REPO}/discussions/360"
|
DISCUSSION = f"{REPO}/discussions/440"
|
||||||
MAINTAINERS = {"macrimi"}
|
MAINTAINERS = {"macrimi"}
|
||||||
LAB = "laboratory-validated"
|
LAB = "laboratory-validated"
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ def render(verification, index):
|
|||||||
"only Docker provides, a fix still pending in ProxMenux — moves to Blocked on the board, with a line saying why "
|
"only Docker provides, a fix still pending in ProxMenux — moves to Blocked on the board, with a line saying why "
|
||||||
"and what would make it worth trying again.",
|
"and what would make it worth trying again.",
|
||||||
"",
|
"",
|
||||||
f"Questions and ideas about OCI testing go in [discussion #360]({DISCUSSION}).",
|
f"Questions and ideas about OCI testing go in [discussion #440]({DISCUSSION}).",
|
||||||
"",
|
"",
|
||||||
"## Tested by the community",
|
"## Tested by the community",
|
||||||
"",
|
"",
|
||||||
|
|||||||
@@ -4186,6 +4186,7 @@
|
|||||||
"No network configuration backups found.": "No se encontraron backups de la configuración de red.",
|
"No network configuration backups found.": "No se encontraron backups de la configuración de red.",
|
||||||
"No network interfaces configured (besides loopback)": "No hay interfaces de red configuradas (aparte del loopback)",
|
"No network interfaces configured (besides loopback)": "No hay interfaces de red configuradas (aparte del loopback)",
|
||||||
"No new Controller/NVMe entries were added.": "No se agregaron nuevas entradas de Controlador/NVMe.",
|
"No new Controller/NVMe entries were added.": "No se agregaron nuevas entradas de Controlador/NVMe.",
|
||||||
|
"No oci-compose was given": "No se dio ningún oci-compose",
|
||||||
"No online node has a guest of this job.": "Ningún nodo en línea tiene una VM o CT de este trabajo.",
|
"No online node has a guest of this job.": "Ningún nodo en línea tiene una VM o CT de este trabajo.",
|
||||||
"No optimizations detected to uninstall.": "No se detectaron optimizaciones para desinstalar.",
|
"No optimizations detected to uninstall.": "No se detectaron optimizaciones para desinstalar.",
|
||||||
"No other storage of this host that accepts backups has that much free space. Free space and try again; the application was not modified.": "Ningún otro almacenamiento de este host que acepte backups tiene tanto espacio libre. Libera espacio e inténtalo de nuevo; la aplicación no se ha modificado.",
|
"No other storage of this host that accepts backups has that much free space. Free space and try again; the application was not modified.": "Ningún otro almacenamiento de este host que acepte backups tiene tanto espacio libre. Libera espacio e inténtalo de nuevo; la aplicación no se ha modificado.",
|
||||||
@@ -4541,6 +4542,7 @@
|
|||||||
"Password reset completed.": "Restablecimiento de contraseña completado.",
|
"Password reset completed.": "Restablecimiento de contraseña completado.",
|
||||||
"Password to access the aMule web interface": "Contraseña para acceder a la interfaz web de aMule",
|
"Password to access the aMule web interface": "Contraseña para acceder a la interfaz web de aMule",
|
||||||
"Passwords do not match. Please try again.": "Las contraseñas no coinciden. Por favor inténtalo de nuevo.",
|
"Passwords do not match. Please try again.": "Las contraseñas no coinciden. Por favor inténtalo de nuevo.",
|
||||||
|
"Paste an oci-compose in the terminal": "Pegar un oci-compose en la terminal",
|
||||||
"Paste it here and press Ctrl+D on an empty line.": "Pégalo aquí y pulsa Ctrl+D en una línea vacía.",
|
"Paste it here and press Ctrl+D on an empty line.": "Pégalo aquí y pulsa Ctrl+D en una línea vacía.",
|
||||||
"Paste its Compose file in the terminal": "Pegar su archivo Compose en la terminal",
|
"Paste its Compose file in the terminal": "Pegar su archivo Compose en la terminal",
|
||||||
"Paste its docker run command in the terminal": "Pegar su comando docker run en la terminal",
|
"Paste its docker run command in the terminal": "Pegar su comando docker run en la terminal",
|
||||||
@@ -7759,6 +7761,7 @@
|
|||||||
"nvidia-smi not found after install. Check log:": "nvidia-smi no se encuentra tras la instalación. Revise el log:",
|
"nvidia-smi not found after install. Check log:": "nvidia-smi no se encuentra tras la instalación. Revise el log:",
|
||||||
"nvidia-smi not found in PATH. Please verify the driver installation.": "nvidia-smi no encontrado en RUTA. Verifique la instalación del controlador.",
|
"nvidia-smi not found in PATH. Please verify the driver installation.": "nvidia-smi no encontrado en RUTA. Verifique la instalación del controlador.",
|
||||||
"nvidia-smi not found in container": "nvidia-smi no encontrado en el contenedor",
|
"nvidia-smi not found in container": "nvidia-smi no encontrado en el contenedor",
|
||||||
|
"oci-compose of the application": "oci-compose de la aplicación",
|
||||||
"of": "de",
|
"of": "de",
|
||||||
"of free disk space.": "de espacio libre en disco.",
|
"of free disk space.": "de espacio libre en disco.",
|
||||||
"older firmware may increase passthrough instability": "un firmware antiguo puede aumentar la inestabilidad del passthrough",
|
"older firmware may increase passthrough instability": "un firmware antiguo puede aumentar la inestabilidad del passthrough",
|
||||||
|
|||||||
+3
-3
@@ -441,9 +441,9 @@ What the author writes always wins over what is added.
|
|||||||
## Writing and testing an oci-compose
|
## Writing and testing an oci-compose
|
||||||
|
|
||||||
1. **Write the file.** Start from one of the [`examples/`](examples/) or from the smallest file above, and add the blocks the application needs. Any file of `catalog/apps/` or `catalog/curated/` is also a valid starting point.
|
1. **Write the file.** Start from one of the [`examples/`](examples/) or from the smallest file above, and add the blocks the application needs. Any file of `catalog/apps/` or `catalog/curated/` is also a valid starting point.
|
||||||
2. **Copy it to the node**, for example to `/root/oci-compose.json`, or publish it where the node can download it.
|
2. **Take it to the node.** It can be pasted in the terminal, copied to the node, for example to `/root/oci-compose.json`, or published where the node can download it.
|
||||||
3. **Open OCI manager Apps** from the ProxMenux menu and choose *Install an image that is not in the catalog*.
|
3. **Open OCI manager Apps** from the ProxMenux menu and choose *Install an image that is not in the catalog*.
|
||||||
4. **Choose how it is given**: *Read an oci-compose from a file of this host* or *Download an oci-compose from an address*.
|
4. **Choose how it is given**: *Paste an oci-compose in the terminal*, *Read an oci-compose from a file of this host* or *Download an oci-compose from an address*.
|
||||||
5. **Read the result.** A file with errors is not installed, and each error names the field:
|
5. **Read the result.** A file with errors is not installed, and each error names the field:
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -475,7 +475,7 @@ python3 -m unittest discover -s tests -p 'test_*.py'
|
|||||||
|
|
||||||
An application reaches the catalog in three steps.
|
An application reaches the catalog in three steps.
|
||||||
|
|
||||||
1. **Suggest it** in [Discussions](https://github.com/MacRimi/ProxMenux/discussions) with the image, the registry it is published in and the category.
|
1. **Suggest it** in the thread [Suggest an application for the OCI catalog](https://github.com/MacRimi/ProxMenux/discussions/440) with the image, the registry it is published in and the category.
|
||||||
2. **Try it.** Installing it from its Compose file or its `docker run` command shows whether the image runs as a native LXC. When it needs something Compose cannot say, an oci-compose written by hand lets that be tested as well. The file that worked, attached to the suggestion, is what the entry of the catalog is written from.
|
2. **Try it.** Installing it from its Compose file or its `docker run` command shows whether the image runs as a native LXC. When it needs something Compose cannot say, an oci-compose written by hand lets that be tested as well. The file that worked, attached to the suggestion, is what the entry of the catalog is written from.
|
||||||
3. **Validate it.** An application tested for real is recorded in `catalog/verification.json` and shown as verified in the installer. [VALIDATION.md](VALIDATION.md) lists the verified applications and describes a test: install, check that it works, restart, update and remove.
|
3. **Validate it.** An application tested for real is recorded in `catalog/verification.json` and shown as verified in the installer. [VALIDATION.md](VALIDATION.md) lists the verified applications and describes a test: install, check that it works, restart, update and remove.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ Reviewers are listed in [.github/oci-validation-reviewers](../.github/oci-valida
|
|||||||
|
|
||||||
An application that cannot be validated for a reason outside the tester's hands — hardware nobody has, something only Docker provides, a fix still pending in ProxMenux — moves to Blocked on the board, with a line saying why and what would make it worth trying again.
|
An application that cannot be validated for a reason outside the tester's hands — hardware nobody has, something only Docker provides, a fix still pending in ProxMenux — moves to Blocked on the board, with a line saying why and what would make it worth trying again.
|
||||||
|
|
||||||
Questions and ideas about OCI testing go in [discussion #360](https://github.com/MacRimi/ProxMenux/discussions/360).
|
Questions and ideas about OCI testing go in [discussion #440](https://github.com/MacRimi/ProxMenux/discussions/440).
|
||||||
|
|
||||||
## Tested by the community
|
## Tested by the community
|
||||||
|
|
||||||
|
|||||||
@@ -454,16 +454,16 @@ def describe_oci_compose(template: dict[str, Any]) -> str:
|
|||||||
return '\n' + '\n'.join(lines)
|
return '\n' + '\n'.join(lines)
|
||||||
|
|
||||||
|
|
||||||
def _read_pasted(ui, title: str | None = None) -> str:
|
def _read_pasted(ui, title: str | None = None, limit: int = MAX_COMPOSE_BYTES, missing: str | None = None) -> str:
|
||||||
"""The definition is pasted in the terminal: dialog cannot take it."""
|
"""The definition is pasted in the terminal: dialog cannot take it."""
|
||||||
console.show_logo()
|
console.show_logo()
|
||||||
console.msg_title(title or translate('Compose file of the application'))
|
console.msg_title(title or translate('Compose file of the application'))
|
||||||
console.msg_info2(translate('Paste it here and press Ctrl+D on an empty line.'))
|
console.msg_info2(translate('Paste it here and press Ctrl+D on an empty line.'))
|
||||||
print()
|
print()
|
||||||
text = sys.stdin.read(MAX_COMPOSE_BYTES + 1)
|
text = sys.stdin.read(limit + 1)
|
||||||
if not text.strip():
|
if not text.strip():
|
||||||
raise UserCancelled(translate('No docker run command was given') if title is not None
|
raise UserCancelled(missing or (translate('No docker run command was given') if title is not None
|
||||||
else translate('No Compose file was given'))
|
else translate('No Compose file was given')))
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
@@ -477,11 +477,15 @@ def read_definition(ui) -> tuple[str, str]:
|
|||||||
('url', translate('Download its Compose file from an address')),
|
('url', translate('Download its Compose file from an address')),
|
||||||
('run', translate('Paste its docker run command in the terminal')),
|
('run', translate('Paste its docker run command in the terminal')),
|
||||||
('image', translate('Only the image reference, with no Compose file')),
|
('image', translate('Only the image reference, with no Compose file')),
|
||||||
|
('oci-compose-paste', translate('Paste an oci-compose in the terminal')),
|
||||||
('oci-compose', translate('Read an oci-compose from a file of this host')),
|
('oci-compose', translate('Read an oci-compose from a file of this host')),
|
||||||
('oci-compose-url', translate('Download an oci-compose from an address')),
|
('oci-compose-url', translate('Download an oci-compose from an address')),
|
||||||
], 'paste', title=translate('Image that is not in the catalog'), size=MENU_SIZE)
|
], 'paste', title=translate('Image that is not in the catalog'), size=MENU_SIZE)
|
||||||
if source is None:
|
if source is None:
|
||||||
raise UserCancelled(translate('Image selection was cancelled'))
|
raise UserCancelled(translate('Image selection was cancelled'))
|
||||||
|
if source == 'oci-compose-paste':
|
||||||
|
return _read_pasted(ui, translate('oci-compose of the application'), MAX_OCI_COMPOSE_BYTES,
|
||||||
|
translate('No oci-compose was given')), OCI_COMPOSE
|
||||||
if source == 'oci-compose':
|
if source == 'oci-compose':
|
||||||
return _read_file(ui.ask(translate('Path of the oci-compose file'), '/root/oci-compose.json'),
|
return _read_file(ui.ask(translate('Path of the oci-compose file'), '/root/oci-compose.json'),
|
||||||
MAX_OCI_COMPOSE_BYTES), OCI_COMPOSE
|
MAX_OCI_COMPOSE_BYTES), OCI_COMPOSE
|
||||||
|
|||||||
@@ -4,20 +4,24 @@ catalog, or the record of an installed application, of which only the template
|
|||||||
is read."""
|
is read."""
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
import io
|
||||||
import json
|
import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
from types import SimpleNamespace
|
||||||
import unittest
|
import unittest
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[1]
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
sys.path.insert(0, str(ROOT / "src"))
|
sys.path.insert(0, str(ROOT / "src"))
|
||||||
|
|
||||||
from proxmenux_oci import custom
|
from proxmenux_oci import custom, i18n
|
||||||
from proxmenux_oci.catalog import Catalog
|
from proxmenux_oci.catalog import Catalog
|
||||||
from proxmenux_oci.converter import ConversionError
|
from proxmenux_oci.converter import ConversionError
|
||||||
|
|
||||||
|
# The messages are compared in English, also on a host set to another language.
|
||||||
|
i18n._language = "en"
|
||||||
CATALOG = Catalog(ROOT)
|
CATALOG = Catalog(ROOT)
|
||||||
EXAMPLES = ("jellyfin-official", "duplicati-official")
|
EXAMPLES = ("jellyfin-official", "duplicati-official")
|
||||||
# Fields that describe where a template came from and are not read to install it.
|
# Fields that describe where a template came from and are not read to install it.
|
||||||
@@ -129,7 +133,7 @@ class HandWrittenTests(unittest.TestCase):
|
|||||||
self.assertEqual(template["first_run"], catalog["first_run"])
|
self.assertEqual(template["first_run"], catalog["first_run"])
|
||||||
self.assertEqual(template["catalog_ui"]["category_label"], catalog["catalog_ui"]["category_label"])
|
self.assertEqual(template["catalog_ui"]["category_label"], catalog["catalog_ui"]["category_label"])
|
||||||
self.assertTrue(template["compatibility"]["automatic_install_candidate"])
|
self.assertTrue(template["compatibility"]["automatic_install_candidate"])
|
||||||
self.assertEqual(CATALOG.schema_errors(template), [])
|
self.assertEqual(custom._errors(template), [])
|
||||||
|
|
||||||
def test_the_least_an_oci_compose_says_is_its_image(self):
|
def test_the_least_an_oci_compose_says_is_its_image(self):
|
||||||
template = custom.template_from_oci_compose(json.dumps(
|
template = custom.template_from_oci_compose(json.dumps(
|
||||||
@@ -137,7 +141,7 @@ class HandWrittenTests(unittest.TestCase):
|
|||||||
self.assertEqual(template["container_contract"]["image"]["repository"], "traefik/whoami")
|
self.assertEqual(template["container_contract"]["image"]["repository"], "traefik/whoami")
|
||||||
self.assertEqual(template["catalog_ui"]["title"], {"en_US": "whoami"})
|
self.assertEqual(template["catalog_ui"]["title"], {"en_US": "whoami"})
|
||||||
self.assertEqual(template["container_contract"]["volumes"], [])
|
self.assertEqual(template["container_contract"]["volumes"], [])
|
||||||
self.assertEqual(CATALOG.schema_errors(template), [])
|
self.assertEqual(custom._errors(template), [])
|
||||||
|
|
||||||
def test_what_the_author_writes_is_kept(self):
|
def test_what_the_author_writes_is_kept(self):
|
||||||
document = json.loads(example("duplicati-official"))
|
document = json.loads(example("duplicati-official"))
|
||||||
@@ -229,10 +233,23 @@ class MenuTests(unittest.TestCase):
|
|||||||
path.write_text(example("jellyfin-official"), encoding="utf-8")
|
path.write_text(example("jellyfin-official"), encoding="utf-8")
|
||||||
ui = FakeUI(["oci-compose"], [str(path)])
|
ui = FakeUI(["oci-compose"], [str(path)])
|
||||||
text, origin = custom.read_definition(ui)
|
text, origin = custom.read_definition(ui)
|
||||||
self.assertEqual(ui.offered[0][-2:], ["oci-compose", "oci-compose-url"])
|
self.assertEqual(ui.offered[0][-3:], ["oci-compose-paste", "oci-compose", "oci-compose-url"])
|
||||||
self.assertEqual(origin, custom.OCI_COMPOSE)
|
self.assertEqual(origin, custom.OCI_COMPOSE)
|
||||||
self.assertEqual(json.loads(text)["catalog_ui"]["title"], {"en_US": "Jellyfin Official"})
|
self.assertEqual(json.loads(text)["catalog_ui"]["title"], {"en_US": "Jellyfin Official"})
|
||||||
|
|
||||||
|
def test_an_oci_compose_can_be_pasted_in_the_terminal(self):
|
||||||
|
quiet = SimpleNamespace(show_logo=lambda: None, msg_title=lambda *_: None, msg_info2=lambda *_: None)
|
||||||
|
with patch.object(custom, "console", quiet), patch("builtins.print"), \
|
||||||
|
patch.object(custom.sys, "stdin", io.StringIO(example("duplicati-official"))):
|
||||||
|
text, origin = custom.read_definition(FakeUI(["oci-compose-paste"]))
|
||||||
|
self.assertEqual(origin, custom.OCI_COMPOSE)
|
||||||
|
self.assertEqual(custom.template_from_oci_compose(text)["catalog_ui"]["title"], {"en_US": "Duplicati Official"})
|
||||||
|
with patch.object(custom, "console", quiet), patch("builtins.print"), \
|
||||||
|
patch.object(custom.sys, "stdin", io.StringIO(" \n")):
|
||||||
|
with self.assertRaises(custom.UserCancelled) as raised:
|
||||||
|
custom.read_definition(FakeUI(["oci-compose-paste"]))
|
||||||
|
self.assertEqual(str(raised.exception), "No oci-compose was given")
|
||||||
|
|
||||||
def test_an_oci_compose_keeps_its_name_and_its_own_questions(self):
|
def test_an_oci_compose_keeps_its_name_and_its_own_questions(self):
|
||||||
with tempfile.TemporaryDirectory() as folder:
|
with tempfile.TemporaryDirectory() as folder:
|
||||||
path = Path(folder) / "oci-compose.json"
|
path = Path(folder) / "oci-compose.json"
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
{
|
{
|
||||||
"id": "sources",
|
"id": "sources",
|
||||||
"title": "How the image is described",
|
"title": "How the image is described",
|
||||||
"intro": "The first screen asks how the image is described. Four ways give a definition that is translated, a fifth uses only the image name, and two read an oci-compose that is already written.",
|
"intro": "The first screen asks how the image is described. Four ways give a definition that is translated, a fifth uses only the image name, and three take an oci-compose that is already written.",
|
||||||
"blocks": [
|
"blocks": [
|
||||||
{
|
{
|
||||||
"table": {
|
"table": {
|
||||||
@@ -34,7 +34,8 @@
|
|||||||
["Download its Compose file from an address", "An <code>http://</code> or <code>https://</code> address that serves the raw YAML. At most 256 KiB are downloaded."],
|
["Download its Compose file from an address", "An <code>http://</code> or <code>https://</code> address that serves the raw YAML. At most 256 KiB are downloaded."],
|
||||||
["Paste its docker run command in the terminal", "The command published by the project. Ports, environment, volumes, devices, capabilities, user, shared memory and the other supported options are translated."],
|
["Paste its docker run command in the terminal", "The command published by the project. Ports, environment, volumes, devices, capabilities, user, shared memory and the other supported options are translated."],
|
||||||
["Only the image reference, with no Compose file", "A reference such as <code>ghcr.io/user/application:latest</code>. The registry is queried and the OCI metadata of the image is kept."],
|
["Only the image reference, with no Compose file", "A reference such as <code>ghcr.io/user/application:latest</code>. The registry is queried and the OCI metadata of the image is kept."],
|
||||||
["Read an oci-compose from a file of this host", "A JSON file on the node, <code>/root/oci-compose.json</code> by default, of at most 2 MiB. It is not translated: it is checked and installed as it is written."],
|
["Paste an oci-compose in the terminal", "The JSON is pasted in the terminal and ends with Ctrl+D on an empty line. It is not translated: it is checked and installed as it is written."],
|
||||||
|
["Read an oci-compose from a file of this host", "A JSON file on the node, <code>/root/oci-compose.json</code> by default, of at most 2 MiB."],
|
||||||
["Download an oci-compose from an address", "An <code>http://</code> or <code>https://</code> address that serves the JSON file. At most 2 MiB are downloaded."]
|
["Download an oci-compose from an address", "An <code>http://</code> or <code>https://</code> address that serves the JSON file. At most 2 MiB are downloaded."]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
{
|
{
|
||||||
"id": "sources",
|
"id": "sources",
|
||||||
"title": "Cómo se describe la imagen",
|
"title": "Cómo se describe la imagen",
|
||||||
"intro": "La primera pantalla pregunta cómo se describe la imagen. Cuatro formas aportan una definición que se traduce, una quinta usa solo el nombre de la imagen y dos leen un oci-compose ya escrito.",
|
"intro": "La primera pantalla pregunta cómo se describe la imagen. Cuatro formas aportan una definición que se traduce, una quinta usa solo el nombre de la imagen y tres reciben un oci-compose ya escrito.",
|
||||||
"blocks": [
|
"blocks": [
|
||||||
{
|
{
|
||||||
"table": {
|
"table": {
|
||||||
@@ -34,7 +34,8 @@
|
|||||||
["Descargar su archivo Compose desde una dirección", "Una dirección <code>http://</code> o <code>https://</code> que sirva el YAML sin procesar. Se descargan como máximo 256 KiB."],
|
["Descargar su archivo Compose desde una dirección", "Una dirección <code>http://</code> o <code>https://</code> que sirva el YAML sin procesar. Se descargan como máximo 256 KiB."],
|
||||||
["Pegar su comando docker run en la terminal", "El comando que publica el proyecto. Se traducen puertos, entorno, volúmenes, dispositivos, capacidades, usuario, memoria compartida y el resto de opciones admitidas."],
|
["Pegar su comando docker run en la terminal", "El comando que publica el proyecto. Se traducen puertos, entorno, volúmenes, dispositivos, capacidades, usuario, memoria compartida y el resto de opciones admitidas."],
|
||||||
["Solo la referencia de la imagen, sin archivo Compose", "Una referencia como <code>ghcr.io/user/application:latest</code>. Se consulta el registro y se conservan los metadatos OCI de la imagen."],
|
["Solo la referencia de la imagen, sin archivo Compose", "Una referencia como <code>ghcr.io/user/application:latest</code>. Se consulta el registro y se conservan los metadatos OCI de la imagen."],
|
||||||
["Leer un oci-compose desde un archivo de este host", "Un archivo JSON del nodo, <code>/root/oci-compose.json</code> por defecto, de 2 MiB como máximo. No se traduce: se comprueba y se instala tal como está escrito."],
|
["Pegar un oci-compose en la terminal", "El JSON se pega en la terminal y termina con Ctrl+D en una línea vacía. No se traduce: se comprueba y se instala tal como está escrito."],
|
||||||
|
["Leer un oci-compose desde un archivo de este host", "Un archivo JSON del nodo, <code>/root/oci-compose.json</code> por defecto, de 2 MiB como máximo."],
|
||||||
["Descargar un oci-compose desde una dirección", "Una dirección <code>http://</code> o <code>https://</code> que sirva el archivo JSON. Se descargan como máximo 2 MiB."]
|
["Descargar un oci-compose desde una dirección", "Una dirección <code>http://</code> o <code>https://</code> que sirva el archivo JSON. Se descargan como máximo 2 MiB."]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user