Exemple #1
0
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
Exemple #3
0
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))
Exemple #4
0
    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)
Exemple #6
0
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)
Exemple #10
0
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!')
Exemple #15
0
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)
Exemple #21
0
    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
Exemple #23
0
 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])
Exemple #24
0
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)
Exemple #26
0
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)
Exemple #28
0
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)