New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
xrv9k slow boot #184
Comments
I have done some testing around this, and indeed doing an "install" procedure can cut the boot time by roughly half(~11 minutes in my testing). Here are my observations:
my patch looks like this:
i can submit a pull request if there is interest and this looks ok. |
Hi @bdreisbach |
i guess manually, in launch.py i called XRV_installer with 1 vs args.nics |
I tried to apply this patch and used 7.2.1 Seems like it doesn't work for me for because prompt doesn't match the expected string...:
for comparison, that is the successful log without install:
|
So, I gave it a try. It works for me with 7.2.2 but it redoes the whole installation. The fact that each try is so slow makes it a bit difficult to iterate. From 1e8b4127a599dd1e43531c907aa721be01aa9a57 Mon Sep 17 00:00:00 2001
From: Vincent Bernat <vincent@bernat.ch>
Date: Mon, 20 Sep 2021 10:12:29 +0200
Subject: [PATCH] WIP
---
xrv9k/Makefile | 1 +
xrv9k/docker/launch.py | 97 ++++++++++++++++++++++++++++++++++++------
2 files changed, 86 insertions(+), 12 deletions(-)
diff --git a/xrv9k/Makefile b/xrv9k/Makefile
index 40f7df5723c0..f9ad59df6b75 100644
--- a/xrv9k/Makefile
+++ b/xrv9k/Makefile
@@ -11,3 +11,4 @@ VERSION=$(shell echo $(IMAGE) | sed -e 's/.\+[^0-9]\([0-9]\.[0-9]\.[0-9]\(\.[0-9
-include ../makefile-sanity.include
-include ../makefile.include
+-include ../makefile-install.include
diff --git a/xrv9k/docker/launch.py b/xrv9k/docker/launch.py
index 69d28437aa6f..a8f534951741 100755
--- a/xrv9k/docker/launch.py
+++ b/xrv9k/docker/launch.py
@@ -7,6 +7,7 @@
import signal
import sys
import time
+import subprocess
import vrnetlab
@@ -38,7 +39,17 @@ def trace(self, message, *args, **kws):
class XRV_vm(vrnetlab.VM):
- def __init__(self, hostname, username, password, nics, conn_mode, vcpu, ram):
+ def __init__(
+ self,
+ hostname,
+ username,
+ password,
+ nics,
+ conn_mode,
+ vcpu,
+ ram,
+ install_mode=False,
+ ):
disk_image = ""
for e in os.listdir("/"):
if re.search(".qcow2", e):
@@ -47,6 +58,7 @@ def __init__(self, hostname, username, password, nics, conn_mode, vcpu, ram):
self.hostname = hostname
self.conn_mode = conn_mode
self.num_nics = nics
+ self.install_mode = install_mode
self.qemu_args.extend(
[
"-cpu",
@@ -111,7 +123,7 @@ def gen_mgmt(self):
return res
def bootstrap_spin(self):
- """"""
+ """ """
if self.spins > 600:
# too many spins with no result -> give up
@@ -162,6 +174,19 @@ def bootstrap_spin(self):
self.wait_write(password, wait="Password:")
self.logger.debug("logged in with %s / %s" % (username, password))
if self.xr_ready is True and ridx == 4:
+ if self.install_mode:
+ # wait for the baking process to complete
+ self.logger.debug("install completed, shutting down device")
+ self.logger.info("requesting power-off")
+ self.wait_write("", None)
+ self.wait_write("conf t")
+ self.wait_write("commit replace best-effort")
+ self.wait_write("yes", "Do you wish to proceed? [no]")
+ self.wait_write("exit")
+ self.wait_write("admin hw-module location 0/RP0 shutdown", "#")
+ self.wait_write("yes", "Shutdown hardware module ? [no,yes]")
+ self.running = True
+ return
# run main config!
if not self.bootstrap_config():
# main config failed :/
@@ -220,10 +245,6 @@ def bootstrap_config(self):
if not self._wait_config("show interfaces description", "Gi0/0/0/0"):
return False
- # wait for call-home in config
- if not self._wait_config("show running-config call-home", "service active"):
- return False
-
self.wait_write("configure")
self.wait_write(f"hostname {self.hostname}")
# configure netconf
@@ -269,9 +290,55 @@ def _wait_config(self, show_cmd, expect):
class XRV(vrnetlab.VR):
- def __init__(self, hostname, username, password, nics, conn_mode, vcpu, ram):
+ def __init__(self, hostname, username, password, *remaining):
+ super(XRV, self).__init__(username, password)
+ self.vms = [XRV_vm(hostname, username, password, *remaining)]
+
+
+class XRV_installer(XRV):
+ """XRV9K installer"""
+
+ def __init__(self, username, password, *remaining):
super(XRV, self).__init__(username, password)
- self.vms = [XRV_vm(hostname, username, password, nics, conn_mode, vcpu, ram)]
+ self.vms = [XRV_vm(username, password, *remaining, install_mode=True)]
+
+ def install(self):
+ self.logger.info("Installing XRV9K")
+ xrv = self.vms[0]
+ while not xrv.running:
+ xrv.work()
+
+ # wait for system to shut down cleanly
+ for i in range(0, 600):
+ time.sleep(1)
+ try:
+ xrv.p.communicate(timeout=1)
+ except subprocess.TimeoutExpired:
+ pass
+ except Exception as exc:
+ # assume it's dead
+ self.logger.info(
+ "Can't communicate with qemu process, assuming VM has shut down properly."
+ + str(exc)
+ )
+ break
+
+ try:
+ (ridx, match, res) = xrv.tn.expect([b"System halted"], 1)
+ if res != b"":
+ self.logger.trace("OUTPUT XRV9K: %s" % res.decode())
+ else:
+ break
+ except Exception as exc:
+ # assume it's dead
+ self.logger.info(
+ "Can't communicate over serial console, assuming VM has shut down properly."
+ + str(exc)
+ )
+ break
+
+ xrv.stop()
+ self.logger.info("Installation complete")
if __name__ == "__main__":
@@ -284,12 +351,13 @@ def __init__(self, hostname, username, password, nics, conn_mode, vcpu, ram):
parser.add_argument("--hostname", default="vr-xrv9k", help="Router hostname")
parser.add_argument("--username", default="vrnetlab", help="Username")
parser.add_argument("--password", default="VR-netlab9", help="Password")
- parser.add_argument("--nics", type=int, default=128, help="Number of NICS")
+ parser.add_argument("--install", action="store_true", help="Install XRV9K")
+ parser.add_argument("--nics", type=int, default=64, help="Number of NICS")
parser.add_argument(
"--vcpu", type=int, default=2, help="Number of cpu cores to use"
)
parser.add_argument(
- "--ram", type=int, default=12228, help="Number RAM to use in MB"
+ "--ram", type=int, default=14336, help="Number RAM to use in MB"
)
parser.add_argument(
"--connection-mode",
@@ -309,7 +377,7 @@ def __init__(self, hostname, username, password, nics, conn_mode, vcpu, ram):
logger.debug(f"Environment variables: {os.environ}")
vrnetlab.boot_delay()
- vr = XRV(
+ xrv_args = (
args.hostname,
args.username,
args.password,
@@ -318,4 +386,9 @@ def __init__(self, hostname, username, password, nics, conn_mode, vcpu, ram):
args.vcpu,
args.ram,
)
- vr.start()
+ if args.install:
+ vr = XRV_installer(*xrv_args)
+ vr.install()
+ else:
+ vr = XRV(*xrv_args)
+ vr.start()
--
2.33.0
|
@vincentbernat what did you change from the base patch? |
Mostly, I did a factory reset after initial install. Also, I did not alter the way initial user is created and logged in. |
I can indeed confirm that giving XRV more NICs makes bootup slower. We did some testing of that, probing through number of nics from like 1 to 128 or so in steps of 10 and it's pretty linear. This was not with a special install mode, but just vanilla image as produced by vrnetlab today. |
This presentation https://clnv.s3.amazonaws.com/2018/eur/pdf/BRKSPG-2724.pdf hints that there is a "baking" process happening the first time xrv9k is booted. I think I've seen this in logs, i.e. xr starts up, does something and then reloads. It likely installs itself somehow.
However, that presentation and several of the guide indicate that one should provide a disk for xrv9k and the install media. That's not what we do. What's the difference? Is there a difference?
One thing I did seem to see is that some SSH key was generated on that first boot, so by making it part of the build process we might end up with the same host key on all VRs.
The text was updated successfully, but these errors were encountered: