Using argparse module to parse the cmd line
[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 shutil
20 import tempfile
21
22 from mic import chroot, msger, rt_util
23 from mic.utils import misc, fs_related, errors
24 from mic.conf import configmgr
25 from mic.plugin import pluginmgr
26 from mic.imager.loop import LoopImageCreator, load_mountpoints
27
28 from mic.pluginbase import ImagerPlugin
29 class LoopPlugin(ImagerPlugin):
30     name = 'loop'
31
32     @classmethod
33     def do_create(self, args):
34         """${cmd_name}: create loop image
35
36         Usage:
37             ${name} ${cmd_name} <ksfile> [OPTS]
38
39         ${cmd_option_list}
40         """
41
42         if args is None:
43             raise errors.Usage("Invalid arguments")
44
45         creatoropts = configmgr.create
46         ksconf = args.ksfile
47
48         if creatoropts['runtime'] == "bootstrap":
49             configmgr._ksconf = ksconf
50             rt_util.bootstrap_mic()
51
52         recording_pkgs = []
53         if len(creatoropts['record_pkgs']) > 0:
54             recording_pkgs = creatoropts['record_pkgs']
55
56         if creatoropts['release'] is not None:
57             if 'name' not in recording_pkgs:
58                 recording_pkgs.append('name')
59             if 'vcs' not in recording_pkgs:
60                 recording_pkgs.append('vcs')
61
62         configmgr._ksconf = ksconf
63
64         # try to find the pkgmgr
65         pkgmgr = None
66         backends = pluginmgr.get_plugins('backend')
67         if 'auto' == creatoropts['pkgmgr']:
68             for key in configmgr.prefer_backends:
69                 if key in backends:
70                     pkgmgr = backends[key]
71                     break
72         else:
73             for key in backends.keys():
74                 if key == creatoropts['pkgmgr']:
75                     pkgmgr = backends[key]
76                     break
77
78         if not pkgmgr:
79             raise errors.CreatorError("Can't find backend: %s, "
80                                       "available choices: %s" %
81                                       (creatoropts['pkgmgr'],
82                                        ','.join(backends.keys())))
83
84         creator = LoopImageCreator(creatoropts,
85                                    pkgmgr,
86                                    args.compress_image,
87                                    args.shrink)
88
89         if len(recording_pkgs) > 0:
90             creator._recording_pkgs = recording_pkgs
91
92         image_names = [creator.name + ".img"]
93         image_names.extend(creator.get_image_names())
94         self.check_image_exists(creator.destdir,
95                                 creator.pack_to,
96                                 image_names,
97                                 creatoropts['release'])
98
99         try:
100             creator.check_depend_tools()
101             creator.mount(None, creatoropts["cachedir"])
102             creator.install()
103             creator.configure(creatoropts["repomd"])
104             creator.copy_kernel()
105             creator.unmount()
106             creator.package(creatoropts["destdir"])
107             creator.create_manifest()
108
109             if creatoropts['release'] is not None:
110                 creator.release_output(ksconf,
111                                        creatoropts['destdir'],
112                                        creatoropts['release'])
113             creator.print_outimage_info()
114
115         except errors.CreatorError:
116             raise
117         finally:
118             creator.cleanup()
119
120         msger.info("Finished.")
121         return 0
122
123     @classmethod
124     def _do_chroot_tar(cls, target, cmd=[]):
125         mountfp_xml = os.path.splitext(target)[0] + '.xml'
126         if not os.path.exists(mountfp_xml):
127             raise errors.CreatorError("No mount point file found for this tar "
128                                       "image, please check %s" % mountfp_xml)
129
130         import tarfile
131         tar = tarfile.open(target, 'r')
132         tmpdir = misc.mkdtemp()
133         tar.extractall(path=tmpdir)
134         tar.close()
135
136         mntdir = misc.mkdtemp()
137
138         loops = []
139         for (mp, label, name, size, fstype) in load_mountpoints(mountfp_xml):
140             if fstype in ("ext2", "ext3", "ext4"):
141                 myDiskMount = fs_related.ExtDiskMount
142             elif fstype == "btrfs":
143                 myDiskMount = fs_related.BtrfsDiskMount
144             elif fstype in ("vfat", "msdos"):
145                 myDiskMount = fs_related.VfatDiskMount
146             else:
147                 raise errors.CreatorError("Cannot support fstype: %s" % fstype)
148
149             name = os.path.join(tmpdir, name)
150             size = size * 1024L * 1024L
151             loop = myDiskMount(fs_related.SparseLoopbackDisk(name, size),
152                                os.path.join(mntdir, mp.lstrip('/')),
153                                fstype, size, label)
154
155             try:
156                 msger.verbose("Mount %s to %s" % (mp, mntdir + mp))
157                 fs_related.makedirs(os.path.join(mntdir, mp.lstrip('/')))
158                 loop.mount()
159
160             except:
161                 loop.cleanup()
162                 for lp in reversed(loops):
163                     chroot.cleanup_after_chroot("img", lp, None, mntdir)
164
165                 shutil.rmtree(tmpdir, ignore_errors=True)
166                 raise
167
168             loops.append(loop)
169
170         try:
171             if len(cmd) != 0:
172                 cmdline = "/usr/bin/env HOME=/root " + ' '.join(cmd)
173             else:
174                 cmdline = "/usr/bin/env HOME=/root /bin/bash"
175             chroot.chroot(mntdir, None, cmdline)
176         except:
177             raise errors.CreatorError("Failed to chroot to %s." % target)
178         finally:
179             for loop in reversed(loops):
180                 chroot.cleanup_after_chroot("img", loop, None, mntdir)
181
182             shutil.rmtree(tmpdir, ignore_errors=True)
183
184     @classmethod
185     def do_chroot(cls, target, cmd=[]):
186         if target.endswith('.tar'):
187             import tarfile
188             if tarfile.is_tarfile(target):
189                 LoopPlugin._do_chroot_tar(target, cmd)
190                 return
191             else:
192                 raise errors.CreatorError("damaged tarball for loop images")
193
194         img = target
195         imgsize = misc.get_file_size(img) * 1024L * 1024L
196         imgtype = misc.get_image_type(img)
197         if imgtype == "btrfsimg":
198             fstype = "btrfs"
199             myDiskMount = fs_related.BtrfsDiskMount
200         elif imgtype in ("ext3fsimg", "ext4fsimg"):
201             fstype = imgtype[:4]
202             myDiskMount = fs_related.ExtDiskMount
203         else:
204             raise errors.CreatorError("Unsupported filesystem type: %s" \
205                                       % imgtype)
206
207         extmnt = misc.mkdtemp()
208         extloop = myDiskMount(fs_related.SparseLoopbackDisk(img, imgsize),
209                                                          extmnt,
210                                                          fstype,
211                                                          4096,
212                                                          "%s label" % fstype)
213         try:
214             extloop.mount()
215
216         except errors.MountError:
217             extloop.cleanup()
218             shutil.rmtree(extmnt, ignore_errors=True)
219             raise
220
221         try:
222             if cmd is not None:
223                 cmdline = cmd
224             else:
225                 cmdline = "/bin/bash"
226             envcmd = fs_related.find_binary_inchroot("env", extmnt)
227             if envcmd:
228                 cmdline = "%s HOME=/root %s" % (envcmd, cmdline)
229             chroot.chroot(extmnt, None, cmdline)
230         except:
231             raise errors.CreatorError("Failed to chroot to %s." % img)
232         finally:
233             chroot.cleanup_after_chroot("img", extloop, None, extmnt)
234
235     @classmethod
236     def do_unpack(cls, srcimg):
237         image = os.path.join(tempfile.mkdtemp(dir="/var/tmp", prefix="tmp"),
238                              "target.img")
239         msger.info("Copying file system ...")
240         shutil.copyfile(srcimg, image)
241         return image