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 rpmmisc
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", "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 (n, v, r, e, a) = rpmmisc.splitFilename(pkg)
67 return (name, version)
69 class Bootstrap(object):
70 def __init__(self, homedir='/var/mic/bootstrap', **kwargs):
74 self.homedir = homedir
76 if not os.path.exists(self.homedir):
77 os.makedirs(self.homedir)
79 self.__dict__.update(**kwargs)
81 def _setRootdir(self, name):
82 self._rootdir = os.path.join(self.homedir, name)
84 def _getRootdir(self):
85 if not os.path.exists(self._rootdir):
86 raise errors.BootstrapError("Root dir: %s not exist" % self._rootdir)
89 rootdir = property(fget = lambda self: self._getRootdir(),
90 fset = lambda self, name: self._setRootdir(name),
91 doc = 'root directory')
93 def _setPkgmgr(self, name):
94 backend_plugins = pluginmgr.get_plugins('backend')
95 for (key, cls) in backend_plugins.iteritems():
99 raise errors.BootstrapError("Backend: %s can't be loaded correctly" % name)
101 pkgmgr = property(fget = lambda self: self._pkgmgr,
102 fset = lambda self, name: self._setPkgmgr(name),
103 doc = 'package manager')
106 def bootstraps(self):
108 return self._bootstraps
109 for dir in os.listdir(self.homedir):
110 metadata_fp = os.path.join(self.homedir, dir, '.metadata')
111 if os.path.exists(metadata_fp) \
112 and 0 != os.path.getsize(metadata_fp):
113 self._bootstraps.append(dir)
114 return self._bootstraps
116 def run(self, name, cmd, chdir='/', bindmounts=None):
119 os.chroot(self.rootdir)
122 if isinstance(cmd, list):
125 lvl = msger.get_loglevel()
126 msger.set_loglevel('quiet')
127 globalmounts = chroot.setup_chrootenv(self.rootdir, bindmounts)
129 proxy.set_proxy_environ()
130 subprocess.call(cmd, preexec_fn=mychroot, shell=True)
131 proxy.unset_proxy_environ()
133 raise errors.BootstrapError("Run in bootstrap fail")
135 chroot.cleanup_chrootenv(self.rootdir, bindmounts, globalmounts)
137 msger.set_loglevel(lvl)
139 def list(self, **kwargs):
141 for binst in self.bootstraps:
142 (mver, kver, rver) = self.status(binst)
143 bsinfo = {'name':binst, 'meego':mver, 'kernel':kver, 'rpm': rver}
144 bslist.append(bsinfo)
148 def status(self, name):
150 if os.path.exists(self.rootdir + '/.metadata'):
151 query_package = query_package_metadat
153 query_package = query_package_rpmdb
155 name, mver = query_package(self.rootdir, 'name', 'meego-release')
156 msger.debug("MeeGo Release: %s" % mver)
158 name, kver = query_package(self.rootdir, 'name', 'kernel')
159 msger.debug("Kernel Version: %s" % kver)
161 name, rver = query_package(self.rootdir, 'name', 'rpm')
162 msger.debug("RPM Version: %s" % rver)
164 return (mver, kver, rver)
166 def create(self, name, repolist, **kwargs):
171 self.cachedir = '/var/tmp/mic/cache' # TBD from conf, do NOT hardcode
174 self.arch = kwargs['arch']
175 if 'cachedir' in kwargs:
176 self.cachedir = kwargs['cachedir']
178 if os.path.exists(self._rootdir):
179 metadata_fp = os.path.join(self._rootdir, '.metadata')
180 if os.path.exists(metadata_fp) and \
181 0 != os.path.getsize(metadata_fp):
182 msger.warning("bootstrap already exists") # TBD more details
185 shutil.rmtree(self._rootdir)
187 if not os.path.exists(self._rootdir):
188 os.makedirs(self._rootdir)
190 pkg_manager = self.pkgmgr(self.arch, self.rootdir, self.cachedir)
193 for repo in repolist:
194 if 'proxy' in repo.keys():
195 pkg_manager.addRepository(repo['name'], repo['baseurl'], proxy = repo['proxy'])
197 pkg_manager.addRepository(repo['name'], repo['baseurl'])
199 rpm.addMacro("_dbpath", "/var/lib/rpm")
200 rpm.addMacro("__file_context_path", "%{nil}")
202 for pkg in minibase_pkgs:
203 pkg_manager.selectPackage(pkg)
204 for pkg in required_pkgs:
205 pkg_manager.selectPackage(pkg)
208 pkg_manager.runInstall(512 * 1024L * 1024L)
210 raise errors.BootstrapError("Create bootstrap fail")
212 metadata = pkg_manager.getAllContent()
213 metadata_fp = os.path.join(self.rootdir, '.metadata')
214 with open(metadata_fp, 'w') as f:
215 pickle.dump(metadata, f)
218 pkg_manager.closeRpmDB()
221 # Copy bootstrap repo files
222 srcdir = "%s/etc/zypp/repos.d/" % self.cachedir
223 destdir= "%s/etc/zypp/repos.d/" % os.path.abspath(self.rootdir)
224 shutil.rmtree(destdir, ignore_errors = True)
225 shutil.copytree(srcdir, destdir)
227 msger.info("Bootstrap created.")
232 def update(self, name):
234 chrootdir = self.rootdir
239 shutil.copyfile("/etc/resolv.conf", chrootdir + "/etc/resolv.conf")
241 subprocess.call("zypper -n --no-gpg-checks update", preexec_fn=mychroot, shell=True)
243 raise errors.BootstrapError("Bootstrap: %s Update fail" % chrootdir)
245 def cleanup(self, name):
248 chroot.cleanup_mounts(self.rootdir)
249 shutil.rmtree(self.rootdir, ignore_errors=True)
251 raise errors.BootstrapError("Bootstrap: %s clean up fail " % self.rootdir)