diff options
Diffstat (limited to 'bbot/agent.cxx')
-rw-r--r-- | bbot/agent.cxx | 108 |
1 files changed, 97 insertions, 11 deletions
diff --git a/bbot/agent.cxx b/bbot/agent.cxx index e608af2..2489ce4 100644 --- a/bbot/agent.cxx +++ b/bbot/agent.cxx @@ -4,9 +4,16 @@ #include <bbot/agent> +#include <pwd.h> // getpwuid() #include <limits.h> // PATH_MAX #include <signal.h> // signal() -#include <unistd.h> // sleep(), realink() +#include <unistd.h> // sleep(), realink(), getuid() + +#include <net/if.h> // ifreq +#include <netinet/in.h> // sockaddr_in +#include <arpa/inet.h> // inet_ntop() +#include <sys/ioctl.h> +#include <sys/socket.h> #include <iostream> @@ -19,23 +26,57 @@ #include <bbot/utility> #include <bbot/diagnostics> +#include <bbot/tftp> #include <bbot/machine> #include <bbot/bootstrap-manifest> +using namespace std; +using namespace butl; +using namespace bbot; + namespace bbot { agent_options ops; - const string bs_prot ("1"); // Bootstrap protocol version. + const string bs_prot ("1"); - string tc_name; // Toolchain name. - string tc_num; // Toolchain number. - string tc_id; // Toolchain id. -} + string tc_name; + string tc_num; + string tc_id; -using namespace std; -using namespace butl; -using namespace bbot; + uid_t uid; + string uname; + + // Note: Linux-specific implementation. + // + string + iface_addr (const string& i) + { + if (i.size () >= IFNAMSIZ) + throw invalid_argument ("interface nama too long"); + + auto_fd fd (socket (AF_INET, SOCK_DGRAM, 0)); + + if (fd.get () == -1) + throw_system_error (errno); + + ifreq ifr; + ifr.ifr_addr.sa_family = AF_INET; + strcpy (ifr.ifr_name, i.c_str ()); + + if (ioctl (fd.get (), SIOCGIFADDR, &ifr) == -1) + throw_system_error (errno); + + char buf[3 * 4 + 3 + 1]; // IPv4 address. + if (inet_ntop (AF_INET, + &reinterpret_cast<sockaddr_in*> (&ifr.ifr_addr)->sin_addr, + buf, + sizeof (buf)) == nullptr) + throw_system_error (errno); + + return buf; + } +} // The btrfs tool likes to print informational messages, like "Created // snapshot such and such". Luckily, it writes them to stdout while proper @@ -65,6 +106,8 @@ bootstrap_machine (const dir_path& md, const machine_manifest& mm, optional<bootstrapped_machine_manifest> obmm) { + tracer trace ("bootstrap_machine"); + bootstrapped_machine_manifest r { mm, toolchain_manifest {tc_id}, @@ -83,15 +126,51 @@ bootstrap_machine (const dir_path& md, r.machine.mac = "de:ad:be:ef:de:ad"; } else + try { + string br ("br1"); // Use private bridge for now. + + // Start the TFTP server (server chroot is /build/tftp). Map: + // + // GET requests to /build/tftp/toolchain/<name>/* + // PUT requests to /build/tftp/bootstrap/<name>/* + // + auto_rmdir arm (dir_path ("/build/tftp/bootstrap/" + tc_name)); + try_mkdir_p (arm.path ()); + + tftp_server tftpd ("Gr ^/?(.+)$ /toolchain/" + tc_name + "/\\1\n" + + "Pr ^/?(.+)$ /bootstrap/" + tc_name + "/\\1\n"); + + l2 ([&]{trace << "tftp server on port " << tftpd.port ();}); + + // Start the machine. + // unique_ptr<machine> m ( start_machine (md, mm, - obmm ? obmm->machine.mac : nullopt)); + obmm ? obmm->machine.mac : nullopt, + br, + tftpd.port ())); r.machine.mac = m->mac; - sleep (10); + // The first request should be the toolchain download. Wait for up to 60 + // seconds for that to arrive. In a sense we use it as an indication that + // the machine has booted and the bootstrap process has started. + // + size_t timeout (60); + if (tftpd.serve (timeout)) + { + l2 ([&]{trace << "received first request in " << 60 - timeout << "s";}); + } + else + { + // @@ What should be do here? Non-fatal? Mark the machine as failed? + // + error << "bootstrap timeout during first request for machine " << md; + m->forcedown (); + throw failed (); + } if (!m->shutdown ()) { @@ -100,6 +179,10 @@ bootstrap_machine (const dir_path& md, throw failed (); } } + catch (const system_error& e) + { + fail << "tftp server error: " << e; + } serialize_manifest (r, md / "manifest", "bootstrapped machine"); return r; @@ -389,6 +472,9 @@ try verb = ops.verbose (); + uid = getuid (); + uname = getpwuid (uid)->pw_name; + if (ops.systemd_daemon ()) { // Map to systemd severity prefixes (see sd-daemon(3) for details). Note |