def os_mount(self): self.mount_path, self.diff_path = self.get_mount_info() failsafe_makedirs(self.mount_path) failsafe_makedirs(self.diff_path) self.docker.local.image_mount(self.fullname, self.diff_path, self.mount_path) self.mounted = True
def setup(mount_path): # ensure FILES var is completely defined if FILES['/root/.ssh/authorized_keys'] is None: # ensure server has a pub key ensure_root_key_exists() # we will authorize the server to connect to nodes with open(SERVER_KEY_PATH + '.pub') as f: FILES['/root/.ssh/authorized_keys'] = f.read() # /etc/dropbear is a symlink to /var/run/dropbear on some images. # * /var/run/dropbear is an absolute path, thus we should mind not # being directed to server files! # * in this conf, the content of this directory is cleared at startup, # which is not what we want. # We may have the same issues with /etc/ssh. remove_if_link(mount_path + '/etc/ssh') remove_if_link(mount_path + '/etc/dropbear') # copy files listed in variable FILES on the image for path, content in FILES.items(): failsafe_makedirs(mount_path + os.path.dirname(path)) with open(mount_path + path, 'w') as f: f.write(content) # set node DNS servers if os.path.exists(mount_path + '/etc/resolv.conf'): os.rename(mount_path + '/etc/resolv.conf', mount_path + '/etc/resolv.conf.saved') with open(mount_path + '/etc/resolv.conf', 'w') as f: for resolver in get_dns_servers(): f.write("nameserver {}\n".format(resolver)) if os.path.isfile(mount_path + '/etc/hostname') and \ not os.path.islink(mount_path + '/etc/hostname'): os.remove(mount_path + '/etc/hostname') # probably a residual of image build # fix absolute symlinks in /boot fix_absolute_symlinks(mount_path, mount_path + '/boot') # fix compatbility with old walt-node packages if os.path.exists(mount_path + '/usr/local/bin/walt-echo'): os.remove(mount_path + '/usr/local/bin/walt-echo') # copy walt scripts in <image>/bin, update template parameters image_bindir = mount_path + '/bin/' for script_name, template in NODE_SCRIPTS.items(): script_path = resource_filename(__name__, script_name) shutil.copy(script_path, image_bindir) if template: update_template(image_bindir + script_name, TEMPLATE_ENV) # read image spec file if any image_spec = spec.read_image_spec(mount_path) if image_spec != None: # update template files specified there spec.update_templates(mount_path, image_spec, TEMPLATE_ENV) # update features matching those of the server spec.enable_matching_features(mount_path, image_spec) # copy server spec file, just in case spec.copy_server_spec_file(mount_path) # fix PTP conf regarding unicast default mode too verbose on LAN fix_ptp(mount_path)
def mount(self, image_id, fullname=None): if image_id in self.mounts: return # already mounted self.mounts.add(image_id) desc = fullname if fullname else image_id print('Mounting %s...' % desc) mount_path = get_mount_path(image_id) failsafe_makedirs(mount_path) self.docker.local.image_mount(image_id, mount_path) setup(mount_path) print('Mounting %s... done' % desc)
def failsafe_mkfifo(path, mode=None): if mode == None: mode = RW_ALL # check if it does not exist already if os.path.exists(path): return # ensure parent dir exists failsafe_makedirs(os.path.dirname(path)) # create the fifo os.mkfifo(path) os.chmod(path, mode)
def setup(image): mount_path = image.mount_path # ensure FILES var is completely defined if FILES['/root/.ssh/authorized_keys'] is None: # ensure server has a pub key ensure_root_key_exists() # we will authorize the server to connect to nodes with open(SERVER_KEY_PATH + '.pub') as f: FILES['/root/.ssh/authorized_keys'] = f.read() # /etc/dropbear is a symlink to /var/run/dropbear on some images. # * /var/run/dropbear is an absolute path, thus we should mind not # being directed to server files! # * in this conf, the content of this directory is cleared at startup, # which is not what we want. # We may have the same issues with /etc/ssh. remove_if_link(mount_path + '/etc/ssh') remove_if_link(mount_path + '/etc/dropbear') # copy files listed in variable FILES on the image for path, content in FILES.items(): failsafe_makedirs(mount_path + os.path.dirname(path)) with open(mount_path + path, 'w') as f: f.write(content) # set node DNS servers if os.path.exists(mount_path + '/etc/resolv.conf'): os.rename(mount_path + '/etc/resolv.conf', mount_path + '/etc/resolv.conf.saved') with open(mount_path + '/etc/resolv.conf', 'w') as f: for resolver in get_dns_servers(): f.write("nameserver {}\n".format(resolver)) if os.path.isfile(mount_path + '/etc/hostname') and \ not os.path.islink(mount_path + '/etc/hostname'): os.remove(mount_path + '/etc/hostname') # probably a residual of image build # fix absolute symlinks in /boot fix_absolute_symlinks(mount_path, mount_path + '/boot') # fix compatbility with old walt-node packages if os.path.exists(mount_path + '/usr/local/bin/walt-echo'): os.remove(mount_path + '/usr/local/bin/walt-echo') # copy walt scripts in <image>/bin, update template parameters image_bindir = mount_path + '/bin/' for script_name, template in NODE_SCRIPTS.items(): script_path = resource_filename(__name__, script_name) shutil.copy(script_path, image_bindir) if template: update_template(image_bindir + script_name, TEMPLATE_ENV) # read image spec file if any image_spec = spec.read_image_spec(mount_path) if image_spec != None: # update template files specified there spec.update_templates(mount_path, image_spec, TEMPLATE_ENV) # update features matching those of the server spec.enable_matching_features(image, image_spec) # copy server spec file, just in case spec.copy_server_spec_file(mount_path) # fix PTP conf regarding unicast default mode too verbose on LAN fix_ptp(mount_path)
def failsafe_mkfifo(path, mode = None): if mode == None: mode = RW_ALL # check if it does not exist already if os.path.exists(path): return # ensure parent dir exists failsafe_makedirs(os.path.dirname(path)) # create the fifo os.mkfifo(path) os.chmod(path, mode)
def start_vnode(self, node): if not os.path.exists('/etc/qemu/bridge.conf'): failsafe_makedirs('/etc/qemu') with open('/etc/qemu/bridge.conf', 'w') as f: f.write('allow walt-net\n') cmd = CMD_START_VNODE % dict(mac=node.mac, ip=node.ip, model=node.model, name=node.name, server_ip=get_server_ip()) print(cmd) subprocess.Popen(shlex.split(cmd))
def start_vnode(self, node): if not os.path.exists('/etc/qemu/bridge.conf'): failsafe_makedirs('/etc/qemu') with open('/etc/qemu/bridge.conf', 'w') as f: f.write('allow walt-net\n') cmd = CMD_START_VNODE % dict( mac = node.mac, ip = node.ip, model = node.model, name = node.name, server_ip = get_server_ip() ) print(cmd) subprocess.Popen(shlex.split(cmd))
def __init__(self, serial_dev_path): self.f = open(serial_dev_path, 'r', 0) self.walt_logs = open(SERVER_LOGS_FIFO, 'w') # Data does not comes in immediately after we have the # device open. Wait a little to make sure we get # the data to be flushed. time.sleep(0.1) self.flush() self.logdefs = [] self.logvars = {} log_dir = '/var/log/walt/autolog%s' % serial_dev_path failsafe_makedirs(log_dir) self.in_dbg_log = open(log_dir + '/in.log', 'w') self.out_dbg_log = open(log_dir + '/out.log', 'w') self.started = False
def run(): if len(sys.argv) < 2: sys.exit('Missing 1st argument: "up" or "down".') action = sys.argv[1] if action not in ('up', 'down'): sys.exit('1st argument must be "up" or "down".') iface = os.environ.get('IFACE') if iface is None: sys.exit('IFACE environment variable is missing.') failsafe_makedirs(WALT_STATUS_DIR) if action == 'up': network_conf = conf['network'] up(iface, network_conf) elif action == 'down': down(iface)
def update(db): # create dir if it does not exist yet failsafe_makedirs(NODES_PATH) # list existing entries, in case some of them are obsolete invalid_entries = set(f for f in os.listdir(NODES_PATH)) # each node has a directory entry with: # - a link called "fs" to the image filesystem root # - a link called "tftp" to a directory of boot files stored per-model in the image # The name of this dir is the mac address of the node, # written <hh>:<hh>:<hh>:<hh>:<hh>:<hh>. # For compatibility with different network bootloaders # we also provide 3 links to this directory: # - mac address written <hh>-<hh>-<hh>-<hh>-<hh>-<hh> # - ipv4 address (dotted quad notation) # - walt node name for db_node in db.select('nodes'): if db_node.image is not None: image_path = get_mount_path(db_node.image) mac = db_node.mac model = db_node.model mac_dash = mac.replace(':', '-') device = db.select_unique('devices', mac=mac) failsafe_makedirs(NODES_PATH + mac) failsafe_symlink(image_path, NODES_PATH + mac + '/fs', force_relative=True) # link to boot files stored inside the image failsafe_symlink(image_path + '/boot/' + model, NODES_PATH + mac + '/tftp', force_relative=True) for ln_name in (mac_dash, device.ip, device.name): failsafe_symlink(NODES_PATH + mac, NODES_PATH + ln_name, force_relative=True) # this entry is valid invalid_entries.discard(ln_name) invalid_entries.discard(mac) # if there are still values in variable invalid_entries, # we can remove the corresponding entry for entry in invalid_entries: entry = NODES_PATH + entry if os.path.isdir(entry) and not os.path.islink(entry): shutil.rmtree(entry) else: os.remove(entry)
def generate_exports_file(images, nodes): with open('/etc/exports', 'w') as f: f.write("# Root filesystem images\n") for image in images: if image.ready: f.write((IMAGE_EXPORT_PATTERN % dict(image_mountpoint=image.mount_path, walt_subnet=get_walt_subnet(), fsid=get_fsid(image))) + "\n") f.write("# Persistent node directories\n") for node in nodes: persist_path = PERSISTENT_PATH % dict(node_mac=node.mac) try: # ensure persistent directories exists failsafe_makedirs(persist_path) except OSError: # directory already exists pass f.write((PERSISTENT_EXPORT_PATTERN % dict(persist_mountpoint=persist_path, walt_subnet=get_walt_subnet())) + "\n")
def start_vnode(self, node): if not os.path.exists('/etc/qemu/bridge.conf'): failsafe_makedirs('/etc/qemu') with open('/etc/qemu/bridge.conf', 'w') as f: f.write('allow walt-net\n') # in case a screen session already exists for this vnode # (e.g. walt server process was killed), kill it self.try_kill_vnode(node.mac) # start vnode VNODE_LOG_DIR.mkdir(parents=True, exist_ok=True) hypmac = node.mac.replace(':', '-') cmd = CMD_START_VNODE % dict( mac = node.mac, hypmac = hypmac, ip = node.ip, model = node.model, name = node.name, server_ip = get_server_ip(), cpu_cores = node.conf.get('cpu.cores', VNODE_DEFAULT_CPU_CORES), ram = node.conf.get('ram', VNODE_DEFAULT_RAM), ttyrec_file = VNODE_LOG_DIR / (hypmac + str(int(time())) + '.tty') ) print(cmd) subprocess.Popen(shlex.split(cmd))
def copy_server_spec_file(image_path): target_path = image_path + SERVER_SPEC_PATH failsafe_makedirs(os.path.dirname(target_path)) shutil.copy(SERVER_SPEC_PATH, target_path)