Add new option of --run_script
[tools/mic.git] / plugins / imager / loop_plugin.py
1 #!/usr/bin/python -tt
2 #
3 # Copyright (c) 2011 Intel, Inc.
4 #
5 # This program is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by the Free
7 # Software Foundation; version 2 of the License
8 #
9 # This program is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 # for more details.
13 #
14 # You should have received a copy of the GNU General Public License along
15 # with this program; if not, write to the Free Software Foundation, Inc., 59
16 # Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 import os
19 import subprocess
20 import shutil
21 import tempfile
22
23 from mic import chroot, msger, rt_util
24 from mic.utils import misc, fs_related, errors
25 from mic.conf import configmgr
26 from mic.plugin import pluginmgr
27 from mic.imager.loop import LoopImageCreator, load_mountpoints
28
29 from mic.pluginbase import ImagerPlugin
30 class LoopPlugin(ImagerPlugin):
31     name = 'loop'
32
33     @classmethod
34     def do_create(self, args):
35         """${cmd_name}: create loop image
36
37         Usage:
38             ${name} ${cmd_name} <ksfile> [OPTS]
39
40         ${cmd_option_list}
41         """
42
43         if args is None:
44             raise errors.Usage("Invalid arguments")
45
46         creatoropts = configmgr.create
47         ksconf = args.ksfile
48
49         if creatoropts['runtime'] == "bootstrap":
50             configmgr._ksconf = ksconf
51             rt_util.bootstrap_mic()
52
53         recording_pkgs = []
54         if len(creatoropts['record_pkgs']) > 0:
55             recording_pkgs = creatoropts['record_pkgs']
56
57         if creatoropts['release'] is not None:
58             if 'name' not in recording_pkgs:
59                 recording_pkgs.append('name')
60             if 'vcs' not in recording_pkgs:
61                 recording_pkgs.append('vcs')
62
63         configmgr._ksconf = ksconf
64
65         # try to find the pkgmgr
66         pkgmgr = None
67         backends = pluginmgr.get_plugins('backend')
68         if 'auto' == creatoropts['pkgmgr']:
69             for key in configmgr.prefer_backends:
70                 if key in backends:
71                     pkgmgr = backends[key]
72                     break
73         else:
74             for key in backends.keys():
75                 if key == creatoropts['pkgmgr']:
76                     pkgmgr = backends[key]
77                     break
78
79         if not pkgmgr:
80             raise errors.CreatorError("Can't find backend: %s, "
81                                       "available choices: %s" %
82                                       (creatoropts['pkgmgr'],
83                                        ','.join(backends.keys())))
84
85         creator = LoopImageCreator(creatoropts,
86                                    pkgmgr,
87                                    args.compress_image,
88                                    args.shrink)
89
90         if len(recording_pkgs) > 0:
91             creator._recording_pkgs = recording_pkgs
92
93         image_names = [creator.name + ".img"]
94         image_names.extend(creator.get_image_names())
95         self.check_image_exists(creator.destdir,
96                                 creator.pack_to,
97                                 image_names,
98                                 creatoropts['release'])
99
100         try:
101             creator.check_depend_tools()
102             creator.mount(None, creatoropts["cachedir"])
103             creator.install()
104             creator.configure(creatoropts["repomd"])
105             creator.copy_kernel()
106             creator.create_cpio_image()
107             creator.unmount()
108             creator.copy_cpio_image()
109             creator.package(creatoropts["destdir"])
110             creator.create_manifest()
111
112             if creatoropts['release'] is not None:
113                 creator.release_output(ksconf,
114                                        creatoropts['destdir'],
115                                        creatoropts['release'])
116             creator.print_outimage_info()
117
118         except errors.CreatorError:
119             raise
120         finally:
121             creator.cleanup()
122
123         #Run script of --run_script after image created
124         if creatoropts['run_script']:
125             cmd = creatoropts['run_script']
126             msger.info("Running command in parameter run_script: "+"".join(cmd))
127             try:
128                 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
129                 p.communicate()
130             except OSError,err:
131                 msger.warning(str(err))
132
133         msger.info("Finished.")
134         return 0
135
136     @classmethod
137     def _do_chroot_tar(cls, target, cmd=[]):
138         mountfp_xml = os.path.splitext(target)[0] + '.xml'
139         if not os.path.exists(mountfp_xml):
140             raise errors.CreatorError("No mount point file found for this tar "
141                                       "image, please check %s" % mountfp_xml)
142
143         import tarfile
144         tar = tarfile.open(target, 'r')
145         tmpdir = misc.mkdtemp()
146         tar.extractall(path=tmpdir)
147         tar.close()
148
149         mntdir = misc.mkdtemp()
150
151         loops = []
152         for (mp, label, name, size, fstype) in load_mountpoints(mountfp_xml):
153             if fstype in ("ext2", "ext3", "ext4"):
154                 myDiskMount = fs_related.ExtDiskMount
155             elif fstype == "btrfs":
156                 myDiskMount = fs_related.BtrfsDiskMount
157             elif fstype in ("vfat", "msdos"):
158                 myDiskMount = fs_related.VfatDiskMount
159             else:
160                 raise errors.CreatorError("Cannot support fstype: %s" % fstype)
161
162             name = os.path.join(tmpdir, name)
163             size = size * 1024L * 1024L
164             loop = myDiskMount(fs_related.SparseLoopbackDisk(name, size),
165                                os.path.join(mntdir, mp.lstrip('/')),
166                                fstype, size, label)
167
168             try:
169                 msger.verbose("Mount %s to %s" % (mp, mntdir + mp))
170                 fs_related.makedirs(os.path.join(mntdir, mp.lstrip('/')))
171                 loop.mount()
172
173             except:
174                 loop.cleanup()
175                 for lp in reversed(loops):
176                     chroot.cleanup_after_chroot("img", lp, None, mntdir)
177
178                 shutil.rmtree(tmpdir, ignore_errors=True)
179                 raise
180
181             loops.append(loop)
182
183         try:
184             if len(cmd) != 0:
185                 cmdline = "/usr/bin/env HOME=/root " + ' '.join(cmd)
186             else:
187                 cmdline = "/usr/bin/env HOME=/root /bin/bash"
188             chroot.chroot(mntdir, None, cmdline)
189         except:
190             raise errors.CreatorError("Failed to chroot to %s." % target)
191         finally:
192             for loop in reversed(loops):
193                 chroot.cleanup_after_chroot("img", loop, None, mntdir)
194
195             shutil.rmtree(tmpdir, ignore_errors=True)
196
197     @classmethod
198     def do_chroot(cls, target, cmd=[]):
199         if target.endswith('.tar'):
200             import tarfile
201             if tarfile.is_tarfile(target):
202                 LoopPlugin._do_chroot_tar(target, cmd)
203                 return
204             else:
205                 raise errors.CreatorError("damaged tarball for loop images")
206
207         img = target
208         imgsize = misc.get_file_size(img) * 1024L * 1024L
209         imgtype = misc.get_image_type(img)
210         if imgtype == "btrfsimg":
211             fstype = "btrfs"
212             myDiskMount = fs_related.BtrfsDiskMount
213         elif imgtype in ("ext3fsimg", "ext4fsimg"):
214             fstype = imgtype[:4]
215             myDiskMount = fs_related.ExtDiskMount
216         else:
217             raise errors.CreatorError("Unsupported filesystem type: %s" \
218                                       % imgtype)
219
220         extmnt = misc.mkdtemp()
221         extloop = myDiskMount(fs_related.SparseLoopbackDisk(img, imgsize),
222                                                          extmnt,
223                                                          fstype,
224                                                          4096,
225                                                          "%s label" % fstype)
226         try:
227             extloop.mount()
228
229         except errors.MountError:
230             extloop.cleanup()
231             shutil.rmtree(extmnt, ignore_errors=True)
232             raise
233
234         try:
235             if cmd is not None:
236                 cmdline = cmd
237             else:
238                 cmdline = "/bin/bash"
239             envcmd = fs_related.find_binary_inchroot("env", extmnt)
240             if envcmd:
241                 cmdline = "%s HOME=/root %s" % (envcmd, cmdline)
242             chroot.chroot(extmnt, None, cmdline)
243         except:
244             raise errors.CreatorError("Failed to chroot to %s." % img)
245         finally:
246             chroot.cleanup_after_chroot("img", extloop, None, extmnt)
247
248     @classmethod
249     def do_unpack(cls, srcimg):
250         image = os.path.join(tempfile.mkdtemp(dir="/var/tmp", prefix="tmp"),
251                              "target.img")
252         msger.info("Copying file system ...")
253         shutil.copyfile(srcimg, image)
254         return image