1eb8dc403SDave Cobbley# Development tool - deploy/undeploy command plugin 2eb8dc403SDave Cobbley# 3eb8dc403SDave Cobbley# Copyright (C) 2014-2016 Intel Corporation 4eb8dc403SDave Cobbley# 5c342db35SBrad Bishop# SPDX-License-Identifier: GPL-2.0-only 6eb8dc403SDave Cobbley# 7eb8dc403SDave Cobbley"""Devtool plugin containing the deploy subcommands""" 8eb8dc403SDave Cobbley 9eb8dc403SDave Cobbleyimport logging 10eb8dc403SDave Cobbleyimport os 11eb8dc403SDave Cobbleyimport shutil 12eb8dc403SDave Cobbleyimport subprocess 13eb8dc403SDave Cobbleyimport tempfile 14eb8dc403SDave Cobbley 15eb8dc403SDave Cobbleyimport bb.utils 16eb8dc403SDave Cobbleyimport argparse_oe 17eb8dc403SDave Cobbleyimport oe.types 18eb8dc403SDave Cobbley 19eb8dc403SDave Cobbleyfrom devtool import exec_fakeroot, setup_tinfoil, check_workspace_recipe, DevtoolError 20eb8dc403SDave Cobbley 21eb8dc403SDave Cobbleylogger = logging.getLogger('devtool') 22eb8dc403SDave Cobbley 23eb8dc403SDave Cobbleydeploylist_path = '/.devtool' 24eb8dc403SDave Cobbley 25eb8dc403SDave Cobbleydef _prepare_remote_script(deploy, verbose=False, dryrun=False, undeployall=False, nopreserve=False, nocheckspace=False): 26eb8dc403SDave Cobbley """ 27eb8dc403SDave Cobbley Prepare a shell script for running on the target to 28eb8dc403SDave Cobbley deploy/undeploy files. We have to be careful what we put in this 29eb8dc403SDave Cobbley script - only commands that are likely to be available on the 30eb8dc403SDave Cobbley target are suitable (the target might be constrained, e.g. using 31eb8dc403SDave Cobbley busybox rather than bash with coreutils). 32eb8dc403SDave Cobbley """ 33eb8dc403SDave Cobbley lines = [] 34eb8dc403SDave Cobbley lines.append('#!/bin/sh') 35eb8dc403SDave Cobbley lines.append('set -e') 36eb8dc403SDave Cobbley if undeployall: 37eb8dc403SDave Cobbley # Yes, I know this is crude - but it does work 38eb8dc403SDave Cobbley lines.append('for entry in %s/*.list; do' % deploylist_path) 39eb8dc403SDave Cobbley lines.append('[ ! -f $entry ] && exit') 40eb8dc403SDave Cobbley lines.append('set `basename $entry | sed "s/.list//"`') 41eb8dc403SDave Cobbley if dryrun: 42eb8dc403SDave Cobbley if not deploy: 43eb8dc403SDave Cobbley lines.append('echo "Previously deployed files for $1:"') 44eb8dc403SDave Cobbley lines.append('manifest="%s/$1.list"' % deploylist_path) 45eb8dc403SDave Cobbley lines.append('preservedir="%s/$1.preserve"' % deploylist_path) 46eb8dc403SDave Cobbley lines.append('if [ -f $manifest ] ; then') 47eb8dc403SDave Cobbley # Read manifest in reverse and delete files / remove empty dirs 48eb8dc403SDave Cobbley lines.append(' sed \'1!G;h;$!d\' $manifest | while read file') 49eb8dc403SDave Cobbley lines.append(' do') 50eb8dc403SDave Cobbley if dryrun: 51eb8dc403SDave Cobbley lines.append(' if [ ! -d $file ] ; then') 52eb8dc403SDave Cobbley lines.append(' echo $file') 53eb8dc403SDave Cobbley lines.append(' fi') 54eb8dc403SDave Cobbley else: 55eb8dc403SDave Cobbley lines.append(' if [ -d $file ] ; then') 56eb8dc403SDave Cobbley # Avoid deleting a preserved directory in case it has special perms 57eb8dc403SDave Cobbley lines.append(' if [ ! -d $preservedir/$file ] ; then') 58eb8dc403SDave Cobbley lines.append(' rmdir $file > /dev/null 2>&1 || true') 59eb8dc403SDave Cobbley lines.append(' fi') 60eb8dc403SDave Cobbley lines.append(' else') 61eb8dc403SDave Cobbley lines.append(' rm -f $file') 62eb8dc403SDave Cobbley lines.append(' fi') 63eb8dc403SDave Cobbley lines.append(' done') 64eb8dc403SDave Cobbley if not dryrun: 65eb8dc403SDave Cobbley lines.append(' rm $manifest') 66eb8dc403SDave Cobbley if not deploy and not dryrun: 67eb8dc403SDave Cobbley # May as well remove all traces 68eb8dc403SDave Cobbley lines.append(' rmdir `dirname $manifest` > /dev/null 2>&1 || true') 69eb8dc403SDave Cobbley lines.append('fi') 70eb8dc403SDave Cobbley 71eb8dc403SDave Cobbley if deploy: 72eb8dc403SDave Cobbley if not nocheckspace: 73eb8dc403SDave Cobbley # Check for available space 74eb8dc403SDave Cobbley # FIXME This doesn't take into account files spread across multiple 75eb8dc403SDave Cobbley # partitions, but doing that is non-trivial 76eb8dc403SDave Cobbley # Find the part of the destination path that exists 77eb8dc403SDave Cobbley lines.append('checkpath="$2"') 78eb8dc403SDave Cobbley lines.append('while [ "$checkpath" != "/" ] && [ ! -e $checkpath ]') 79eb8dc403SDave Cobbley lines.append('do') 80eb8dc403SDave Cobbley lines.append(' checkpath=`dirname "$checkpath"`') 81eb8dc403SDave Cobbley lines.append('done') 82eb8dc403SDave Cobbley lines.append(r'freespace=$(df -P $checkpath | sed -nre "s/^(\S+\s+){3}([0-9]+).*/\2/p")') 83eb8dc403SDave Cobbley # First line of the file is the total space 84eb8dc403SDave Cobbley lines.append('total=`head -n1 $3`') 85eb8dc403SDave Cobbley lines.append('if [ $total -gt $freespace ] ; then') 86eb8dc403SDave Cobbley lines.append(' echo "ERROR: insufficient space on target (available ${freespace}, needed ${total})"') 87eb8dc403SDave Cobbley lines.append(' exit 1') 88eb8dc403SDave Cobbley lines.append('fi') 89eb8dc403SDave Cobbley if not nopreserve: 90eb8dc403SDave Cobbley # Preserve any files that exist. Note that this will add to the 91eb8dc403SDave Cobbley # preserved list with successive deployments if the list of files 92eb8dc403SDave Cobbley # deployed changes, but because we've deleted any previously 93eb8dc403SDave Cobbley # deployed files at this point it will never preserve anything 94eb8dc403SDave Cobbley # that was deployed, only files that existed prior to any deploying 95eb8dc403SDave Cobbley # (which makes the most sense) 96eb8dc403SDave Cobbley lines.append('cat $3 | sed "1d" | while read file fsize') 97eb8dc403SDave Cobbley lines.append('do') 98eb8dc403SDave Cobbley lines.append(' if [ -e $file ] ; then') 99eb8dc403SDave Cobbley lines.append(' dest="$preservedir/$file"') 100eb8dc403SDave Cobbley lines.append(' mkdir -p `dirname $dest`') 101eb8dc403SDave Cobbley lines.append(' mv $file $dest') 102eb8dc403SDave Cobbley lines.append(' fi') 103eb8dc403SDave Cobbley lines.append('done') 104eb8dc403SDave Cobbley lines.append('rm $3') 105eb8dc403SDave Cobbley lines.append('mkdir -p `dirname $manifest`') 106eb8dc403SDave Cobbley lines.append('mkdir -p $2') 107eb8dc403SDave Cobbley if verbose: 108eb8dc403SDave Cobbley lines.append(' tar xv -C $2 -f - | tee $manifest') 109eb8dc403SDave Cobbley else: 110eb8dc403SDave Cobbley lines.append(' tar xv -C $2 -f - > $manifest') 111eb8dc403SDave Cobbley lines.append('sed -i "s!^./!$2!" $manifest') 112eb8dc403SDave Cobbley elif not dryrun: 113eb8dc403SDave Cobbley # Put any preserved files back 114eb8dc403SDave Cobbley lines.append('if [ -d $preservedir ] ; then') 115eb8dc403SDave Cobbley lines.append(' cd $preservedir') 116eb8dc403SDave Cobbley # find from busybox might not have -exec, so we don't use that 117eb8dc403SDave Cobbley lines.append(' find . -type f | while read file') 118eb8dc403SDave Cobbley lines.append(' do') 119eb8dc403SDave Cobbley lines.append(' mv $file /$file') 120eb8dc403SDave Cobbley lines.append(' done') 121eb8dc403SDave Cobbley lines.append(' cd /') 122eb8dc403SDave Cobbley lines.append(' rm -rf $preservedir') 123eb8dc403SDave Cobbley lines.append('fi') 124eb8dc403SDave Cobbley 125eb8dc403SDave Cobbley if undeployall: 126eb8dc403SDave Cobbley if not dryrun: 127eb8dc403SDave Cobbley lines.append('echo "NOTE: Successfully undeployed $1"') 128eb8dc403SDave Cobbley lines.append('done') 129eb8dc403SDave Cobbley 130eb8dc403SDave Cobbley # Delete the script itself 131eb8dc403SDave Cobbley lines.append('rm $0') 132eb8dc403SDave Cobbley lines.append('') 133eb8dc403SDave Cobbley 134eb8dc403SDave Cobbley return '\n'.join(lines) 135eb8dc403SDave Cobbley 136eb8dc403SDave Cobbley 137eb8dc403SDave Cobbley 138eb8dc403SDave Cobbleydef deploy(args, config, basepath, workspace): 139eb8dc403SDave Cobbley """Entry point for the devtool 'deploy' subcommand""" 140eb8dc403SDave Cobbley import math 141eb8dc403SDave Cobbley import oe.recipeutils 142eb8dc403SDave Cobbley import oe.package 143*169d7bccSPatrick Williams import oe.utils 144eb8dc403SDave Cobbley 145eb8dc403SDave Cobbley check_workspace_recipe(workspace, args.recipename, checksrc=False) 146eb8dc403SDave Cobbley 147eb8dc403SDave Cobbley try: 148eb8dc403SDave Cobbley host, destdir = args.target.split(':') 149eb8dc403SDave Cobbley except ValueError: 150eb8dc403SDave Cobbley destdir = '/' 151eb8dc403SDave Cobbley else: 152eb8dc403SDave Cobbley args.target = host 153eb8dc403SDave Cobbley if not destdir.endswith('/'): 154eb8dc403SDave Cobbley destdir += '/' 155eb8dc403SDave Cobbley 156eb8dc403SDave Cobbley tinfoil = setup_tinfoil(basepath=basepath) 157eb8dc403SDave Cobbley try: 158eb8dc403SDave Cobbley try: 159eb8dc403SDave Cobbley rd = tinfoil.parse_recipe(args.recipename) 160eb8dc403SDave Cobbley except Exception as e: 161eb8dc403SDave Cobbley raise DevtoolError('Exception parsing recipe %s: %s' % 162eb8dc403SDave Cobbley (args.recipename, e)) 163eb8dc403SDave Cobbley recipe_outdir = rd.getVar('D') 164eb8dc403SDave Cobbley if not os.path.exists(recipe_outdir) or not os.listdir(recipe_outdir): 165eb8dc403SDave Cobbley raise DevtoolError('No files to deploy - have you built the %s ' 166eb8dc403SDave Cobbley 'recipe? If so, the install step has not installed ' 167eb8dc403SDave Cobbley 'any files.' % args.recipename) 168eb8dc403SDave Cobbley 169eb8dc403SDave Cobbley if args.strip and not args.dry_run: 170eb8dc403SDave Cobbley # Fakeroot copy to new destination 171eb8dc403SDave Cobbley srcdir = recipe_outdir 1725f35090dSAndrew Geissler recipe_outdir = os.path.join(rd.getVar('WORKDIR'), 'devtool-deploy-target-stripped') 173eb8dc403SDave Cobbley if os.path.isdir(recipe_outdir): 1747e0e3c0cSAndrew Geissler exec_fakeroot(rd, "rm -rf %s" % recipe_outdir, shell=True) 175eb8dc403SDave Cobbley exec_fakeroot(rd, "cp -af %s %s" % (os.path.join(srcdir, '.'), recipe_outdir), shell=True) 176eb8dc403SDave Cobbley os.environ['PATH'] = ':'.join([os.environ['PATH'], rd.getVar('PATH') or '']) 177eb8dc403SDave Cobbley oe.package.strip_execs(args.recipename, recipe_outdir, rd.getVar('STRIP'), rd.getVar('libdir'), 178*169d7bccSPatrick Williams rd.getVar('base_libdir'), oe.utils.get_bb_number_threads(rd), rd) 179eb8dc403SDave Cobbley 180eb8dc403SDave Cobbley filelist = [] 181c9f7865aSAndrew Geissler inodes = set({}) 182eb8dc403SDave Cobbley ftotalsize = 0 183eb8dc403SDave Cobbley for root, _, files in os.walk(recipe_outdir): 184eb8dc403SDave Cobbley for fn in files: 185c9f7865aSAndrew Geissler fstat = os.lstat(os.path.join(root, fn)) 186eb8dc403SDave Cobbley # Get the size in kiB (since we'll be comparing it to the output of du -k) 187eb8dc403SDave Cobbley # MUST use lstat() here not stat() or getfilesize() since we don't want to 188eb8dc403SDave Cobbley # dereference symlinks 189c9f7865aSAndrew Geissler if fstat.st_ino in inodes: 190c9f7865aSAndrew Geissler fsize = 0 191c9f7865aSAndrew Geissler else: 192c9f7865aSAndrew Geissler fsize = int(math.ceil(float(fstat.st_size)/1024)) 193c9f7865aSAndrew Geissler inodes.add(fstat.st_ino) 194eb8dc403SDave Cobbley ftotalsize += fsize 195eb8dc403SDave Cobbley # The path as it would appear on the target 196eb8dc403SDave Cobbley fpath = os.path.join(destdir, os.path.relpath(root, recipe_outdir), fn) 197eb8dc403SDave Cobbley filelist.append((fpath, fsize)) 198eb8dc403SDave Cobbley 199eb8dc403SDave Cobbley if args.dry_run: 200eb8dc403SDave Cobbley print('Files to be deployed for %s on target %s:' % (args.recipename, args.target)) 201eb8dc403SDave Cobbley for item, _ in filelist: 202eb8dc403SDave Cobbley print(' %s' % item) 203eb8dc403SDave Cobbley return 0 204eb8dc403SDave Cobbley 205eb8dc403SDave Cobbley extraoptions = '' 206eb8dc403SDave Cobbley if args.no_host_check: 207eb8dc403SDave Cobbley extraoptions += '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' 208eb8dc403SDave Cobbley if not args.show_status: 209eb8dc403SDave Cobbley extraoptions += ' -q' 210eb8dc403SDave Cobbley 21119323693SBrad Bishop scp_sshexec = '' 21219323693SBrad Bishop ssh_sshexec = 'ssh' 21319323693SBrad Bishop if args.ssh_exec: 21419323693SBrad Bishop scp_sshexec = "-S %s" % args.ssh_exec 21519323693SBrad Bishop ssh_sshexec = args.ssh_exec 216eb8dc403SDave Cobbley scp_port = '' 217eb8dc403SDave Cobbley ssh_port = '' 218eb8dc403SDave Cobbley if args.port: 219eb8dc403SDave Cobbley scp_port = "-P %s" % args.port 220eb8dc403SDave Cobbley ssh_port = "-p %s" % args.port 221eb8dc403SDave Cobbley 22264c979e8SBrad Bishop if args.key: 22364c979e8SBrad Bishop extraoptions += ' -i %s' % args.key 22464c979e8SBrad Bishop 225eb8dc403SDave Cobbley # In order to delete previously deployed files and have the manifest file on 226eb8dc403SDave Cobbley # the target, we write out a shell script and then copy it to the target 227eb8dc403SDave Cobbley # so we can then run it (piping tar output to it). 228eb8dc403SDave Cobbley # (We cannot use scp here, because it doesn't preserve symlinks.) 229eb8dc403SDave Cobbley tmpdir = tempfile.mkdtemp(prefix='devtool') 230eb8dc403SDave Cobbley try: 231eb8dc403SDave Cobbley tmpscript = '/tmp/devtool_deploy.sh' 232eb8dc403SDave Cobbley tmpfilelist = os.path.join(os.path.dirname(tmpscript), 'devtool_deploy.list') 233eb8dc403SDave Cobbley shellscript = _prepare_remote_script(deploy=True, 234eb8dc403SDave Cobbley verbose=args.show_status, 235eb8dc403SDave Cobbley nopreserve=args.no_preserve, 236eb8dc403SDave Cobbley nocheckspace=args.no_check_space) 237eb8dc403SDave Cobbley # Write out the script to a file 238eb8dc403SDave Cobbley with open(os.path.join(tmpdir, os.path.basename(tmpscript)), 'w') as f: 239eb8dc403SDave Cobbley f.write(shellscript) 240eb8dc403SDave Cobbley # Write out the file list 241eb8dc403SDave Cobbley with open(os.path.join(tmpdir, os.path.basename(tmpfilelist)), 'w') as f: 242eb8dc403SDave Cobbley f.write('%d\n' % ftotalsize) 243eb8dc403SDave Cobbley for fpath, fsize in filelist: 244eb8dc403SDave Cobbley f.write('%s %d\n' % (fpath, fsize)) 245eb8dc403SDave Cobbley # Copy them to the target 24619323693SBrad Bishop ret = subprocess.call("scp %s %s %s %s/* %s:%s" % (scp_sshexec, scp_port, extraoptions, tmpdir, args.target, os.path.dirname(tmpscript)), shell=True) 247eb8dc403SDave Cobbley if ret != 0: 248eb8dc403SDave Cobbley raise DevtoolError('Failed to copy script to %s - rerun with -s to ' 249eb8dc403SDave Cobbley 'get a complete error message' % args.target) 250eb8dc403SDave Cobbley finally: 251eb8dc403SDave Cobbley shutil.rmtree(tmpdir) 252eb8dc403SDave Cobbley 253eb8dc403SDave Cobbley # Now run the script 25419323693SBrad Bishop ret = exec_fakeroot(rd, 'tar cf - . | %s %s %s %s \'sh %s %s %s %s\'' % (ssh_sshexec, ssh_port, extraoptions, args.target, tmpscript, args.recipename, destdir, tmpfilelist), cwd=recipe_outdir, shell=True) 255eb8dc403SDave Cobbley if ret != 0: 256eb8dc403SDave Cobbley raise DevtoolError('Deploy failed - rerun with -s to get a complete ' 257eb8dc403SDave Cobbley 'error message') 258eb8dc403SDave Cobbley 259eb8dc403SDave Cobbley logger.info('Successfully deployed %s' % recipe_outdir) 260eb8dc403SDave Cobbley 261eb8dc403SDave Cobbley files_list = [] 262eb8dc403SDave Cobbley for root, _, files in os.walk(recipe_outdir): 263eb8dc403SDave Cobbley for filename in files: 264eb8dc403SDave Cobbley filename = os.path.relpath(os.path.join(root, filename), recipe_outdir) 265eb8dc403SDave Cobbley files_list.append(os.path.join(destdir, filename)) 266eb8dc403SDave Cobbley finally: 267eb8dc403SDave Cobbley tinfoil.shutdown() 268eb8dc403SDave Cobbley 269eb8dc403SDave Cobbley return 0 270eb8dc403SDave Cobbley 271eb8dc403SDave Cobbleydef undeploy(args, config, basepath, workspace): 272eb8dc403SDave Cobbley """Entry point for the devtool 'undeploy' subcommand""" 273eb8dc403SDave Cobbley if args.all and args.recipename: 274eb8dc403SDave Cobbley raise argparse_oe.ArgumentUsageError('Cannot specify -a/--all with a recipe name', 'undeploy-target') 275eb8dc403SDave Cobbley elif not args.recipename and not args.all: 276eb8dc403SDave Cobbley raise argparse_oe.ArgumentUsageError('If you don\'t specify a recipe, you must specify -a/--all', 'undeploy-target') 277eb8dc403SDave Cobbley 278eb8dc403SDave Cobbley extraoptions = '' 279eb8dc403SDave Cobbley if args.no_host_check: 280eb8dc403SDave Cobbley extraoptions += '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' 281eb8dc403SDave Cobbley if not args.show_status: 282eb8dc403SDave Cobbley extraoptions += ' -q' 283eb8dc403SDave Cobbley 28419323693SBrad Bishop scp_sshexec = '' 28519323693SBrad Bishop ssh_sshexec = 'ssh' 28619323693SBrad Bishop if args.ssh_exec: 28719323693SBrad Bishop scp_sshexec = "-S %s" % args.ssh_exec 28819323693SBrad Bishop ssh_sshexec = args.ssh_exec 289eb8dc403SDave Cobbley scp_port = '' 290eb8dc403SDave Cobbley ssh_port = '' 291eb8dc403SDave Cobbley if args.port: 292eb8dc403SDave Cobbley scp_port = "-P %s" % args.port 293eb8dc403SDave Cobbley ssh_port = "-p %s" % args.port 294eb8dc403SDave Cobbley 295eb8dc403SDave Cobbley args.target = args.target.split(':')[0] 296eb8dc403SDave Cobbley 297eb8dc403SDave Cobbley tmpdir = tempfile.mkdtemp(prefix='devtool') 298eb8dc403SDave Cobbley try: 299eb8dc403SDave Cobbley tmpscript = '/tmp/devtool_undeploy.sh' 300eb8dc403SDave Cobbley shellscript = _prepare_remote_script(deploy=False, dryrun=args.dry_run, undeployall=args.all) 301eb8dc403SDave Cobbley # Write out the script to a file 302eb8dc403SDave Cobbley with open(os.path.join(tmpdir, os.path.basename(tmpscript)), 'w') as f: 303eb8dc403SDave Cobbley f.write(shellscript) 304eb8dc403SDave Cobbley # Copy it to the target 30519323693SBrad Bishop ret = subprocess.call("scp %s %s %s %s/* %s:%s" % (scp_sshexec, scp_port, extraoptions, tmpdir, args.target, os.path.dirname(tmpscript)), shell=True) 306eb8dc403SDave Cobbley if ret != 0: 307eb8dc403SDave Cobbley raise DevtoolError('Failed to copy script to %s - rerun with -s to ' 308eb8dc403SDave Cobbley 'get a complete error message' % args.target) 309eb8dc403SDave Cobbley finally: 310eb8dc403SDave Cobbley shutil.rmtree(tmpdir) 311eb8dc403SDave Cobbley 312eb8dc403SDave Cobbley # Now run the script 31319323693SBrad Bishop ret = subprocess.call('%s %s %s %s \'sh %s %s\'' % (ssh_sshexec, ssh_port, extraoptions, args.target, tmpscript, args.recipename), shell=True) 314eb8dc403SDave Cobbley if ret != 0: 315eb8dc403SDave Cobbley raise DevtoolError('Undeploy failed - rerun with -s to get a complete ' 316eb8dc403SDave Cobbley 'error message') 317eb8dc403SDave Cobbley 318eb8dc403SDave Cobbley if not args.all and not args.dry_run: 319eb8dc403SDave Cobbley logger.info('Successfully undeployed %s' % args.recipename) 320eb8dc403SDave Cobbley return 0 321eb8dc403SDave Cobbley 322eb8dc403SDave Cobbley 323eb8dc403SDave Cobbleydef register_commands(subparsers, context): 324eb8dc403SDave Cobbley """Register devtool subcommands from the deploy plugin""" 325eb8dc403SDave Cobbley 326eb8dc403SDave Cobbley parser_deploy = subparsers.add_parser('deploy-target', 327eb8dc403SDave Cobbley help='Deploy recipe output files to live target machine', 328eb8dc403SDave Cobbley description='Deploys a recipe\'s build output (i.e. the output of the do_install task) to a live target machine over ssh. By default, any existing files will be preserved instead of being overwritten and will be restored if you run devtool undeploy-target. Note: this only deploys the recipe itself and not any runtime dependencies, so it is assumed that those have been installed on the target beforehand.', 329eb8dc403SDave Cobbley group='testbuild') 330eb8dc403SDave Cobbley parser_deploy.add_argument('recipename', help='Recipe to deploy') 331eb8dc403SDave Cobbley parser_deploy.add_argument('target', help='Live target machine running an ssh server: user@hostname[:destdir]') 332eb8dc403SDave Cobbley parser_deploy.add_argument('-c', '--no-host-check', help='Disable ssh host key checking', action='store_true') 333eb8dc403SDave Cobbley parser_deploy.add_argument('-s', '--show-status', help='Show progress/status output', action='store_true') 334eb8dc403SDave Cobbley parser_deploy.add_argument('-n', '--dry-run', help='List files to be deployed only', action='store_true') 335eb8dc403SDave Cobbley parser_deploy.add_argument('-p', '--no-preserve', help='Do not preserve existing files', action='store_true') 336eb8dc403SDave Cobbley parser_deploy.add_argument('--no-check-space', help='Do not check for available space before deploying', action='store_true') 33719323693SBrad Bishop parser_deploy.add_argument('-e', '--ssh-exec', help='Executable to use in place of ssh') 338eb8dc403SDave Cobbley parser_deploy.add_argument('-P', '--port', help='Specify port to use for connection to the target') 33964c979e8SBrad Bishop parser_deploy.add_argument('-I', '--key', 340d25ed324SAndrew Geissler help='Specify ssh private key for connection to the target') 341eb8dc403SDave Cobbley 342eb8dc403SDave Cobbley strip_opts = parser_deploy.add_mutually_exclusive_group(required=False) 343eb8dc403SDave Cobbley strip_opts.add_argument('-S', '--strip', 344eb8dc403SDave Cobbley help='Strip executables prior to deploying (default: %(default)s). ' 345eb8dc403SDave Cobbley 'The default value of this option can be controlled by setting the strip option in the [Deploy] section to True or False.', 346eb8dc403SDave Cobbley default=oe.types.boolean(context.config.get('Deploy', 'strip', default='0')), 347eb8dc403SDave Cobbley action='store_true') 348eb8dc403SDave Cobbley strip_opts.add_argument('--no-strip', help='Do not strip executables prior to deploy', dest='strip', action='store_false') 349eb8dc403SDave Cobbley 350eb8dc403SDave Cobbley parser_deploy.set_defaults(func=deploy) 351eb8dc403SDave Cobbley 352eb8dc403SDave Cobbley parser_undeploy = subparsers.add_parser('undeploy-target', 353eb8dc403SDave Cobbley help='Undeploy recipe output files in live target machine', 354eb8dc403SDave Cobbley description='Un-deploys recipe output files previously deployed to a live target machine by devtool deploy-target.', 355eb8dc403SDave Cobbley group='testbuild') 356eb8dc403SDave Cobbley parser_undeploy.add_argument('recipename', help='Recipe to undeploy (if not using -a/--all)', nargs='?') 357eb8dc403SDave Cobbley parser_undeploy.add_argument('target', help='Live target machine running an ssh server: user@hostname') 358eb8dc403SDave Cobbley parser_undeploy.add_argument('-c', '--no-host-check', help='Disable ssh host key checking', action='store_true') 359eb8dc403SDave Cobbley parser_undeploy.add_argument('-s', '--show-status', help='Show progress/status output', action='store_true') 360eb8dc403SDave Cobbley parser_undeploy.add_argument('-a', '--all', help='Undeploy all recipes deployed on the target', action='store_true') 361eb8dc403SDave Cobbley parser_undeploy.add_argument('-n', '--dry-run', help='List files to be undeployed only', action='store_true') 36219323693SBrad Bishop parser_undeploy.add_argument('-e', '--ssh-exec', help='Executable to use in place of ssh') 363eb8dc403SDave Cobbley parser_undeploy.add_argument('-P', '--port', help='Specify port to use for connection to the target') 36464c979e8SBrad Bishop parser_undeploy.add_argument('-I', '--key', 365d25ed324SAndrew Geissler help='Specify ssh private key for connection to the target') 36664c979e8SBrad Bishop 367eb8dc403SDave Cobbley parser_undeploy.set_defaults(func=undeploy) 368