예제 #1
0
def run_main(args):
    if not os.path.exists(SCRIPT_FILENAME):
        print 'ERROR: Please run "solo script pack" first to bundle your archive.'
        return 1

    print 'connecting to solo...'
    solo = soloutils.connect_solo(await=True)
    scp = SCPClient(solo.get_transport())

    # Requires pip
    print 'checking pip...'
    if soloutils.install_pip.run(solo, scp) != 0:
        print 'failed installing pip.'
        sys.exit(1)

    push(solo, scp, '--force' in args['<arg>'])

    print 'running script...'
    print ''
    soloutils.command_stream(
        solo, '''
set -e
cd /log/solo-script
source ./env/bin/activate
exec python /log/solo-script/''' + args['<arg>'][1] + '''
''')

    scp.close()
    solo.close()
예제 #2
0
파일: script.py 프로젝트: mgrennan/solo-cli
def run_main(args):
    if not os.path.exists(SCRIPT_FILENAME):
        print 'ERROR: Please run "solo script pack" first to bundle your archive.'
        return 1

    print 'connecting to solo...'
    solo = soloutils.connect_solo(await=True)
    scp = SCPClient(solo.get_transport())

    # Requires pip
    print 'checking pip...'
    if soloutils.install_pip.run(solo, scp) != 0:
        print 'failed installing pip.'
        sys.exit(1)

    push(solo, scp, '--force' in args['<arg>'])

    print 'running script...'
    print ''
    soloutils.command_stream(solo, '''
set -e
cd /log/solo-script
source ./env/bin/activate
exec python /log/solo-script/''' + args['<arg>'][1]  + '''
''')

    scp.close()
    solo.close()
예제 #3
0
def main(args):
    print 'connecting to the Controller...'
    controller = soloutils.connect_controller(await=True)

    controller_version = soloutils.controller_versions(controller)['version']
    if LooseVersion('1.1.15') != LooseVersion(controller_version):
        print 'error: expecting Controller to be EXACTLY EQUAL TO 1.1.15'
        print 'your Controller version: {}'.format(controller_version)
        print 'please flash your Controller with 1.1.15 to run this command.'
        print ''
        print '    solo update solo 1.1.15'
        print '    solo update controller 1.1.15'
        sys.exit(1)

    code = soloutils.command_stream(controller, SCRIPT.format(ssid=args['--name'], password=args['--password']))
    controller.close()

    if code == 0:
        try:
            print 'resetting Solo\'s wifi...'
            print '(if solo is not online, you can hit Ctrl+C safely now.)'
            solo = soloutils.connect_solo(await=True)
            soloutils.command_stream(solo, 'init 2 && init 4')
            solo.close()
        except KeyboardInterrupt:
            pass

        print 'setup complete! you are now connected to the Internet.'
        print "(if you are not connected to the Internet on your PC,"
        print " disconnect and reconnect to Solo\'s network.)"

    sys.exit(code)
예제 #4
0
def factory_reset(target):
    code = soloutils.command_stream(target, 'sololink_config --factory-reset')
    if code != 0:
        code = soloutils.command_stream(
            target,
            'mkdir -p /log/updates && touch /log/updates/FACTORYRESET && shutdown -r now'
        )
    return code == 0
예제 #5
0
def settings_reset(target):
    code = soloutils.command_stream(target, 'sololink_config --settings-reset')
    if code != 0:
        code = soloutils.command_stream(
            target,
            'mkdir -p /log/updates && touch /log/updates/RESETSETTINGS && shutdown -r now'
        )
    return code == 0
예제 #6
0
파일: video.py 프로젝트: STMPNGRND/solo-cli
def main(args):
    print 'connecting to solo...'
    solo = soloutils.connect_solo(await=True)

    if args['acquire']:
        code = soloutils.command_stream(solo, ACQUIRE)
    elif args['restore']:
        code = soloutils.command_stream(solo, RESTORE)

    solo.close()
    sys.exit(code)
예제 #7
0
def main(args):
    print 'connecting to solo...'
    solo = soloutils.connect_solo(await=True)

    if args['acquire']:
        code = soloutils.command_stream(solo, ACQUIRE)
    elif args['restore']:
        code = soloutils.command_stream(solo, RESTORE)

    solo.close()
    sys.exit(code)
예제 #8
0
def main(args):
    print 'NOTE: this process requires simultaneous access to'
    print 'Solo and to the Internet. if you have not yet done so,'
    print 'run `solo wifi` to connect to Solo and to a local'
    print 'wifi connection simultaneously.'
    print ''
    print 'NOTE: also run `solo install-smart` first.'
    print ''

    # prompt for consent
    print 'WARNING: this can break your Solo and require a factory reset!'
    print 'your Solo will turn off after and you will need to power cycle it.'
    y = raw_input('proceed to resize filesystem? [y/N] ')
    if not (y.lower() == 'y' or y.lower() == 'yes'):
        sys.exit(1)

    print ''
    print 'connecting to solo...'
    solo = soloutils.connect_solo(await=True)

    print 'waiting for Internet connectivity...'
    soloutils.await_net()

    print ''
    code = soloutils.command_stream(solo, SCRIPT)

    print ''
    dt = datetime.today() + timedelta(minutes=4)
    print(
        'please wait up to four minutes longer for the resize to complete (at {}).'
        .format(dt.strftime('%-I:%M')))
    print('(you can manually restart solo if it fails to come online again.)')

    solo.close()
    sys.exit(code)
예제 #9
0
def push(solo, scp, force):
    if not force:
        code, stdout, stderr = soloutils.command(
            solo, 'md5sum /tmp/solo-script.tar.gz')
        md5sum = next(iter((stdout or '').split()), None)
        localmd5sum = hashlib.md5(open(SCRIPT_FILENAME,
                                       'rb').read()).hexdigest()

        if code == 0 and md5sum == localmd5sum:
            print 'script bundle already up to date.'
            return 0

    print 'uploading script bundle...'
    scp.put(SCRIPT_FILENAME, '/tmp')
    return soloutils.command_stream(
        solo, '''
set -e
rm -rf /log/solo-script || true
mkdir /log/solo-script
cd /log/solo-script
tar -xvf /tmp/solo-script.tar.gz
virtualenv --clear env || virtualenv env
cp -rf /usr/lib/python2.7/site-packages/greenlet* env/lib/python2.7/site-packages/ || true
source ./env/bin/activate
pip install --no-index -U ./wheelhouse/* 
''')
예제 #10
0
def main(args):
    print 'NOTE: this process requires simultaneous access to'
    print 'Solo and to the Internet. if you have not yet done so,'
    print 'run `solo wifi` to connect to Solo and to a local'
    print 'wifi connection simultaneously.'
    print ''
    print 'NOTE: also run `solo install-smart` first.'
    print ''

    # prompt for consent
    print 'WARNING: this can break your Solo and require a factory reset!'
    print 'your Solo will turn off after and you will need to power cycle it.'
    y = raw_input('proceed to resize filesystem? [y/N] ')
    if not (y.lower() == 'y' or y.lower() == 'yes'):
        sys.exit(1)

    print ''
    print 'connecting to solo...'
    solo = soloutils.connect_solo(await=True)

    print 'waiting for Internet connectivity...'
    soloutils.await_net()

    print ''
    code = soloutils.command_stream(solo, SCRIPT)

    print ''
    dt = datetime.today() + timedelta(minutes=4)
    print('please wait up to four minutes longer for the resize to complete (at {}).'.format(dt.strftime('%-I:%M')))
    print('(you can manually restart solo if it fails to come online again.)')

    solo.close()
    sys.exit(code)
예제 #11
0
def main(args):
    print 'connecting to the Controller...'
    controller = soloutils.connect_controller(await=True)

    controller_version = soloutils.controller_versions(controller)['version']
    if LooseVersion('1.2.0') > LooseVersion(controller_version):
        print 'error: expecting version to be >= 1.2.0'
        print 'your Controller version: {}'.format(controller_version)
        print 'please flash your Controller with a newer version to run this command.'
        print ''
        print '    solo update solo latest'
        print '    solo update controller latest'
        sys.exit(1)

    print ''
    if args['--password']:
        print 'connecting to encrypted wifi network.'
        credentials = 'ssid="{ssid}"\npsk="{password}"'.format(
            ssid=args['--name'], password=args['--password'])
    else:
        print 'connecting to wifi network with NO password.'
        credentials = 'ssid="{ssid}"\nkey_mgmt=NONE'.format(
            ssid=args['--name'])
    print '(your computer may disconnect from Solo\'s network.)'

    controller = soloutils.connect_controller(await=True)
    code = soloutils.command_blind(controller,
                                   SCRIPT.format(credentials=credentials))
    time.sleep(8)
    controller.close()

    print ''
    print 'please manually reconnect to Solo\'s network once it becomes available.'
    print 'it may take up to 30s to a reconnect to succeed.'
    controller = soloutils.connect_controller(await=True, silent=True)
    print ''
    code = soloutils.command_stream(controller, 'cat /log/setupwifi.log')
    controller.close()

    try:
        drone = soloutils.connect_solo(await=False)
        print '(resetting Solo\'s DNS...',
        sys.stdout.flush()
        soloutils.command(drone,
                          'ifdown wlan0; ifdown -a; ifup -a; ifup wlan0')
        time.sleep(4)
        drone.close()
        print ' done.)'
    except:
        pass

    sys.exit(code)
예제 #12
0
def flash_px4(firmware_file):
    errprinter('connecting to Solo...')
    client = soloutils.connect_solo(await=True)
    soloutils.command_stream(client, 'rm -rf /firmware/loaded')

    # Upload the files.
    errprinter('uploading files...')
    scp = SCPClient(client.get_transport())
    scp.put(firmware_file, '/firmware')
    scp.close()

    # shutdown solo for firmware reflash
    #code = soloutils.command_stream(client, 'shutdown -r now')
    code = soloutils.command_stream(client, 'loadPixhawk.py')
    #errprinter('Solo will update once it reboots!')
    errprinter('Pixhawk has been updated to new firmware')
    #dt = datetime.today() + timedelta(minutes=4)
    #errprinter('please wait up to four minutes longer for the installation to complete (by {}).'.format(dt.strftime('%-I:%M')))

    # Complete!
    client.close()

    sys.exit(0)
예제 #13
0
파일: flash.py 프로젝트: mgrennan/solo-cli
def flash_px4(firmware_file):
    errprinter('connecting to Solo...')
    client = soloutils.connect_solo(await=True)
    soloutils.command_stream(client, 'rm -rf /firmware/loaded')

    # Upload the files.
    errprinter('uploading files...')
    scp = SCPClient(client.get_transport())
    scp.put(firmware_file, '/firmware')
    scp.close()

    # shutdown solo for firmware reflash
    #code = soloutils.command_stream(client, 'shutdown -r now')
    code = soloutils.command_stream(client, 'loadPixhawk.py')
    #errprinter('Solo will update once it reboots!')
    errprinter('Pixhawk has been updated to new firmware')
    #dt = datetime.today() + timedelta(minutes=4)
    #errprinter('please wait up to four minutes longer for the installation to complete (by {}).'.format(dt.strftime('%-I:%M')))

    # Complete!
    client.close()

    sys.exit(0)
예제 #14
0
파일: flash.py 프로젝트: mgrennan/solo-cli
def flash(target, firmware_file, firmware_md5, args):
    # Connect to controller...
    if target == 'controller':
        errprinter('connecting to Controller...')
        client = soloutils.connect_controller(await=True)
    else:
        errprinter('connecting to Solo...')
        client = soloutils.connect_solo(await=True)

    # Prepare the update.
    # older versions don't have sololink_config and ssh returns 127, so do it manually
    code = soloutils.command_stream(client, 'sololink_config --update-prepare sololink')
    if code != 0:
        soloutils.command_stream(client, 'rm -rf /log/updates && mkdir -p /log/updates')

    # Upload the files.
    errprinter('uploading files...')
    scp = SCPClient(client.get_transport())
    scp.put(firmware_file, posixpath.join('/log/updates/', posixpath.basename(firmware_file)))
    scp.put(firmware_md5, posixpath.join('/log/updates/', posixpath.basename(firmware_md5)))
    scp.close()

    if target == 'controller':
        errprinter("starting update on the Controller...")
    else:
        errprinter("starting update on Solo...")

    if args['--clean']:
        errprinter('marking all user-local changes to be reset...')
        code = soloutils.command_stream(client, 'sololink_config --update-apply sololink --reset')
    else:
        code = soloutils.command_stream(client, 'sololink_config --update-apply sololink')
    # Fallback to earlier versions.
    if code != 0:
        if args['--clean']:
            code = soloutils.command_stream(client, 'touch /log/updates/UPDATE && touch /log/updates/RESETSETTINGS && shutdown -r now')
        else:
            code = soloutils.command_stream(client, 'touch /log/updates/UPDATE && shutdown -r now')
        
    if target == 'controller':
        errprinter('the Controller will update once it reboots!')
    else:
        errprinter('Solo will update once it reboots!')

    dt = datetime.today() + timedelta(minutes=4)
    errprinter('please wait up to four minutes longer for the installation to complete (by {}).'.format(dt.strftime('%-I:%M')))

    # Complete!
    client.close()

    return code
예제 #15
0
파일: wifi.py 프로젝트: STMPNGRND/solo-cli
def main(args):
    print 'connecting to the Controller...'
    controller = soloutils.connect_controller(await=True)

    controller_version = soloutils.controller_versions(controller)['version']
    if LooseVersion('1.2.0') > LooseVersion(controller_version):
        print 'error: expecting version to be >= 1.2.0'
        print 'your Controller version: {}'.format(controller_version)
        print 'please flash your Controller with a newer version to run this command.'
        print ''
        print '    solo update solo latest'
        print '    solo update controller latest'
        sys.exit(1)

    print ''
    if args['--password']:
        print 'connecting to encrypted wifi network.'
        credentials = 'ssid="{ssid}"\npsk="{password}"'.format(ssid=args['--name'], password=args['--password'])
    else:
        print 'connecting to wifi network with NO password.'
        credentials = 'ssid="{ssid}"\nkey_mgmt=NONE'.format(ssid=args['--name'])
    print '(your computer may disconnect from Solo\'s network.)'

    controller = soloutils.connect_controller(await=True)
    code = soloutils.command_blind(controller, SCRIPT.format(credentials=credentials))
    time.sleep(8)
    controller.close()

    print ''
    print 'please manually reconnect to Solo\'s network once it becomes available.'
    print 'it may take up to 30s to a reconnect to succeed.'
    controller = soloutils.connect_controller(await=True, silent=True)
    print ''
    code = soloutils.command_stream(controller, 'cat /log/setupwifi.log')
    controller.close()

    try:
        drone = soloutils.connect_solo(await=False)
        print '(resetting Solo\'s DNS...',
        sys.stdout.flush()
        soloutils.command(drone, 'ifdown wlan0; ifdown -a; ifup -a; ifup wlan0')
        time.sleep(4)
        drone.close()
        print ' done.)'
    except:
        pass

    sys.exit(code)
예제 #16
0
def main(args):
    print 'NOTE: this process requires simultaneous access to'
    print 'Solo and to the Internet. if you have not yet done so,'
    print 'run `solo wifi` to connect to Solo and to a local'
    print 'wifi connection simultaneously.'
    print ''

    print 'connecting to solo...'
    solo = soloutils.connect_solo(await=True)

    print 'waiting for Internet connectivity...'
    soloutils.await_net()

    print ''
    code = soloutils.command_stream(solo, SCRIPT)
    solo.close()
    sys.exit(code)
예제 #17
0
def main(args):
    print 'NOTE: this process requires simultaneous access to'
    print 'Solo and to the Internet. if you have not yet done so,'
    print 'run `solo wifi` to connect to Solo and to a local'
    print 'wifi connection simultaneously.'
    print ''

    print 'connecting to solo...'
    solo = soloutils.connect_solo(await=True)

    print 'waiting for Internet connectivity...'
    soloutils.await_net()

    print ''
    code = soloutils.command_stream(solo, SCRIPT)
    solo.close()
    sys.exit(code)
예제 #18
0
파일: script.py 프로젝트: mgrennan/solo-cli
def push(solo, scp, force):
    if not force:
        code, stdout, stderr = soloutils.command(solo, 'md5sum /tmp/solo-script.tar.gz')
        md5sum = next(iter((stdout or '').split()), None)
        localmd5sum = hashlib.md5(open(SCRIPT_FILENAME, 'rb').read()).hexdigest()
        
        if code == 0 and md5sum == localmd5sum:
            print 'script bundle already up to date.'
            return 0

    print 'uploading script bundle...'
    scp.put(SCRIPT_FILENAME, '/tmp')
    return soloutils.command_stream(solo, '''
set -e
rm -rf /log/solo-script || true
mkdir /log/solo-script
cd /log/solo-script
tar -xvf /tmp/solo-script.tar.gz
virtualenv --clear env || virtualenv env
cp -rf /usr/lib/python2.7/site-packages/greenlet* env/lib/python2.7/site-packages/ || true
source ./env/bin/activate
pip install --no-index -U ./wheelhouse/* 
''')
예제 #19
0
def flash(target, firmware_file, firmware_md5, args):
    # Connect to controller...
    if target == 'controller':
        errprinter('connecting to Controller...')
        client = soloutils.connect_controller(await=True)
    else:
        errprinter('connecting to Solo...')
        client = soloutils.connect_solo(await=True)

    # Prepare the update.
    # older versions don't have sololink_config and ssh returns 127, so do it manually
    code = soloutils.command_stream(
        client, 'sololink_config --update-prepare sololink')
    if code != 0:
        soloutils.command_stream(
            client, 'rm -rf /log/updates && mkdir -p /log/updates')

    # Upload the files.
    errprinter('uploading files...')
    scp = SCPClient(client.get_transport())
    scp.put(firmware_file,
            posixpath.join('/log/updates/', posixpath.basename(firmware_file)))
    scp.put(firmware_md5,
            posixpath.join('/log/updates/', posixpath.basename(firmware_md5)))
    scp.close()

    if target == 'controller':
        errprinter("starting update on the Controller...")
    else:
        errprinter("starting update on Solo...")

    if args['--clean']:
        errprinter('marking all user-local changes to be reset...')
        code = soloutils.command_stream(
            client, 'sololink_config --update-apply sololink --reset')
    else:
        code = soloutils.command_stream(
            client, 'sololink_config --update-apply sololink')
    # Fallback to earlier versions.
    if code != 0:
        if args['--clean']:
            code = soloutils.command_stream(
                client,
                'touch /log/updates/UPDATE && touch /log/updates/RESETSETTINGS && shutdown -r now'
            )
        else:
            code = soloutils.command_stream(
                client, 'touch /log/updates/UPDATE && shutdown -r now')

    if target == 'controller':
        errprinter('the Controller will update once it reboots!')
    else:
        errprinter('Solo will update once it reboots!')

    dt = datetime.today() + timedelta(minutes=4)
    errprinter(
        'please wait up to four minutes longer for the installation to complete (by {}).'
        .format(dt.strftime('%-I:%M')))

    # Complete!
    client.close()

    return code
예제 #20
0
def settings_reset(target):
    code = soloutils.command_stream(target, 'sololink_config --settings-reset')
    if code != 0:
        code = soloutils.command_stream(target, 'mkdir -p /log/updates && touch /log/updates/RESETSETTINGS && shutdown -r now')
    return code == 0
예제 #21
0
def factory_reset(target):
    code = soloutils.command_stream(target, 'sololink_config --factory-reset')
    if code != 0:
        code = soloutils.command_stream(target, 'mkdir -p /log/updates && touch /log/updates/FACTORYRESET && shutdown -r now')
    return code == 0
예제 #22
0
def main(args):
    if args['both']:
        group = 'Solo and the Controller'
    if args['solo']:
        group = 'Solo'
    if args['controller']:
        group = 'the Controller'

    version = None
    if args['<version>']:
        version = re.sub(r'^v', '', args['<version>'])
        if not re.match(r'^\d+', version):
            errprinter('error: verion number specified looks invalid.')
            sys.exit(1)

    if not args['--list']:
        # prompt for consent
        errprinter('you are about to update {}.'.format(group))
        errprinter(
            'this preserves all your local changes to Solo, but compatibility')
        errprinter('with newer updates is not guaranteed.')
        y = raw_input('proceed to perform update? [y/N] ')
        if not (y.lower() == 'y' or y.lower() == 'yes'):
            sys.exit(1)

    if not args['latest'] and not version and not args['--list']:
        errprinter(
            'TODO: only solo update to "latest" or "<version>" works yet.')
        sys.exit(1)
    if args['both']:
        errprinter(
            'TODO: only "solo" or "controller" update yet works, not "both".')
        sys.exit(1)

    errprinter('checking Internet connectivity...')
    soloutils.await_net()

    if args['controller']:
        product = [1, 10]
    else:
        product = [2, 9]

    updates = releases(product)

    if version:
        updates = filter(
            lambda x: version in re.sub('.tar.gz', '',
                                        x.url.split('/')[-1]), updates)
        if len(updates) == 0:
            errprinter(
                'error: no version matching {} were found.'.format(version))
            sys.exit(1)

    if args['--list']:
        for update in updates:
            print(update.version)
        sys.exit(0)

    # download file
    file_loc, md5_loc = fetch(updates[-1])

    errprinter(
        'please power-up the Controller and connect your PC to the Solo wifi network.'
    )

    # Connect to controller...
    if args['controller']:
        errprinter('connecting to Controller...')
        client = soloutils.connect_controller(await=True)
    else:
        errprinter('connecting to Solo...')
        client = soloutils.connect_solo(await=True)

    # Prepare the update.
    # older versions don't have sololink_config and ssh returns 127, so do it manually
    code = soloutils.command_stream(
        client, 'sololink_config --update-prepare sololink')
    if code != 0:
        soloutils.command_stream(
            client, 'rm -rf /log/updates && mkdir -p /log/updates')

    # Upload the files.
    errprinter('uploading updates...')
    scp = SCPClient(client.get_transport())
    scp.put(file_loc,
            posixpath.join('/log/updates/', posixpath.basename(file_loc)))
    scp.put(md5_loc,
            posixpath.join('/log/updates/', posixpath.basename(md5_loc)))
    scp.close()

    if args['controller']:
        errprinter("starting update on the Controller...")
    else:
        errprinter("starting update on Solo...")
    code = soloutils.command_stream(client,
                                    'sololink_config --update-apply sololink')
    if code != 0:
        code = soloutils.command_stream(
            client, 'touch /log/updates/UPDATE && shutdown -r now')
        if args['controller']:
            errprinter('the Controller will update once it reboots.')
        else:
            errprinter('Solo will update once it reboots.')
    else:
        errprinter('update succeeded!')

    dt = datetime.today() + timedelta(minutes=4)
    errprinter(
        'please wait up to four minutes longer for the installation to complete (at {}).'
        .format(dt.strftime('%-I:%M')))

    # Complete!
    client.close()
    sys.exit(code)
예제 #23
0
파일: update.py 프로젝트: djnugent/solo-cli
def main(args):
    if args["both"]:
        group = "Solo and the Controller"
    if args["solo"]:
        group = "Solo"
    if args["controller"]:
        group = "the Controller"

    version = None
    if args["<version>"]:
        version = re.sub(r"^v", "", args["<version>"])
        if not re.match(r"^\d+", version):
            errprinter("error: verion number specified looks invalid.")
            sys.exit(1)

    if not args["--list"]:
        # prompt for consent
        errprinter("you are about to update {}.".format(group))
        errprinter("this preserves all your local changes to Solo, but compatibility")
        errprinter("with newer updates is not guaranteed.")
        y = raw_input("proceed to perform update? [y/N] ")
        if not (y.lower() == "y" or y.lower() == "yes"):
            sys.exit(1)

    if not args["latest"] and not version and not args["--list"]:
        errprinter('TODO: only solo update to "latest" or "<version>" works yet.')
        sys.exit(1)
    if args["both"]:
        errprinter('TODO: only "solo" or "controller" update yet works, not "both".')
        sys.exit(1)

    errprinter("checking Internet connectivity...")
    soloutils.await_net()

    if args["controller"]:
        product = [1, 10]
    else:
        product = [2, 9]

    updates = releases(product)

    if version:
        updates = filter(lambda x: version in re.sub(".tar.gz", "", x.url.split("/")[-1]), updates)
        if len(updates) == 0:
            errprinter("error: no version matching {} were found.".format(version))
            sys.exit(1)

    if args["--list"]:
        for update in updates:
            print(update.version)
        sys.exit(0)

    # download file
    file_loc, md5_loc = fetch(updates[-1])

    errprinter("please power-up the Controller and connect your PC to the Solo wifi network.")

    # Connect to controller...
    if args["controller"]:
        errprinter("connecting to Controller...")
        client = soloutils.connect_controller(await=True)
    else:
        errprinter("connecting to Solo...")
        client = soloutils.connect_solo(await=True)

    # Prepare the update.
    # older versions don't have sololink_config and ssh returns 127, so do it manually
    code = soloutils.command_stream(client, "sololink_config --update-prepare sololink")
    if code != 0:
        soloutils.command_stream(client, "rm -rf /log/updates && mkdir -p /log/updates")

    # Upload the files.
    errprinter("uploading updates...")
    scp = SCPClient(client.get_transport())
    scp.put(file_loc, posixpath.join("/log/updates/", posixpath.basename(file_loc)))
    scp.put(md5_loc, posixpath.join("/log/updates/", posixpath.basename(md5_loc)))
    scp.close()

    if args["controller"]:
        errprinter("starting update on the Controller...")
    else:
        errprinter("starting update on Solo...")
    code = soloutils.command_stream(client, "sololink_config --update-apply sololink")
    if code != 0:
        code = soloutils.command_stream(client, "touch /log/updates/UPDATE && shutdown -r now")
        if args["controller"]:
            errprinter("the Controller will update once it reboots.")
        else:
            errprinter("Solo will update once it reboots.")
    else:
        errprinter("update succeeded!")

    dt = datetime.today() + timedelta(minutes=4)
    errprinter(
        "please wait up to four minutes longer for the installation to complete (at {}).".format(dt.strftime("%-I:%M"))
    )

    # Complete!
    client.close()
    sys.exit(code)