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 sync_mic(rootdir, plugin=cropts['plugin_dir'])
109 #FIXME: sync the ks file to bootstrap
110 if "/" == os.path.dirname(os.path.abspath(configmgr._ksconf)):
111 safecopy(configmgr._ksconf, rootdir)
113 msger.info("Start mic in bootstrap: %s\n" % rootdir)
114 bsarch = ELF_arch(rootdir)
115 if bsarch in personality_defs:
116 condPersonality(bsarch)
117 bindmounts = get_bindmounts(cropts)
118 ret = bsenv.run(argv, cwd, rootdir, bindmounts)
120 except errors.BootstrapError, err:
121 raise errors.CreatorError("Failed to download/install bootstrap package " \
122 "or the package is in bad format: %s" % err)
123 except RuntimeError, err:
124 #change exception type but keep the trace back
125 value, tb = sys.exc_info()[1:]
126 raise errors.CreatorError, value, tb
132 def get_bindmounts(cropts):
138 cropts['local_pkgs_path'],
145 for lrepo in cropts['localrepos']:
146 binddirs.append(lrepo)
147 for ltpkrepo in cropts['localtpkrepos']:
148 binddirs.append(ltpkrepo)
150 bindlist = map(expath, filter(None, binddirs))
151 bindlist += map(os.path.dirname, map(expath, filter(None, bindfiles)))
152 bindlist = sorted(set(bindlist))
153 bindmounts = ';'.join(bindlist)
157 def get_mic_binpath():
160 import pkg_resources # depends on 'setuptools'
161 dist = pkg_resources.get_distribution('mic')
162 # the real script is under EGG_INFO/scripts
163 if dist.has_metadata('scripts/mic'):
164 fp = os.path.join(dist.egg_info, "scripts/mic")
167 except pkg_resources.DistributionNotFound:
174 # not found script if 'flat' egg installed
176 return find_binary_path('mic')
177 except errors.CreatorError:
178 raise errors.BootstrapError("Can't find mic binary in host OS")
181 def get_mic_modpath():
185 raise errors.BootstrapError("Can't find mic module in host OS")
186 path = os.path.abspath(mic.__file__)
187 return os.path.dirname(path)
189 def get_mic_libpath():
190 return os.getenv("MIC_LIBRARY_PATH", "/usr/lib/mic")
192 # the hard code path is prepared for bootstrap
193 def sync_mic(bootstrap, binpth = '/usr/bin/mic',
195 plugin='/usr/lib/mic/plugins',
196 pylib = '/usr/lib/python2.7/site-packages',
197 conf = '/etc/mic/mic.conf'):
198 _path = lambda p: os.path.join(bootstrap, p.lstrip('/'))
201 'binpth': get_mic_binpath(),
202 'libpth': get_mic_libpath(),
204 'pylib': get_mic_modpath(),
205 'conf': '/etc/mic/mic.conf',
208 if not os.path.exists(_path(pylib)):
209 pyptn = '/usr/lib/python?.?/site-packages'
210 pylibs = glob.glob(_path(pyptn))
212 pylib = pylibs[0].replace(bootstrap, '')
214 raise errors.BootstrapError("Can't find python site dir in: %s" %
217 for key, value in micpaths.items():
219 safecopy(value, _path(eval(key)), False, ["*.pyc", "*.pyo"])
220 except (OSError, IOError), err:
221 raise errors.BootstrapError(err)
223 # auto select backend
224 conf_str = file(_path(conf)).read()
225 conf_str = re.sub("pkgmgr\s*=\s*.*", "pkgmgr=auto", conf_str)
226 with open(_path(conf), 'w') as wf:
229 # chmod +x /usr/bin/mic
230 os.chmod(_path(binpth), 0777)
232 # correct python interpreter
233 mic_cont = file(_path(binpth)).read()
234 mic_cont = "#!/usr/bin/python\n" + mic_cont
235 with open(_path(binpth), 'w') as wf:
239 def safecopy(src, dst, symlinks=False, ignore_ptns=()):
240 if os.path.isdir(src):
241 if os.path.isdir(dst):
242 dst = os.path.join(dst, os.path.basename(src))
243 if os.path.exists(dst):
244 shutil.rmtree(dst, ignore_errors=True)
246 src = src.rstrip('/')
247 # check common prefix to ignore copying itself
248 if dst.startswith(src + '/'):
249 ignore_ptns = list(ignore_ptns) + [ os.path.basename(src) ]
251 ignores = shutil.ignore_patterns(*ignore_ptns)
253 shutil.copytree(src, dst, symlinks, ignores)
254 except (OSError, IOError):
255 shutil.rmtree(dst, ignore_errors=True)
258 if not os.path.isdir(dst):
259 makedirs(os.path.dirname(dst))
261 shutil.copy2(src, dst)