def start_slimremote_duckiebot_container(duckiebot_name, max_vel): duckiebot_ip = get_duckiebot_ip(duckiebot_name) duckiebot_client = get_remote_client(duckiebot_ip) container_name = 'evaluator' try: container = duckiebot_client.containers.get(container_name) dtslogger.info("slim remote already running on %s, restarting..." % duckiebot_name) stop_container(container) remove_container(container) except Exception as e: dtslogger.info("Starting slim remote on %s" % duckiebot_name) parameters = { 'image': SLIMREMOTE_IMAGE, 'remove': True, 'privileged': True, 'detach': True, 'environment': { "DUCKIETOWN_MAXSPEED": max_vel }, 'name': container_name, 'ports': { '5558': '5558', '8902': '8902' }, } return duckiebot_client.containers.run(**parameters)
def command(shell, args): # get installed commands installed = set(shell.commands.keys()) # get list of commands to uninstall / not-uninstallable requested_to_uninstall = set(args) to_uninstall = requested_to_uninstall.intersection(installed) not_uninstallable = requested_to_uninstall.difference(installed) need_reload = False # not uninstallable for cmd in not_uninstallable: dtslogger.warn('The command `%s` cannot be found.' % cmd) # uninstall for cmd in to_uninstall: dtslogger.info('Removing command `%s`...' % cmd) shell.disable_command(cmd) need_reload = True dtslogger.info('Successfully completed calibration!') print('Done!') # update list of commands if need_reload: print('Updating index...') shell.reload_commands() print('Done!') else: print('Nothing to do.') return True
def run_image_on_duckiebot(image_name, duckiebot_name, env=None, volumes=None): duckiebot_ip = get_duckiebot_ip(duckiebot_name) duckiebot_client = get_remote_client(duckiebot_ip) env_vars = default_env(duckiebot_name, duckiebot_ip) if env is not None: env_vars.update(env) dtslogger.info("Running %s with environment: %s" % (image_name, env_vars)) params = { 'image': image_name, 'remove': True, 'network_mode': 'host', 'privileged': True, 'detach': True, 'environment': env_vars } if volumes is not None: params['volumes'] = volumes # Make sure we are not already running the same image if all(elem.image != image_name for elem in duckiebot_client.containers.list()): return duckiebot_client.containers.run(**params) else: dtslogger.warn( 'Container with image %s is already running on %s, skipping...' % (image_name, duckiebot_name))
def command(shell, args): script_file = join(dirname(realpath(__file__)), 'start_hatchery.sh') script_cmd = '/bin/sh %s' % script_file print('Running %s' % script_cmd) env = {} env.update(os.environ) V = 'DOCKER_HOST' if V in env: msg = 'I will ignore %s in the environment because we want to run things on the laptop.' % V dtslogger.info(msg) env.pop(V) ret = subprocess.call(script_cmd, shell=True, stdin=sys.stdin, stderr=sys.stderr, stdout=sys.stdout, env=env) # process.communicate() if ret == 0: print('Done!') else: msg = ( 'An error occurred while starting the GUI tools container, please check and try again (%s).' % ret) raise Exception(msg)
def command(shell, args): token = shell.get_dt1_token() parser = argparse.ArgumentParser() parser.add_argument('--config', default='challenge.yaml', help="YAML configuration file") parser.add_argument('--no-cache', default=False, action='store_true') parser.add_argument('--steps', default=None, help='Which steps (comma separated)') parser.add_argument('--force-invalidate-subs', default=False, action='store_true') parser.add_argument('-C', dest='cwd', default=None, help='Base directory') parser.add_argument('--impersonate', type=str, default=None) parsed = parser.parse_args(args) impersonate = parsed.impersonate from dt_shell.env_checks import check_docker_environment client = check_docker_environment() if client is None: # To remove when done client = check_docker_environment() if parsed.cwd is not None: dtslogger.info('Changing to directory %s' % parsed.cwd) os.chdir(parsed.cwd) no_cache = parsed.no_cache fn = os.path.join(parsed.config) if not os.path.exists(fn): msg = 'File %s does not exist.' % fn raise UserError(msg) data = read_yaml_file(fn) if 'description' not in data or data['description'] is None: fnd = os.path.join(os.path.dirname(fn), 'challenge.description.md') if os.path.exists(fnd): desc = open(fnd).read() data['description'] = desc msg = 'Read description from %s' % fnd dtslogger.info(msg) base = os.path.dirname(fn) challenge = ChallengeDescription.from_yaml(data) with wrap_server_operations(): go(token, impersonate, parsed, challenge, base, client, no_cache)
def remove_if_running(client, container_name): try: container = client.containers.get(container_name) dtslogger.info("%s already running - stopping it first.." % container_name) stop_container(container) dtslogger.info("removing %s" % container_name) remove_container(container) except Exception as e: dtslogger.warn("couldn't remove existing container: %s" % e)
def get_clean_env(): env = {} env.update(os.environ) V = 'DOCKER_HOST' if V in env: msg = 'I will ignore %s in the environment because we want to run things on the laptop.' % V dtslogger.info(msg) env.pop(V) return env
def command(shell, args): if shell.commands_path_leave_alone: dtslogger.warn( 'Will not update the commands because the path was set explicitly.' ) else: if shell.update_commands(): dtslogger.info('Duckietown Shell commands updated.') else: dtslogger.error('Update was not successful.')
def write_to_hypriot(rpath, contents): if not os.path.exists(TMP_HYPRIOT_MOUNTPOINT): msg = 'Disk not mounted: %s' % TMP_HYPRIOT_MOUNTPOINT raise Exception(msg) x = os.path.join(TMP_HYPRIOT_MOUNTPOINT, rpath) d = os.path.dirname(x) if not os.path.exists(d): os.makedirs(d) with open(x, 'w') as f: f.write(contents) dtslogger.info('Written to %s' % x)
def run_gui_controller(hostname, image): client = check_docker_environment() container_name = "joystick_gui_%s" % hostname remove_if_running(client, container_name) duckiebot_ip = get_duckiebot_ip(hostname) env = { 'HOSTNAME': hostname, 'ROS_MASTER': hostname, 'DUCKIEBOT_NAME': hostname, 'ROS_MASTER_URI': 'http://%s:11311' % duckiebot_ip } env['QT_X11_NO_MITSHM'] = 1 volumes = {} subprocess.call(["xhost", "+"]) p = platform.system().lower() if 'darwin' in p: dtslogger.warn( "We can try but running the joystick gui on MacOSx is not expected to work..." ) env['DISPLAY'] = 'host.docker.internal:0' volumes = {'/tmp/.X11-unix': {'bind': '/tmp/.X11-unix', 'mode': 'rw'}} else: env['DISPLAY'] = os.environ['DISPLAY'] dtslogger.info("Running %s on localhost with environment vars: %s" % (container_name, env)) if 'master19' in image: image = "duckietown/rpi-duckiebot-base:master19-no-arm" cmd = "python misc/virtualJoy/virtualJoy.py %s" % hostname elif 'daffy' in image: image = "duckietown/dt-core:daffy-amd64" cmd = "roslaunch virtual_joystick virtual_joystick_gui.launch veh:=%s" % hostname params = { 'image': image, 'name': container_name, 'network_mode': 'host', 'environment': env, 'privileged': True, 'stdin_open': True, 'tty': True, 'command': cmd, 'detach': True, 'volumes': volumes } container = client.containers.run(**params) cmd = 'docker attach %s' % container_name start_command_in_subprocess(cmd)
def build_image(client, path, challenge_name, step_name, service_name, filename, no_cache: bool, registry_info: RegistryInfo) -> BuildResult: d = datetime.datetime.now() username = get_dockerhub_username() from duckietown_challenges.utils import tag_from_date if username.lower() != username: msg = f'Are you sure that the DockerHub username is not lowercase? You gave "{username}".' dtslogger.warning(msg) username = username.lower() br = BuildResult( repository=('%s-%s-%s' % (challenge_name, step_name, service_name)).lower(), organization=username, registry=registry_info.registry, tag=tag_from_date(d), digest=None) complete = get_complete_tag(br) cmd = ['docker', 'build', '--pull', '-t', complete, '-f', filename] if no_cache: cmd.append('--no-cache') cmd.append(path) dtslogger.debug('$ %s' % " ".join(cmd)) subprocess.check_call(cmd) image = client.images.get(complete) repo_digests = image.attrs.get('RepoDigests', []) if repo_digests: msg = 'Already found repo digest: %s' % repo_digests dtslogger.info(msg) else: dtslogger.info('Image not present on registry. Need to push.') cmd = ['docker', 'push', complete] dtslogger.debug('$ %s' % " ".join(cmd)) subprocess.check_call(cmd) image = client.images.get(complete) dtslogger.info('image id: %s' % image.id) dtslogger.info('complete: %s' % get_complete_tag(br)) repo_digests = image.attrs.get('RepoDigests', []) if not repo_digests: msg = 'Could not find any repo digests (push not succeeded?)' raise Exception(msg) dtslogger.info('RepoDigests: %s' % repo_digests) _, digest = repo_digests[0].split('@') # br.digest = image.id br.digest = digest br = parse_complete_tag(get_complete_tag(br)) return br
def command(shell, args): # configure arguments parser = argparse.ArgumentParser() parser.add_argument('-C', '--workdir', default=None, help="Directory containing the project to push") parser.add_argument('-a', '--arch', default=DEFAULT_ARCH, help="Target architecture for the image to push") parser.add_argument( '-H', '--machine', default=DEFAULT_MACHINE, help="Docker socket or hostname from where to push the image") parser.add_argument( '-f', '--force', default=False, action='store_true', help="Whether to force the push when the git index is not clean") parsed, _ = parser.parse_known_args(args=args) # --- code_dir = parsed.workdir if parsed.workdir else os.getcwd() dtslogger.info('Project workspace: {}'.format(code_dir)) # show info about project shell.include.devel.info.command(shell, args) # get info about current repo repo_info = shell.include.devel.info.get_repo_info(code_dir) repo = repo_info['REPOSITORY'] branch = repo_info['BRANCH'] nmodified = repo_info['INDEX_NUM_MODIFIED'] nadded = repo_info['INDEX_NUM_ADDED'] # check if the index is clean if nmodified + nadded > 0: dtslogger.warning( 'Your index is not clean (some files are not committed).') dtslogger.warning( 'If you know what you are doing, use --force to force the execution of the command.' ) if not parsed.force: exit(1) dtslogger.warning('Forced!') # create defaults default_tag = "duckietown/%s:%s" % (repo, branch) tag = "duckietown/%s:%s-%s" % (repo, branch, parsed.arch) tags = [tag] + ([default_tag] if parsed.arch == DEFAULT_ARCH else []) for t in tags: # push image dtslogger.info("Pushing image {}...".format(t)) _run_cmd(['docker', '-H=%s' % parsed.machine, 'push', t])
def step_flash(shell, parsed): deps = [ 'wget', 'tar', 'udisksctl', 'docker', 'base64', 'gzip', 'udevadm', 'lsblk' ] for dep in deps: check_program_dependency(dep) # Ask for a device if not set already: global SD_CARD_DEVICE if SD_CARD_DEVICE == '': msg = 'Please type the device with your SD card. Please be careful to pick the right device and \ to include \'/dev/\'. Here\'s a list of the devices on your system:' dtslogger.info(msg) script_file = get_resource('list_disks.sh') script_cmd = '/bin/bash %s' % script_file env = get_environment_clean() ret = subprocess.call(script_cmd, shell=True, env=env, stdin=sys.stdin, stderr=sys.stderr, stdout=sys.stdout) SD_CARD_DEVICE = raw_input( "Type the name of your device (include the \'/dev\' part): ") # Check if the device exists if not os.path.exists(SD_CARD_DEVICE): msg = 'Device %s was not found on your system. Maybe you mistyped something.' % SD_CARD_DEVICE raise Exception(msg) script_file = get_resource('init_sd_card2.sh') script_cmd = '/bin/bash %s' % script_file env = get_environment_clean() env['INIT_SD_CARD_DEV'] = SD_CARD_DEVICE ret = subprocess.call(script_cmd, shell=True, env=env, stdin=sys.stdin, stderr=sys.stderr, stdout=sys.stdout) if ret == 0: dtslogger.info('Done!') else: msg = ( 'An error occurred while initializing the SD card, please check and try again (%s).' % ret) raise Exception(msg)
def command(shell, args): # configure arguments parser = argparse.ArgumentParser() parser.add_argument( 'action', nargs=1, choices=VALID_COMMANDS, help="Action to perform on the watchtower instance") parser.add_argument( '-H', '--machine', default=DEFAULT_MACHINE, help="Docker socket or hostname where the watchtower is running") parsed, _ = parser.parse_known_args(args=args) action = parsed.action[0] # --- # get info about containers running on the docker endpoint container_id = _get_container_id(parsed.machine, all=False) is_running = container_id is not None # action: status if action == 'status': bg_color = 'on_green' if is_running else 'on_red' msg = '[RUNNING]' if is_running else '[NOT RUNNING]' info = 'with ID {}'.format(container_id) if is_running else '' print("{}: Watchtower {}".format(colored(msg, 'white', bg_color), info)) return # action: stop if action == 'stop' and not is_running: msg = 'No watchtower instance found. Nothing to do.' dtslogger.info(msg) return # action: start if action == 'start': if is_running: msg = 'Watchtower already running. Nothing to do.' dtslogger.info(msg) return else: container_id = _get_container_id(parsed.machine, all=True) if container_id is None: msg = 'Watchtower instance not found. Run `docker run ...` first.' dtslogger.info(msg) return # action: [stop, start] dtslogger.info('{}ing watchtower container...'.format(action.title())) _ = _run_cmd( ['docker', '-H=%s' % parsed.machine, action, container_id], get_output=True) dtslogger.info('Done!')
def start_picamera(duckiebot_name): duckiebot_ip = get_duckiebot_ip(duckiebot_name) duckiebot_client = get_remote_client(duckiebot_ip) duckiebot_client.images.pull(RPI_DUCKIEBOT_ROS_PICAM) env_vars = default_env(duckiebot_name, duckiebot_ip) dtslogger.info("Running %s on %s with environment vars: %s" % (RPI_DUCKIEBOT_ROS_PICAM, duckiebot_name, env_vars)) return duckiebot_client.containers.run(image=RPI_DUCKIEBOT_ROS_PICAM, remove=True, network_mode='host', devices=['/dev/vchiq'], detach=True, environment=env_vars)
def _get_container_id(machine, all): dtslogger.info( 'Retrieving info about the containers running on the Docker endpoint...' ) containers = _run_cmd([ 'docker', '-H=%s' % machine, 'ps', '--format', '("{{.ID}}", "{{.Image}}")', '--all=%d' % int(all) ], get_output=True) # check if there is a watchtower instance running for id_im in containers: id, im = eval(id_im) if im.startswith(WATCHTOWER_IMAGE): return id return None
def save_images(stack2yaml, compress): """ returns stack2info """ cache_dir = DOCKER_IMAGES_CACHE_DIR if not os.path.exists(cache_dir): os.makedirs(cache_dir) client = check_docker_environment() stack2info = {} for cf, config in stack2yaml.items(): image_name2id = {} for service, service_config in config['services'].items(): image_name = service_config['image'] dtslogger.info('Pulling %s' % image_name) cmd = ['docker', 'pull', image_name] _run_cmd(cmd) image = client.images.get(image_name) image_id = str(image.id) image_name2id[image_name] = image_id hname = get_md5("-".join(sorted(list(image_name2id.values()))))[:8] if compress: destination = os.path.join(cache_dir, cf + '-' + hname + '.tar.gz') else: destination = os.path.join(cache_dir, cf + '-' + hname + '.tar') destination0 = os.path.join(cache_dir, cf + '-' + hname + '.tar') stack2info[cf] = StackInfo(archive=destination, image_name2id=image_name2id, hname=hname) if os.path.exists(destination): msg = 'Using cached file %s' % destination dtslogger.info(msg) continue dtslogger.info('Saving to %s' % destination0) cmd = ['docker', 'save', '-o', destination0] + list(image_name2id.values()) _run_cmd(cmd) if compress: cmd = ['gzip', '-f', destination0] _run_cmd(cmd) assert not os.path.exists(destination0) assert os.path.exists(destination) else: assert destination == destination0 msg = 'Saved archive %s of size %s' % (destination, friendly_size_file(destination)) dtslogger.info(msg) assert len(stack2info) == len(stack2yaml) return stack2info
def run_cli_controller(hostname, image, duckiebot_ip, network_mode, sim): if sim: duckiebot_client = check_docker_environment() else: duckiebot_client = docker.DockerClient('tcp://' + duckiebot_ip + ':2375') container_name = "joystick_cli_%s" % hostname remove_if_running(duckiebot_client, container_name) env = { 'HOSTNAME': hostname, 'ROS_MASTER': hostname, 'VEHICLE_NAME': hostname, 'ROS_MASTER_URI': 'http://%s:11311' % duckiebot_ip } dtslogger.info("Running %s on localhost with environment vars: %s" % (container_name, env)) if 'master19' in image: image = "duckietown/rpi-duckiebot-base:master19" # run on robot cmd = "python misc/virtualJoy/joy_cli.py %s" % hostname elif 'daffy' in image: if sim: image = "duckietown/dt-core:daffy-amd64" else: image = "duckietown/dt-core:daffy" cmd = "roslaunch virtual_joystick virtual_joystick_cli.launch veh:=%s" % hostname params = { 'image': image, 'name': container_name, 'network_mode': network_mode, 'environment': env, 'privileged': True, 'stdin_open': True, 'tty': True, 'command': cmd, 'detach': True } container = duckiebot_client.containers.run(**params) if sim: cmd = 'docker attach %s' % container_name else: cmd = 'docker -H %s.local attach %s' % (hostname, container_name) start_command_in_subprocess(cmd)
def check_compatible(): dtslogger.info('duckietown-shell-commands %s' % duckietown_shell_commands_version) OtherVersions = getattr(dt_shell, 'OtherVersions', {}) OtherVersions.name2versions['duckietown-shell-commands'] = duckietown_shell_commands_version vnow = parse_version(dt_shell.__version__) vneed = parse_version(min_duckietown_shell) if vneed > vnow: msg = ''' Detected Duckietown Shell %s but these commands (%s) need Duckietown Shell >= %s. ''' % (render_version(vnow), duckietown_shell_commands_version, render_version(vneed)) raise UserError(msg)
def check_has_space(where, min_available_gb): try: import psutil except ImportError: msg = 'Skipping disk check because psutil not installed.' dtslogger.info(msg) else: disk = psutil.disk_usage(where) disk_available_gb = disk.free / (1024 * 1024 * 1024.0) if disk_available_gb < min_available_gb: msg = 'This procedure requires that you have at least %f GB of memory.' % min_available_gb msg += '\nYou only have %.2f GB available on %s.' % (disk_available_gb, where) dtslogger.error(msg) raise NotEnoughSpace(msg) else: msg = 'You have %.2f GB available on %s. ' % (disk_available_gb, where) dtslogger.info(msg)
def command(shell, args): script_file = join(dirname(realpath(__file__)), 'calibrate_duckiebot.sh') prog = 'dts calibrate DUCKIEBOT_NAME' usage = """ Calibrate: %(prog)s """ parser = argparse.ArgumentParser(prog=prog, usage=usage) parser.add_argument('hostname', default=None, help='Name of the Duckiebot to calibrate') parsed_args = parser.parse_args(args) duckiebot_ip = get_duckiebot_ip(parsed_args.hostname) # shell.calibrate(duckiebot_name=args[0], duckiebot_ip=duckiebot_ip) script_cmd = '/bin/bash %s %s %s' % (script_file, parsed_args.hostname, duckiebot_ip) env = {} env.update(os.environ) V = 'DOCKER_HOST' if V in env: msg = 'I will ignore %s because the calibrate command knows what it\'s doing.' % V dtslogger.info(msg) env.pop(V) ret = call(script_cmd, shell=True, stdin=sys.stdin, stderr=sys.stderr, stdout=sys.stdout, env=env) if ret == 0: print('Done!') else: msg = ( 'An error occurred while running the calibration procedure, please check and try again (%s).' % ret) raise Exception(msg)
def get_stack2yaml(stacks, base): names = os.listdir(base) all_stacks = [os.path.splitext(_)[0] for _ in names if _.endswith("yaml")] dtslogger.info('The stacks that are available are: %s' % ", ".join(all_stacks)) dtslogger.info('You asked to use %s' % stacks) use = [] for s in stacks: if s not in all_stacks: msg = 'Cannot find stack %r in %s' % (s, all_stacks) raise Exception(msg) use.append(s) stacks2yaml = OrderedDict() for sn in use: lpath = join(base, sn + '.yaml') if not os.path.exists(lpath): raise Exception(lpath) stacks2yaml[sn] = yaml.load(open(lpath).read()) return stacks2yaml
def command(shell, args): # configure arguments parser = argparse.ArgumentParser() parser.add_argument('-C', '--workdir', default=None, help="Directory containing the project to clean") parser.add_argument('-a', '--arch', default=DEFAULT_ARCH, help="Target architecture for the image to clean") parser.add_argument( '-H', '--machine', default=DEFAULT_MACHINE, help="Docker socket or hostname where to clean the image") parsed, _ = parser.parse_known_args(args=args) # --- code_dir = parsed.workdir if parsed.workdir else os.getcwd() dtslogger.info('Project workspace: {}'.format(code_dir)) # show info about project shell.include.devel.info.command(shell, args) # get info about current repo repo_info = shell.include.devel.info.get_repo_info(code_dir) repo = repo_info['REPOSITORY'] branch = repo_info['BRANCH'] nmodified = repo_info['INDEX_NUM_MODIFIED'] nadded = repo_info['INDEX_NUM_ADDED'] # create defaults default_tag = "duckietown/%s:%s" % (repo, branch) tag = "%s-%s" % (default_tag, parsed.arch) tags = [tag] + ([default_tag] if parsed.arch == DEFAULT_ARCH else []) # remove images for t in tags: img = _run_cmd( ['docker', '-H=%s' % parsed.machine, 'images', '-q', t], get_output=True) if img: dtslogger.info("Removing image {}...".format(t)) _run_cmd(['docker', '-H=%s' % parsed.machine, 'rmi', t])
def record_bag(duckiebot_name, duration): duckiebot_ip = get_duckiebot_ip(duckiebot_name) local_client = check_docker_environment() dtslogger.info("Starting bag recording...") parameters = { 'image': RPI_DUCKIEBOT_BASE, 'remove': True, 'network_mode': 'host', 'privileged': True, 'detach': True, 'environment': default_env(duckiebot_name, duckiebot_ip), 'command': 'bash -c "cd /data && rosbag record --duration %s -a"' % duration, 'volumes': bind_local_data_dir() } # Mac Docker has ARM support directly in the Docker environment, so we don't need to run qemu... if platform.system() != 'Darwin': parameters['entrypoint'] = 'qemu3-arm-static' return local_client.containers.run(**parameters)
def step_expand(shell, parsed): check_program_dependency('parted') check_program_dependency('resize2fs') check_program_dependency('df') check_program_dependency('umount') global SD_CARD_DEVICE if not os.path.exists(SD_CARD_DEVICE): msg = 'This only works assuming device == %s' % SD_CARD_DEVICE raise Exception(msg) else: msg = 'Found device %s.' % SD_CARD_DEVICE dtslogger.info(msg) # Some devices get only a number added to the disk name, other get p + a number if os.path.exists(SD_CARD_DEVICE + '1'): DEVp1 = SD_CARD_DEVICE + '1' DEVp2 = SD_CARD_DEVICE + '2' elif os.path.exists(SD_CARD_DEVICE + 'p1'): DEVp1 = SD_CARD_DEVICE + 'p1' DEVp2 = SD_CARD_DEVICE + 'p2' else: msg = 'The second partition of device %s could not be found.' % SD_CARD_DEVICE raise Exception(msg) # Unmount the devices and check if this worked, otherwise parted will fail p = subprocess.Popen(['df', '-h'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) ret, err = p.communicate() if DEVp1 in ret: cmd = ['sudo', 'umount', DEVp1] _run_cmd(cmd) if DEVp2 in ret: cmd = ['sudo', 'umount', DEVp2] _run_cmd(cmd) p = subprocess.Popen(['df', '-h'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) ret, err = p.communicate() if DEVp1 in ret or DEVp2 in ret: msg = 'Automatic unmounting of %s and %s was unsuccessful. Please do it manually and run again.' % ( DEVp1, DEVp2) raise Exception(msg) # Do the expansion dtslogger.info('Current status:') cmd = ['sudo', 'lsblk', SD_CARD_DEVICE] _run_cmd(cmd) cmd = ['sudo', 'parted', '-s', SD_CARD_DEVICE, 'resizepart', '2', '100%'] _run_cmd(cmd) cmd = ['sudo', 'e2fsck', '-f', DEVp2] _run_cmd(cmd) cmd = ['sudo', 'resize2fs', DEVp2] _run_cmd(cmd) dtslogger.info('Updated status:') cmd = ['sudo', 'lsblk', SD_CARD_DEVICE] _run_cmd(cmd)
def run_image_on_localhost(image_name, duckiebot_name, container_name, env=None, volumes=None): duckiebot_ip = get_duckiebot_ip(duckiebot_name) local_client = check_docker_environment() env_vars = default_env(duckiebot_name, duckiebot_ip) if env is not None: env_vars.update(env) try: container = local_client.containers.get(container_name) dtslogger.info("an image already on localhost - stopping it first..") stop_container(container) remove_container(container) except Exception as e: dtslogger.warn("coulgn't remove existing container: %s" % e) dtslogger.info("Running %s on localhost with environment vars: %s" % (image_name, env_vars)) params = { 'image': image_name, 'remove': True, 'network_mode': 'host', 'privileged': True, 'detach': True, 'tty': True, 'name': container_name, 'environment': env_vars } if volumes is not None: params['volumes'] = volumes new_local_container = local_client.containers.run(**params) return new_local_container
def command(shell, args): prog = 'dts start_gui_tools DUCKIEBOT_NAME' usage = """ Keyboard control: %(prog)s """ parser = argparse.ArgumentParser(prog=prog, usage=usage) parser.add_argument('hostname', default=None, help='Name of the Duckiebot to calibrate') parsed_args = parser.parse_args(args) env = {} env.update(os.environ) V = 'DOCKER_HOST' if V in env: msg = 'I will ignore %s in the environment because we want to run things on the laptop.' % V dtslogger.info(msg) env.pop(V) start_gui_tools(parsed_args.hostname)
def start_rqt_image_view(duckiebot_name=None): dtslogger.info( """{}\nOpening a camera feed by running xhost+ and running rqt_image_view...""" .format('*' * 20)) local_client = check_docker_environment() local_client.images.pull(RPI_GUI_TOOLS) env_vars = {'QT_X11_NO_MITSHM': 1} if duckiebot_name is not None: duckiebot_ip = get_duckiebot_ip(duckiebot_name) env_vars.update(default_env(duckiebot_name, duckiebot_ip)) operating_system = platform.system() if operating_system == 'Linux': subprocess.call(["xhost", "+"]) env_vars['DISPLAY'] = ':0' elif operating_system == 'Darwin': IP = subprocess.check_output([ '/bin/sh', '-c', 'ifconfig en0 | grep inet | awk \'$1=="inet" {print $2}\'' ]) env_vars['IP'] = IP subprocess.call(["xhost", "+IP"]) dtslogger.info("Running %s on localhost with environment vars: %s" % (RPI_GUI_TOOLS, env_vars)) return local_client.containers.run( image=RPI_GUI_TOOLS, remove=True, privileged=True, detach=True, network_mode='host', environment=env_vars, command= 'bash -c "source /home/software/docker/env.sh && rqt_image_view"')
def configure_ssh(parsed, ssh_key_pri, ssh_key_pub): ssh_dir = os.path.expanduser('~/.ssh') if not os.path.exists(ssh_dir): os.makedirs(ssh_dir) ssh_key_pri_copied = os.path.join(ssh_dir, 'DT18_key_00') ssh_key_pub_copied = os.path.join(ssh_dir, 'DT18_key_00.pub') if not os.path.exists(ssh_key_pri_copied): shutil.copy(ssh_key_pri, ssh_key_pri_copied) if not os.path.exists(ssh_key_pub_copied): shutil.copy(ssh_key_pub, ssh_key_pub_copied) ssh_config = os.path.join(ssh_dir, 'config') if not os.path.exists(ssh_config): msg = ('Could not find ssh config file %s' % ssh_config) dtslogger.info(msg) current = "" else: current = open(ssh_config).read() bit = """ # --- init_sd_card generated --- # Use the key for all hosts IdentityFile {IDENTITY} Host {HOSTNAME} User {DTS_USERNAME} Hostname {HOSTNAME}.local IdentityFile {IDENTITY} StrictHostKeyChecking no # ------------------------------ """.format(HOSTNAME=parsed.hostname, IDENTITY=ssh_key_pri_copied, DTS_USERNAME=parsed.linux_username) if bit not in current: dtslogger.info('Updating ~/.ssh/config with: ' + bit) with open(ssh_config, 'a') as f: f.write(bit) else: dtslogger.info('Configuration already found in ~/.ssh/config')
def step_flash(shell, parsed): deps = ['wget', 'tar', 'udisksctl', 'docker', 'base64', 'gzip', 'udevadm', 'lsblk'] for dep in deps: check_program_dependency(dep) # Ask for a device if not set already: global SD_CARD_DEVICE if SD_CARD_DEVICE == '': msg = 'Please type the device with your SD card. Please be careful to pick the right device and \ to include \'/dev/\'. Here\'s a list of the devices on your system:' dtslogger.info(msg) script_file = get_resource('list_disks.sh') script_cmd = '/bin/bash %s' % script_file start_command_in_subprocess(script_cmd) msg = "Type the name of your device (include the \'/dev\' part): " SD_CARD_DEVICE = builtins.input(msg) # Check if the device exists if not os.path.exists(SD_CARD_DEVICE): msg = 'Device %s was not found on your system. Maybe you mistyped something.' % SD_CARD_DEVICE raise Exception(msg) script_file = get_resource('init_sd_card.sh') script_cmd = '/bin/bash %s' % script_file env = get_clean_env() env['INIT_SD_CARD_DEV'] = SD_CARD_DEVICE # pass HypriotOS version to init_sd_card script if parsed.experimental: env['HYPRIOTOS_VERSION'] = HYPRIOTOS_EXPERIMENTAL_VERSION else: env['HYPRIOTOS_VERSION'] = HYPRIOTOS_STABLE_VERSION start_command_in_subprocess(script_cmd, env) dtslogger.info('Waiting 5 seconds for the device to get ready...') time.sleep(5) dtslogger.info('Partitions created:') cmd = ['sudo', 'lsblk', SD_CARD_DEVICE] _run_cmd(cmd)