diff options
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/lib/devtool/deploy.py | 144 |
1 files changed, 103 insertions, 41 deletions
diff --git a/scripts/lib/devtool/deploy.py b/scripts/lib/devtool/deploy.py index d742ed3f8e..d2a314b236 100644 --- a/scripts/lib/devtool/deploy.py +++ b/scripts/lib/devtool/deploy.py | |||
@@ -1,6 +1,6 @@ | |||
1 | # Development tool - deploy/undeploy command plugin | 1 | # Development tool - deploy/undeploy command plugin |
2 | # | 2 | # |
3 | # Copyright (C) 2014-2015 Intel Corporation | 3 | # Copyright (C) 2014-2016 Intel Corporation |
4 | # | 4 | # |
5 | # This program is free software; you can redistribute it and/or modify | 5 | # This program is free software; you can redistribute it and/or modify |
6 | # it under the terms of the GNU General Public License version 2 as | 6 | # it under the terms of the GNU General Public License version 2 as |
@@ -19,10 +19,57 @@ | |||
19 | import os | 19 | import os |
20 | import subprocess | 20 | import subprocess |
21 | import logging | 21 | import logging |
22 | import tempfile | ||
23 | import shutil | ||
22 | from devtool import exec_fakeroot, setup_tinfoil, check_workspace_recipe, DevtoolError | 24 | from devtool import exec_fakeroot, setup_tinfoil, check_workspace_recipe, DevtoolError |
23 | 25 | ||
24 | logger = logging.getLogger('devtool') | 26 | logger = logging.getLogger('devtool') |
25 | 27 | ||
28 | deploylist_path = '/.devtool' | ||
29 | |||
30 | def _prepare_remote_script(deploy, verbose=False): | ||
31 | """ | ||
32 | Prepare a shell script for running on the target to | ||
33 | deploy/undeploy files. We have to be careful what we put in this | ||
34 | script - only commands that are likely to be available on the | ||
35 | target are suitable (the target might be constrained, e.g. using | ||
36 | busybox rather than bash with coreutils). | ||
37 | """ | ||
38 | lines = [] | ||
39 | lines.append('#!/bin/sh') | ||
40 | lines.append('set -e') | ||
41 | lines.append('manifest="%s/$1.list"' % deploylist_path) | ||
42 | lines.append('if [ -f $manifest ] ; then') | ||
43 | # Read manifest in reverse and delete files / remove empty dirs | ||
44 | lines.append(' sed \'1!G;h;$!d\' $manifest | while read file') | ||
45 | lines.append(' do') | ||
46 | lines.append(' if [ -d $file ] ; then') | ||
47 | lines.append(' rmdir $file > /dev/null 2>&1 || true') | ||
48 | lines.append(' else') | ||
49 | lines.append(' rm $file') | ||
50 | lines.append(' fi') | ||
51 | lines.append(' done') | ||
52 | lines.append(' rm $manifest') | ||
53 | if not deploy: | ||
54 | # May as well remove all traces | ||
55 | lines.append(' rmdir `dirname $manifest` > /dev/null 2>&1 || true') | ||
56 | lines.append('fi') | ||
57 | |||
58 | if deploy: | ||
59 | lines.append('mkdir -p `dirname $manifest`') | ||
60 | lines.append('mkdir -p $2') | ||
61 | if verbose: | ||
62 | lines.append(' tar xv -C $2 -f - | tee $manifest') | ||
63 | else: | ||
64 | lines.append(' tar xv -C $2 -f - > $manifest') | ||
65 | lines.append('sed -i "s!^./!$2!" $manifest') | ||
66 | # Delete the script itself | ||
67 | lines.append('rm $0') | ||
68 | lines.append('') | ||
69 | |||
70 | return '\n'.join(lines) | ||
71 | |||
72 | |||
26 | def deploy(args, config, basepath, workspace): | 73 | def deploy(args, config, basepath, workspace): |
27 | """Entry point for the devtool 'deploy' subcommand""" | 74 | """Entry point for the devtool 'deploy' subcommand""" |
28 | import re | 75 | import re |
@@ -36,9 +83,8 @@ def deploy(args, config, basepath, workspace): | |||
36 | destdir = '/' | 83 | destdir = '/' |
37 | else: | 84 | else: |
38 | args.target = host | 85 | args.target = host |
39 | 86 | if not destdir.endswith('/'): | |
40 | deploy_dir = os.path.join(basepath, 'target_deploy', args.target) | 87 | destdir += '/' |
41 | deploy_file = os.path.join(deploy_dir, args.recipename + '.list') | ||
42 | 88 | ||
43 | tinfoil = setup_tinfoil(basepath=basepath) | 89 | tinfoil = setup_tinfoil(basepath=basepath) |
44 | try: | 90 | try: |
@@ -59,74 +105,90 @@ def deploy(args, config, basepath, workspace): | |||
59 | print(' %s' % os.path.join(destdir, os.path.relpath(root, recipe_outdir), fn)) | 105 | print(' %s' % os.path.join(destdir, os.path.relpath(root, recipe_outdir), fn)) |
60 | return 0 | 106 | return 0 |
61 | 107 | ||
62 | if os.path.exists(deploy_file): | ||
63 | if undeploy(args, config, basepath, workspace): | ||
64 | # Error already shown | ||
65 | return 1 | ||
66 | 108 | ||
67 | extraoptions = '' | 109 | extraoptions = '' |
68 | if args.no_host_check: | 110 | if args.no_host_check: |
69 | extraoptions += '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' | 111 | extraoptions += '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' |
70 | if args.show_status: | 112 | if not args.show_status: |
71 | tarextractopts = 'xv' | ||
72 | else: | ||
73 | tarextractopts = 'x' | ||
74 | extraoptions += ' -q' | 113 | extraoptions += ' -q' |
75 | # We cannot use scp here, because it doesn't preserve symlinks | 114 | |
76 | ret = exec_fakeroot(rd, 'tar cf - . | ssh %s %s \'tar %s -C %s -f -\'' % (extraoptions, args.target, tarextractopts, destdir), cwd=recipe_outdir, shell=True) | 115 | # In order to delete previously deployed files and have the manifest file on |
116 | # the target, we write out a shell script and then copy it to the target | ||
117 | # so we can then run it (piping tar output to it). | ||
118 | # (We cannot use scp here, because it doesn't preserve symlinks.) | ||
119 | tmpdir = tempfile.mkdtemp(prefix='devtool') | ||
120 | try: | ||
121 | tmpscript = '/tmp/devtool_deploy.sh' | ||
122 | shellscript = _prepare_remote_script(deploy=True, verbose=args.show_status) | ||
123 | # Write out the script to a file | ||
124 | with open(os.path.join(tmpdir, os.path.basename(tmpscript)), 'w') as f: | ||
125 | f.write(shellscript) | ||
126 | # Copy it to the target | ||
127 | ret = subprocess.call("scp %s %s/* %s:%s" % (extraoptions, tmpdir, args.target, os.path.dirname(tmpscript)), shell=True) | ||
128 | if ret != 0: | ||
129 | raise DevtoolError('Failed to copy script to %s - rerun with -s to ' | ||
130 | 'get a complete error message' % args.target) | ||
131 | finally: | ||
132 | shutil.rmtree(tmpdir) | ||
133 | |||
134 | # Now run the script | ||
135 | ret = exec_fakeroot(rd, 'tar cf - . | ssh %s %s \'sh %s %s %s\'' % (extraoptions, args.target, tmpscript, args.recipename, destdir), cwd=recipe_outdir, shell=True) | ||
77 | if ret != 0: | 136 | if ret != 0: |
78 | raise DevtoolError('Deploy failed - rerun with -s to get a complete ' | 137 | raise DevtoolError('Deploy failed - rerun with -s to get a complete ' |
79 | 'error message') | 138 | 'error message') |
80 | 139 | ||
81 | logger.info('Successfully deployed %s' % recipe_outdir) | 140 | logger.info('Successfully deployed %s' % recipe_outdir) |
82 | 141 | ||
83 | if not os.path.exists(deploy_dir): | ||
84 | os.makedirs(deploy_dir) | ||
85 | |||
86 | files_list = [] | 142 | files_list = [] |
87 | for root, _, files in os.walk(recipe_outdir): | 143 | for root, _, files in os.walk(recipe_outdir): |
88 | for filename in files: | 144 | for filename in files: |
89 | filename = os.path.relpath(os.path.join(root, filename), recipe_outdir) | 145 | filename = os.path.relpath(os.path.join(root, filename), recipe_outdir) |
90 | files_list.append(os.path.join(destdir, filename)) | 146 | files_list.append(os.path.join(destdir, filename)) |
91 | 147 | ||
92 | with open(deploy_file, 'w') as fobj: | ||
93 | fobj.write('\n'.join(files_list)) | ||
94 | |||
95 | return 0 | 148 | return 0 |
96 | 149 | ||
97 | def undeploy(args, config, basepath, workspace): | 150 | def undeploy(args, config, basepath, workspace): |
98 | """Entry point for the devtool 'undeploy' subcommand""" | 151 | """Entry point for the devtool 'undeploy' subcommand""" |
99 | deploy_file = os.path.join(basepath, 'target_deploy', args.target, args.recipename + '.list') | ||
100 | if not os.path.exists(deploy_file): | ||
101 | raise DevtoolError('%s has not been deployed' % args.recipename) | ||
102 | |||
103 | if args.dry_run: | ||
104 | print('Previously deployed files to be un-deployed for %s on target %s:' % (args.recipename, args.target)) | ||
105 | with open(deploy_file, 'r') as f: | ||
106 | for line in f: | ||
107 | print(' %s' % line.rstrip()) | ||
108 | return 0 | ||
109 | |||
110 | extraoptions = '' | 152 | extraoptions = '' |
111 | if args.no_host_check: | 153 | if args.no_host_check: |
112 | extraoptions += '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' | 154 | extraoptions += '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' |
113 | if not args.show_status: | 155 | if not args.show_status: |
114 | extraoptions += ' -q' | 156 | extraoptions += ' -q' |
115 | 157 | ||
116 | ret = subprocess.call("scp %s %s %s:/tmp" % (extraoptions, deploy_file, args.target), shell=True) | 158 | args.target = args.target.split(':')[0] |
117 | if ret != 0: | ||
118 | raise DevtoolError('Failed to copy file list to %s - rerun with -s to ' | ||
119 | 'get a complete error message' % args.target) | ||
120 | 159 | ||
121 | ret = subprocess.call("ssh %s %s 'xargs -n1 rm -f </tmp/%s'" % (extraoptions, args.target, os.path.basename(deploy_file)), shell=True) | 160 | if args.dry_run: |
122 | if ret == 0: | 161 | listfile = os.path.join(deploylist_path, '%s.list' % args.recipename) |
123 | logger.info('Successfully undeployed %s' % args.recipename) | 162 | print('Previously deployed files to be un-deployed for %s on target %s:' % (args.recipename, args.target)) |
124 | os.remove(deploy_file) | 163 | ret = subprocess.call('ssh %s %s \'[ -f %s ] && cat %s || true\'' % (extraoptions, args.target, listfile, listfile), shell=True) |
125 | else: | 164 | if ret != 0: |
165 | raise DevtoolError('Undeploy failed - rerun with -s to get a complete ' | ||
166 | 'error message') | ||
167 | return 0 | ||
168 | |||
169 | tmpdir = tempfile.mkdtemp(prefix='devtool') | ||
170 | try: | ||
171 | tmpscript = '/tmp/devtool_undeploy.sh' | ||
172 | shellscript = _prepare_remote_script(deploy=False) | ||
173 | # Write out the script to a file | ||
174 | with open(os.path.join(tmpdir, os.path.basename(tmpscript)), 'w') as f: | ||
175 | f.write(shellscript) | ||
176 | # Copy it to the target | ||
177 | ret = subprocess.call("scp %s %s/* %s:%s" % (extraoptions, tmpdir, args.target, os.path.dirname(tmpscript)), shell=True) | ||
178 | if ret != 0: | ||
179 | raise DevtoolError('Failed to copy script to %s - rerun with -s to ' | ||
180 | 'get a complete error message' % args.target) | ||
181 | finally: | ||
182 | shutil.rmtree(tmpdir) | ||
183 | |||
184 | # Now run the script | ||
185 | ret = subprocess.call('ssh %s %s \'sh %s %s\'' % (extraoptions, args.target, tmpscript, args.recipename), shell=True) | ||
186 | if ret != 0: | ||
126 | raise DevtoolError('Undeploy failed - rerun with -s to get a complete ' | 187 | raise DevtoolError('Undeploy failed - rerun with -s to get a complete ' |
127 | 'error message') | 188 | 'error message') |
128 | 189 | ||
129 | return ret | 190 | logger.info('Successfully undeployed %s' % args.recipename) |
191 | return 0 | ||
130 | 192 | ||
131 | 193 | ||
132 | def register_commands(subparsers, context): | 194 | def register_commands(subparsers, context): |