3 # Copyright (c) 2009, 2010, 2011 Intel, Inc.
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
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
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.
18 from __future__ import with_statement
26 from mic import chroot
27 from mic.plugin import pluginmgr
28 from mic.utils import proxy
29 from mic.utils import misc
30 from mic.utils import errors
32 minibase_pkgs = [ "kernel", "rpm", "setup", "filesystem", "basesystem",
33 "tzdata", "libgcc", "ncurses-base", "ncurses", "glibc",
34 "glibc-common", "ncurses-libs", "nss-softokn-freebl",
35 "bash", "zlib", "info", "cpio", "coreutils", "zypper" ]
37 required_pkgs = [ "pam", "passwd", "meego-release", "nss", "genisoimage",
38 "bzip2", "gzip", "perl", "make", "file", "psmisc", "wget",
39 "syslinux-extlinux", "btrfs-progs", "satsolver-tools",
40 "isomd5sum", "mtd-utils", "mtd-utils-ubi", "libzypp",
41 "python-zypp", "grep", "sed", "qemu-arm-static", "mic" ]
44 def query_package_rpmdb(root='/', tag='name', pattern=None):
47 ts = rpm.TransactionSet(root)
48 mi = ts.dbMatch(tag, pattern)
50 version = hdr['version']
51 return (name, version)
53 def query_package_metadat(root='/', tag='name', pattern=None):
57 with open(root + '/.metadata', 'r') as f:
58 metadata = pickle.load(f)
61 raise errors.BootstrapError("Load %s/.metadata error" % root)
63 for pkg in metadata.keys():
64 m = misc.RPM_RE.match(pkg)
66 (n, a, v, r) = m.groups()
68 raise errors.BootstrapError("Wrong Format .metadata in %s"
72 return (name, version)
74 class Bootstrap(object):
75 def __init__(self, homedir='/var/mic/bootstrap', **kwargs):
79 self.homedir = homedir
81 if not os.path.exists(self.homedir):
82 os.makedirs(self.homedir)
84 self.__dict__.update(**kwargs)
86 def _setRootdir(self, name):
87 self._rootdir = os.path.join(self.homedir, name)
89 def _getRootdir(self):
90 if not os.path.exists(self._rootdir):
91 raise errors.BootstrapError("Root dir: %s not exist" % self._rootdir)
94 rootdir = property(fget = lambda self: self._getRootdir(),
95 fset = lambda self, name: self._setRootdir(name),
96 doc = 'root directory')
98 def _setPkgmgr(self, name):
99 backend_plugins = pluginmgr.get_plugins('backend')
100 for (key, cls) in backend_plugins.iteritems():
104 raise errors.BootstrapError("Backend: %s can't be loaded correctly" % name)
106 pkgmgr = property(fget = lambda self: self._pkgmgr,
107 fset = lambda self, name: self._setPkgmgr(name),
108 doc = 'package manager')
111 def bootstraps(self):
113 return self._bootstraps
114 for dir in os.listdir(self.homedir):
115 metadata_fp = os.path.join(self.homedir, dir, '.metadata')
116 if os.path.exists(metadata_fp) \
117 and 0 != os.path.getsize(metadata_fp):
118 self._bootstraps.append(dir)
119 return self._bootstraps
121 def run(self, name, cmd, chdir='/', bindmounts=None):
124 os.chroot(self.rootdir)
127 if isinstance(cmd, list):
130 lvl = msger.get_loglevel()
131 msger.set_loglevel('quiet')
132 globalmounts = chroot.setup_chrootenv(self.rootdir, bindmounts)
134 proxy.set_proxy_environ()
135 subprocess.call(cmd, preexec_fn=mychroot, shell=True)
136 proxy.unset_proxy_environ()
138 raise errors.BootstrapError("Run in bootstrap fail")
140 chroot.cleanup_chrootenv(self.rootdir, bindmounts, globalmounts)
142 msger.set_loglevel(lvl)
144 def list(self, **kwargs):
146 for binst in self.bootstraps:
147 (mver, kver, rver) = self.status(binst)
148 bsinfo = {'name':binst, 'meego':mver, 'kernel':kver, 'rpm': rver}
149 bslist.append(bsinfo)
153 def status(self, name):
155 if os.path.exists(self.rootdir + '/.metadata'):
156 query_package = query_package_metadat
158 query_package = query_package_rpmdb
160 name, mver = query_package(self.rootdir, 'name', 'meego-release')
161 msger.debug("MeeGo Release: %s" % mver)
163 name, kver = query_package(self.rootdir, 'name', 'kernel')
164 msger.debug("Kernel Version: %s" % kver)
166 name, rver = query_package(self.rootdir, 'name', 'rpm')
167 msger.debug("RPM Version: %s" % rver)
169 return (mver, kver, rver)
171 def create(self, name, repolist, **kwargs):
176 self.cachedir = '/var/tmp/mic/cache' # TBD from conf, do NOT hardcode
179 self.arch = kwargs['arch']
180 if 'cachedir' in kwargs:
181 self.cachedir = kwargs['cachedir']
183 if os.path.exists(self._rootdir):
184 metadata_fp = os.path.join(self._rootdir, '.metadata')
185 if os.path.exists(metadata_fp) and \
186 0 != os.path.getsize(metadata_fp):
187 msger.warning("bootstrap already exists") # TBD more details
190 shutil.rmtree(self._rootdir)
192 if not os.path.exists(self._rootdir):
193 os.makedirs(self._rootdir)
195 pkg_manager = self.pkgmgr(self.arch, self.rootdir, self.cachedir)
198 for repo in repolist:
199 if 'proxy' in repo.keys():
200 pkg_manager.addRepository(repo['name'], repo['baseurl'], proxy = repo['proxy'])
202 pkg_manager.addRepository(repo['name'], repo['baseurl'])
204 rpm.addMacro("_dbpath", "/var/lib/rpm")
205 rpm.addMacro("__file_context_path", "%{nil}")
207 for pkg in minibase_pkgs:
208 pkg_manager.selectPackage(pkg)
209 for pkg in required_pkgs:
210 pkg_manager.selectPackage(pkg)
213 pkg_manager.runInstall(512 * 1024L * 1024L)
215 raise errors.BootstrapError("Create bootstrap fail")
217 metadata = pkg_manager.getAllContent()
218 metadata_fp = os.path.join(self.rootdir, '.metadata')
219 with open(metadata_fp, 'w') as f:
220 pickle.dump(metadata, f)
223 pkg_manager.closeRpmDB()
226 # Copy bootstrap repo files
227 srcdir = "%s/etc/zypp/repos.d/" % self.cachedir
228 destdir= "%s/etc/zypp/repos.d/" % os.path.abspath(self.rootdir)
229 shutil.rmtree(destdir, ignore_errors = True)
230 shutil.copytree(srcdir, destdir)
232 msger.info("Bootstrap created.")
237 def update(self, name):
239 chrootdir = self.rootdir
244 shutil.copyfile("/etc/resolv.conf", chrootdir + "/etc/resolv.conf")
246 subprocess.call("zypper -n --no-gpg-checks update", preexec_fn=mychroot, shell=True)
248 raise errors.BootstrapError("Bootstrap: %s Update fail" % chrootdir)
250 def cleanup(self, name):
253 chroot.cleanup_mounts(self.rootdir)
254 shutil.rmtree(self.rootdir, ignore_errors=True)
256 raise errors.BootstrapError("Bootstrap: %s clean up fail " % self.rootdir)