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
27 from mic import bootstrap, msger
28 from mic.conf import configmgr
29 from mic.utils import errors, proxy
30 from mic.utils.fs_related import find_binary_path, makedirs
31 from mic.chroot import setup_chrootenv, cleanup_chrootenv, ELF_arch
33 _libc = ctypes.cdll.LoadLibrary(None)
34 _errno = ctypes.c_int.in_dll(_libc, "errno")
35 _libc.personality.argtypes = [ctypes.c_ulong]
36 _libc.personality.restype = ctypes.c_int
37 _libc.unshare.argtypes = [ctypes.c_int,]
38 _libc.unshare.restype = ctypes.c_int
40 expath = lambda p: os.path.abspath(os.path.expanduser(p))
45 'x86_64': PER_LINUX, 'ppc64': PER_LINUX, 'sparc64': PER_LINUX,
46 'i386': PER_LINUX32, 'i586': PER_LINUX32, 'i686': PER_LINUX32,
47 'ppc': PER_LINUX32, 'sparc': PER_LINUX32, 'sparcv9': PER_LINUX32,
48 'ia64' : PER_LINUX, 'alpha' : PER_LINUX,
49 's390' : PER_LINUX32, 's390x' : PER_LINUX,
52 def condPersonality(per=None):
53 if per is None or per in ('noarch',):
55 if personality_defs.get(per, None) is None:
57 res = _libc.personality(personality_defs[per])
59 raise OSError(_errno.value, os.strerror(_errno.value))
62 if os.path.exists(os.path.join("/", ".chroot.lock")):
64 return (os.stat("/").st_ino != 2)
66 def bootstrap_mic(argv=None):
73 # by default, sys.argv is used to run mic in bootstrap
76 if argv[0] not in ('/usr/bin/mic', 'mic'):
77 argv[0] = '/usr/bin/mic'
79 cropts = configmgr.create
80 bsopts = configmgr.bootstrap
81 distro = bsopts['distro_name'].lower()
83 rootdir = bsopts['rootdir']
84 pkglist = bsopts['packages']
87 # create bootstrap and run mic in bootstrap
88 bsenv = bootstrap.Bootstrap(rootdir, distro, cropts['arch'])
89 bsenv.logfile = cropts['logfile']
90 # rootdir is regenerated as a temp dir
91 rootdir = bsenv.rootdir
93 if 'optional' in bsopts:
94 optlist = bsopts['optional']
99 msger.info("Creating %s bootstrap ..." % distro)
100 bsenv.create(cropts['repomd'], pkglist, optlist)
102 # bootstrap is relocated under "bootstrap"
103 if os.path.exists(os.path.join(rootdir, "bootstrap")):
104 rootdir = os.path.join(rootdir, "bootstrap")
106 bsenv.dirsetup(rootdir)
107 if cropts['use_mic_in_bootstrap']:
108 msger.info("No copy host mic")
110 msger.info("Copy host mic to bootstrap")
111 sync_mic(rootdir, plugin=cropts['plugin_dir'])
113 #FIXME: sync the ks file to bootstrap
114 if "/" == os.path.dirname(os.path.abspath(configmgr._ksconf)):
115 safecopy(configmgr._ksconf, rootdir)
117 msger.info("Start mic in bootstrap: %s\n" % rootdir)
118 bsarch = ELF_arch(rootdir)
119 if bsarch in personality_defs:
120 condPersonality(bsarch)
121 bindmounts = get_bindmounts(cropts)
122 ret = bsenv.run(argv, cwd, rootdir, bindmounts)
124 except errors.BootstrapError, err:
125 raise errors.CreatorError("Failed to download/install bootstrap package " \
126 "or the package is in bad format: %s" % err)
127 except RuntimeError, err:
128 #change exception type but keep the trace back
129 value, tb = sys.exc_info()[1:]
130 raise errors.CreatorError, value, tb
136 def get_bindmounts(cropts):
142 cropts['local_pkgs_path'],
149 for lrepo in cropts['localrepos']:
150 binddirs.append(lrepo)
151 for ltpkrepo in cropts['localtpkrepos']:
152 binddirs.append(ltpkrepo)
154 bindlist = map(expath, filter(None, binddirs))
155 bindlist += map(os.path.dirname, map(expath, filter(None, bindfiles)))
156 bindlist = sorted(set(bindlist))
157 bindmounts = ';'.join(bindlist)
161 def get_mic_binpath():
164 import pkg_resources # depends on 'setuptools'
165 dist = pkg_resources.get_distribution('mic')
166 # the real script is under EGG_INFO/scripts
167 if dist.has_metadata('scripts/mic'):
168 fp = os.path.join(dist.egg_info, "scripts/mic")
171 except pkg_resources.DistributionNotFound:
178 # not found script if 'flat' egg installed
180 return find_binary_path('mic')
181 except errors.CreatorError:
182 raise errors.BootstrapError("Can't find mic binary in host OS")
185 def get_mic_modpath():
189 raise errors.BootstrapError("Can't find mic module in host OS")
190 path = os.path.abspath(mic.__file__)
191 return os.path.dirname(path)
193 def get_mic_libpath():
194 return os.getenv("MIC_LIBRARY_PATH", "/usr/lib/mic")
196 # the hard code path is prepared for bootstrap
197 def sync_mic(bootstrap, binpth = '/usr/bin/mic',
199 plugin='/usr/lib/mic/plugins',
200 pylib = '/usr/lib/python2.7/site-packages',
201 conf = '/etc/mic/mic.conf'):
202 _path = lambda p: os.path.join(bootstrap, p.lstrip('/'))
205 'binpth': get_mic_binpath(),
206 'libpth': get_mic_libpath(),
208 'pylib': get_mic_modpath(),
209 'conf': '/etc/mic/mic.conf',
212 if not os.path.exists(_path(pylib)):
213 pyptn = '/usr/lib/python?.?/site-packages'
214 pylibs = glob.glob(_path(pyptn))
216 pylib = pylibs[0].replace(bootstrap, '')
218 raise errors.BootstrapError("Can't find python site dir in: %s" %
221 for key, value in micpaths.items():
223 safecopy(value, _path(eval(key)), False, ["*.pyc", "*.pyo"])
224 except (OSError, IOError), err:
225 raise errors.BootstrapError(err)
227 # auto select backend
228 conf_str = file(_path(conf)).read()
229 conf_str = re.sub("pkgmgr\s*=\s*.*", "pkgmgr=auto", conf_str)
230 with open(_path(conf), 'w') as wf:
233 # chmod +x /usr/bin/mic
234 os.chmod(_path(binpth), 0777)
236 # correct python interpreter
237 mic_cont = file(_path(binpth)).read()
238 mic_cont = "#!/usr/bin/python\n" + mic_cont
239 with open(_path(binpth), 'w') as wf:
243 def safecopy(src, dst, symlinks=False, ignore_ptns=()):
244 if os.path.isdir(src):
245 if os.path.isdir(dst):
246 dst = os.path.join(dst, os.path.basename(src))
247 if os.path.exists(dst):
248 shutil.rmtree(dst, ignore_errors=True)
250 src = src.rstrip('/')
251 # check common prefix to ignore copying itself
252 if dst.startswith(src + '/'):
253 ignore_ptns = list(ignore_ptns) + [ os.path.basename(src) ]
255 ignores = shutil.ignore_patterns(*ignore_ptns)
257 shutil.copytree(src, dst, symlinks, ignores)
258 except (OSError, IOError):
259 shutil.rmtree(dst, ignore_errors=True)
262 if not os.path.isdir(dst):
263 makedirs(os.path.dirname(dst))
265 shutil.copy2(src, dst)