Advertisement
Guest User

Untitled

a guest
Feb 14th, 2017
117
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 24.09 KB | None | 0 0
  1. #!/usr/bin/python
  2.  
  3. # lxc_bootstrap
  4. # Copyright (C) 2017 Thomas Ward <teward@ubuntu.com>
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU Affero General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU Affero General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU Affero General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18.  
  19. # LXC Bootstrapper, around the lxc-create 'Download' template for userspace
  20. # containers; creates then modifies the container based on specifications.
  21. #
  22. # Designed for Ubuntu / Debian systems.
  23.  
  24. # import os
  25. import sys
  26. import argparse
  27. import crypt
  28. import subprocess as sp
  29. import random
  30. import platform
  31. from string import ascii_letters, digits
  32.  
  33. SHADOW_SALT_CHARSET = ascii_letters + digits
  34.  
  35. ARCHITECTURE_MAP = {
  36. 'amd64': 'amd64', # Explicit definition
  37. 'i386': 'i386', # Explicit definition
  38. 'armhf': 'armhf', # Explicit definition
  39. 'arm64': 'arm64', # Explicit definition
  40. 'x86_64': 'amd64',
  41. 'x86': 'i386',
  42. 'armv7l': 'armhf',
  43. 'armv8l': 'arm64'
  44. }
  45.  
  46.  
  47. # noinspection PyClassHasNoInit
  48. class Bootstrap:
  49. # noinspection PyClassHasNoInit
  50. class Container:
  51. bootstrap_existing = False
  52. name = None
  53. architecture = None
  54. distribution = None
  55. release = None
  56.  
  57. # noinspection PyClassHasNoInit
  58. class Customization:
  59. # noinspection PyClassHasNoInit
  60. class Packages:
  61. to_add = ['openssh-server', 'software-properties-common', 'haveged', 'python', 'python-dev',
  62. 'python3', 'python3-dev', 'perl-modules', 'ubuntu-server', 'iptables', 'libnetfilter-conntrack3']
  63. to_remove = ['lxd', 'lxd-client', 'lxd-tools', 'lxc']
  64. autoremove_after = False
  65.  
  66. # noinspection PyClassHasNoInit
  67. class Users:
  68. userdata = [('teward', '47AlphaTango@2012', None, True)]
  69.  
  70.  
  71. def _parse_arguments():
  72. argparser = argparse.ArgumentParser(description="LXC Container Bootstrapper Assistant", add_help=True)
  73. argparser.add_argument('-e', '--existing', '--bootstrap-existing', dest="container_bootstrap_existing",
  74. default=False, required=False, action='store_true',
  75. help="Don't create a container, run bootstrapping on "
  76. "an already-existing container.")
  77. argparser.add_argument('-n', '--name', type=str, dest="container_name", required=True,
  78. help="The name to assign to the LXC container.")
  79. argparser.add_argument('-a', '--arch', type=str, dest="container_arch", default=None, required=False,
  80. help="The architecture for the container")
  81. argparser.add_argument('-d', '--dist', '--distro', type=str, dest="container_dist", default=None, required=False,
  82. help="The distribution for the container")
  83. argparser.add_argument('-r', '--release', '--codename', type=str, dest="container_release", default=None,
  84. required=False, help="The specific release of the container")
  85. argparser.add_argument('--add-packages', type=str, dest="packages_add", required=False,
  86. default='openssh-server,software-properties-common,haveged,python,python-dev,'
  87. 'python3,python3-dev,perl-modules,ubuntu-server,iptables',
  88. help="Comma-separated list of packages to add to the container.")
  89. argparser.add_argument('--exclude-packages', type=str, dest="packages_exclude", required=False,
  90. default='lxd,lxd-client,lxd-tools,lxc',
  91. help="Comma-separated list of packages to exclude from the container.")
  92. argparser.add_argument('--users', '--userdata', '--userfile', type=str, dest="user_datafile", required=False,
  93. default=None,
  94. help="Path to a file containing user data, one user per line in USERNAME:PASSWORD:SALT:ADMIN"
  95. " format, where SALT is an optional 8-character alpha numeric string, and ADMIN is "
  96. "'True' or 'False'")
  97.  
  98. return argparser.parse_args()
  99.  
  100.  
  101. # noinspection PyShadowingNames
  102. def _get_bootstrap(args):
  103. if type(args) is not argparse.Namespace:
  104. raise TypeError("Invalid arguments provided.")
  105. tmpbootstrap = Bootstrap()
  106.  
  107. tmpbootstrap.Container.name = str(args.container_name).strip(''')
  108.  
  109. tmpbootstrap.Container.bootstrap_existing = args.container_bootstrap_existing
  110.  
  111. if not tmpbootstrap.Container.bootstrap_existing:
  112. if 'Windows' in platform.platform():
  113. raise OSError("LXC doesn't work on Windows, so we can't use this script. Sorry!")
  114. elif 'Linux' not in platform.platform():
  115. raise OSError("This script only works for Linux OSes, sorry!")
  116.  
  117. if args.container_arch:
  118. tmpbootstrap.Container.architecture = args.container_arch
  119. else:
  120. tmpbootstrap.Container.architecture = ARCHITECTURE_MAP[platform.machine()]
  121.  
  122. if args.container_dist:
  123. tmpbootstrap.Container.distribution = args.container_dist
  124. else:
  125. lsb_dist = sp.Popen('/usr/bin/lsb_release -s -i'.split(), stdout=sp.PIPE, stderr=sp.PIPE).communicate()
  126. if lsb_dist[1]:
  127. raise SystemError("Error getting release distributor ID.")
  128. else:
  129. tmpbootstrap.Container.distribution = str(lsb_dist[0]).lower().strip('rn')
  130.  
  131. if args.container_release:
  132. tmpbootstrap.Container.release = args.container_release
  133. else:
  134. try:
  135. lsb_codename = sp.Popen('/usr/bin/lsb_release -s -c'.split(),
  136. stdout=sp.PIPE, stderr=sp.PIPE).communicate()
  137. if lsb_codename[1]:
  138. raise SystemError("Error getting release codename from lsb_release")
  139. tmpbootstrap.Container.release = str(lsb_codename[0]).lower().strip('rn')
  140. except Exception as e:
  141. raise e
  142.  
  143. if args.packages_add:
  144. addpackages = args.packages_add.split(',')
  145. for pkg in addpackages:
  146. if pkg.lower() not in tmpbootstrap.Customization.Packages.to_add:
  147. tmpbootstrap.Customization.Packages.to_add.append(pkg.lower())
  148.  
  149. if args.packages_exclude:
  150. delpackages = args.packages_exclude.split(',')
  151. for pkg in delpackages:
  152. if pkg.lower() in tmpbootstrap.Customization.Packages.to_add:
  153. tmpbootstrap.Customization.Packages.to_add.remove(pkg.lower())
  154. else:
  155. if pkg.lower() not in tmpbootstrap.Customization.Packages.to_remove:
  156. tmpbootstrap.Customization.Packages.to_remove.append(pkg.lower())
  157.  
  158. if args.user_datafile:
  159. datafile = open(args.user_datafile, 'r')
  160. for data in datafile:
  161. data = data.split(':')
  162. if len(data) != 4:
  163. raise IOError("Invalid data provided from datafile.")
  164. else:
  165. datatuple = (data[0], data[1], data[2], bool(data[3]))
  166. # noinspection PyTypeChecker
  167. tmpbootstrap.Customization.Users.userdata.append(datatuple)
  168.  
  169. return tmpbootstrap
  170.  
  171.  
  172. def _create_container(data):
  173. lxc_create_cmd = str("/usr/bin/lxc-create -t download -n %s -- -d %s -r %s -a %s" % (
  174. data.name, data.distribution, data.release, data.architecture)).split()
  175.  
  176. try:
  177. # noinspection PyUnusedLocal
  178. ecode = sp.check_call(lxc_create_cmd, stdout=sys.stdout, stderr=sys.stderr)
  179. except sp.CalledProcessError:
  180. print "Something went wrong when creating the container."
  181. exit()
  182.  
  183.  
  184. def _start_container(container_name):
  185. execstr = str('lxc-start -n %s' % container_name).split()
  186. try:
  187. # noinspection PyUnusedLocal
  188. ecode = sp.check_call(execstr, stdout=sys.stdout, stderr=sys.stderr)
  189. except sp.CalledProcessError:
  190. print "Could not start the container, cannot continue with bootstrap."
  191. exit()
  192.  
  193.  
  194. def _shadow_pw_str(password, salt=None):
  195. if not salt or len(salt) != 8:
  196. # Create a random salt
  197. for _ in range(8):
  198. try:
  199. salt += random.SystemRandom().choice(SHADOW_SALT_CHARSET)
  200. except (TypeError, UnboundLocalError):
  201. salt = random.SystemRandom().choice(SHADOW_SALT_CHARSET)
  202.  
  203. hashed = crypt.crypt(password, ('$6$%s$' % salt))
  204. return hashed
  205.  
  206.  
  207. # noinspection PyUnreachableCode,PyUnusedLocal
  208. def _container_bootstrap_users(container_name, data):
  209. # Default comes with 'ubuntu' user and group; let's nuke them
  210. del_default_usr = "/usr/bin/lxc-attach -n %s -- deluser --remove-all-files ubuntu" % container_name
  211. del_default_grp = "/usr/bin/lxc-attach -n %s -- delgroup --only-if-empty ubuntu" % container_name
  212.  
  213. try:
  214. deldefusr = sp.check_call(del_default_usr.split(), stdout=sys.stdout, stderr=sys.stderr)
  215. except sp.CalledProcessError:
  216. print "Could not delete default user and/or group, please refer to error logs."
  217.  
  218. try:
  219. deldefgrp = sp.check_call(del_default_grp.split(), stdout=sys.stdout, stderr=sys.stderr)
  220. except sp.CalledProcessError as e:
  221. if e.returncode == 5:
  222. print "Could not delete default group, it's not empty!"
  223. elif e.returncode == 3:
  224. pass # return code of 3 means that the group doesn't exist, so we can move on.
  225.  
  226. # Since we just nuked the '1000' group and user (default Ubuntu), let's start there now.
  227. uid = 1000
  228. gid = 1000
  229.  
  230. for (username, password, salt, admin) in data.userdata:
  231. hashpw = _shadow_pw_str(password, salt)
  232.  
  233. groupcreatecmd = "lxc-attach -n %s -- groupadd -g %s %s" % (container_name, gid, username)
  234.  
  235. usrcreatecmd = ("lxc-attach -n %s -- useradd --create-home -u %s -g %s -p '%s' --shell=/bin/bash %s"
  236. % (container_name, uid, gid, hashpw, username))
  237.  
  238. try:
  239. groupcmd = sp.check_call(groupcreatecmd.split(), stdout=sys.stdout, stderr=sys.stderr)
  240. usercmd = sp.check_call(usrcreatecmd.split(), stdout=sys.stdout, stderr=sys.stderr)
  241. if admin:
  242. usermodcmd = "lxc-attach -n %s -- usermod -a -G sudo %s" % (container_name, username)
  243. usermod = sp.check_call(usermodcmd.split(), stdout=sys.stdout, stderr=sys.stderr)
  244.  
  245. except sp.CalledProcessError:
  246. print "Something went wrong when bootstrapping user '%s'..." % username
  247.  
  248. uid += 1
  249. gid += 1
  250.  
  251.  
  252. # noinspection PyUnusedLocal
  253. def _container_bootstrap_packages(container_name, data, autoremove=False):
  254. # Construct string
  255. basecommand = '/usr/bin/lxc-attach -n %s -- apt-get ' % container_name
  256. installstr = basecommand + "install -y %s" % " ".join(data.to_add)
  257. removestr = basecommand + "remove -y --purge %s" % " ".join(data.to_remove)
  258. autoremove = basecommand + "autoremove -y --purge"
  259.  
  260. try:
  261. ecode = sp.call(installstr.split(), stdout=sys.stdout, stderr=sys.stderr)
  262. except sp.CalledProcessError:
  263. print "Something went wrong installing additional packages."
  264. exit()
  265.  
  266. try:
  267. ecode = sp.call(removestr.split(), stdout=sys.stdout, stderr=sys.stderr)
  268. except sp.CalledProcessError:
  269. print "Something went wrong removing specified packages."
  270. exit()
  271.  
  272. if autoremove:
  273. try:
  274. ecode = sp.call(autoremove.split(), stdout=sys.stdout, stderr=sys.stderr)
  275. except sp.CalledProcessError:
  276. print "Something went wrong cleaning up after removal with 'autoremove'."
  277.  
  278.  
  279. def run():
  280. # Get args first, we'll pass this to the Bootstrapper.
  281. # noinspection PyUnreachableCode
  282. args = _parse_arguments()
  283.  
  284. # Take the arguments, throw it into _get_bootstrap, and get a Bootstrap object.
  285. bootstrap = _get_bootstrap(args)
  286.  
  287. if not bootstrap.Container.bootstrap_existing:
  288. # Create the container
  289. _create_container(bootstrap.Container)
  290. else:
  291. # Do nothing, continue on with bootstrap process.
  292. pass
  293.  
  294. _start_container(bootstrap.Container.name)
  295.  
  296. _container_bootstrap_packages(bootstrap.Container.name, bootstrap.Customization.Packages)
  297.  
  298. _container_bootstrap_users(bootstrap.Container.name, bootstrap.Customization.Users)
  299.  
  300.  
  301. if __name__ == "__main__":
  302. run()
  303.  
  304. #!/usr/bin/python
  305.  
  306. # lxc_bootstrap
  307. # Copyright (C) 2017 Thomas Ward <teward@ubuntu.com>
  308. #
  309. # This program is free software: you can redistribute it and/or modify
  310. # it under the terms of the GNU Affero General Public License as published by
  311. # the Free Software Foundation, either version 3 of the License, or
  312. # (at your option) any later version.
  313. #
  314. # This program is distributed in the hope that it will be useful,
  315. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  316. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  317. # GNU Affero General Public License for more details.
  318. #
  319. # You should have received a copy of the GNU Affero General Public License
  320. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  321.  
  322. # LXC Bootstrapper, around the lxc-create 'Download' template for userspace
  323. # containers; creates then modifies the container based on specifications.
  324. #
  325. # Designed for Ubuntu / Debian systems.
  326.  
  327. # import os
  328. import sys
  329. import argparse
  330. import crypt
  331. import subprocess as sp
  332. import random
  333. import platform
  334. from string import ascii_letters, digits
  335.  
  336. SHADOW_SALT_CHARSET = ascii_letters + digits
  337.  
  338.  
  339. class TransparentDict(dict):
  340.  
  341. def __missing__(self, key):
  342. return key
  343.  
  344.  
  345. ARCHITECTURE_MAP = TransparentDict({
  346. 'x86_64': 'amd64',
  347. 'x86': 'i386',
  348. 'armv7l': 'armhf',
  349. 'armv8l': 'arm64'
  350. })
  351.  
  352.  
  353. class User:
  354.  
  355. def __init__(self, name, password, salt, admin):
  356. self.name = name
  357. self.passord = password
  358. self.salt = salt
  359. self.admin = admin
  360.  
  361. @property
  362. def shadow_password(self):
  363. if not self.salt or len(self.salt) != 8:
  364. # Create a random salt
  365. for _ in range(8):
  366. try:
  367. self.salt += random.SystemRandom().choice(SHADOW_SALT_CHARSET)
  368. except (TypeError, UnboundLocalError):
  369. self.salt = random.SystemRandom().choice(SHADOW_SALT_CHARSET)
  370.  
  371. return crypt.crypt(self.password, ('$6${}$'.format(self.salt)))
  372.  
  373.  
  374. class Container:
  375. create_cmd = "/usr/bin/lxc-create -t download -n {0.name} -- -d {0.distribution} -r {0.release} -a {0.architecture}"
  376. start_cmd = 'lxc-start -n {0.name}'
  377. attach_cmd = "/usr/bin/lxc-attach -n {0.name} -- "
  378. del_user_cmd = attach_cmd + "deluser --remove-all-files ubuntu"
  379. del_group_cmd = attach_cmd + "delgroup --only-if-empty ubuntu"
  380. create_group_cmd = attach_cmd + "groupadd -g {gid} {user.name}"
  381. create_user_cmd = attach_cmd +
  382. "useradd --create-home -u {uid} -g {gid} -p {user.shadow_password} --shell=/bin/bash {user.name}"
  383. mod_user_cmd = attach_cmd + "usermod -a -G sudo {user.name}"
  384. apt_get_install_cmd = attach_cmd + "apt-get install -y {}"
  385. apt_get_remove_cmd = attach_cmd + "apt-get remove -y --purge {}"
  386. apt_get_autoremove_cmd = attach_cmd + "apt-get autoremove -y --purge"
  387.  
  388. def __init__(self,
  389. name=None,
  390. architecture=None,
  391. distribution=None,
  392. release=None):
  393. self.name = name
  394. self.architecture = architecture
  395. self.distribution = distribution
  396. self.release = release
  397.  
  398. def create(self):
  399. cmd = self.create_cmd.format(self).split()
  400. try:
  401. sp.check_call(cmd, stdout=sys.stdout, stderr=sys.stderr)
  402. except sp.CalledProcessError as e:
  403. print "Something went wrong when creating the container."
  404. print e
  405. exit()
  406.  
  407. def start(self):
  408. cmd = self.start_cmd.format(self).split()
  409. try:
  410. sp.check_call(cmd, stdout=sys.stdout, stderr=sys.stderr)
  411. except sp.CalledProcessError as e:
  412. print "Could not start the container, cannot continue with bootstrap."
  413. print e
  414. exit()
  415.  
  416. def bootstrap_users(self, users):
  417. # Default comes with 'ubuntu' user and group; let's nuke them
  418. try:
  419. sp.check_call(self.del_user_cmd.format(self).split(),
  420. stdout=sys.stdout, stderr=sys.stderr)
  421. except sp.CalledProcessError:
  422. print "Could not delete default user and/or group, please refer to error logs."
  423.  
  424. try:
  425. sp.check_call(self.del_group.format(self).split(),
  426. stdout=sys.stdout, stderr=sys.stderr)
  427. except sp.CalledProcessError as e:
  428. if e.returncode == 5:
  429. print "Could not delete default group, it's not empty!"
  430. elif e.returncode == 3:
  431. # return code of 3 means that the group doesn't exist, so we can
  432. # move on.
  433. pass
  434.  
  435. # Since we just nuked the '1000' group and user (default Ubuntu), let's
  436. # start there now.
  437. uid, gid = 1000, 1000
  438.  
  439. for user in users:
  440.  
  441. groupcreatecmd = self.create_group_cmd.format(
  442. self, user=user, gid=gid, uid=uid).split()
  443.  
  444. usrcreatecmd = self.create_user_cmd.format(
  445. self, user=user, gid=gid, uid=uid).split()
  446.  
  447. try:
  448. sp.check_call(groupcreatecmd, stdout=sys.stdout,
  449. stderr=sys.stderr)
  450. sp.check_call(usrcreatecmd, stdout=sys.stdout,
  451. stderr=sys.stderr)
  452. if user.admin:
  453. sp.check_call(self.mod_user_cmd.format(self, user=user).split(),
  454. stdout=sys.stdout, stderr=sys.stderr)
  455. except sp.CalledProcessError:
  456. print "Something went wrong when bootstrapping user '{0.name}'...".format(user)
  457.  
  458. uid += 1
  459. gid += 1
  460.  
  461. def bootstrap_packages(self, packages, autoremove=False):
  462. try:
  463. sp.call(self.apt_get_install_cmd.format(self, " ".join(packages.to_add)).split(),
  464. stdout=sys.stdout, stderr=sys.stderr)
  465. except sp.CalledProcessError as e:
  466. print "Something went wrong installing additional packages."
  467. print e
  468. exit()
  469.  
  470. try:
  471. sp.call(self.apt_get_remove_cmd.format(self, " ".join(data.to_remove))
  472. .split(),
  473. stdout=sys.stdout, stderr=sys.stderr)
  474. except sp.CalledProcessError as e:
  475. print "Something went wrong removing specified packages."
  476. print e
  477. exit()
  478.  
  479. if autoremove:
  480. try:
  481. sp.call(self.apt_get_autoremove_cmd.split(),
  482. stdout=sys.stdout, stderr=sys.stderr)
  483. except sp.CalledProcessError as e:
  484. print "Something went wrong cleaning up after removal with 'autoremove'."
  485. print e
  486.  
  487.  
  488. class Packages:
  489.  
  490.  
  491. def _parse_arguments():
  492. current_platform = platform.platform()
  493. if 'Windows' in current_platform:
  494. raise OSError(
  495. "LXC doesn't work on Windows, so we can't use this script. Sorry!")
  496. elif 'Linux' not in current_platform:
  497. raise OSError("This script only works for Linux OSes, sorry!")
  498.  
  499. argparser = argparse.ArgumentParser(
  500. description="LXC Container Bootstrapper Assistant", add_help=True)
  501. argparser.add_argument('-e', '--existing', '--bootstrap-existing', dest="container_bootstrap_existing",
  502. default=False, required=False, action='store_true',
  503. help="Don't create a container, run bootstrapping on "
  504. "an already-existing container.")
  505. argparser.add_argument('-n', '--name', type=str, dest="container_name", required=True,
  506. help="The name to assign to the LXC container.")
  507. argparser.add_argument('-a', '--arch', type=str, dest="container_arch", default=None, required=False,
  508. help="The architecture for the container")
  509. argparser.add_argument('-d', '--dist', '--distro', type=str, dest="container_dist", default=None, required=False,
  510. help="The distribution for the container")
  511. argparser.add_argument('-r', '--release', '--codename', type=str, dest="container_release", default=None,
  512. required=False, help="The specific release of the container")
  513. argparser.add_argument('--add-packages', type=str, dest="packages_add", required=False,
  514. default='openssh-server,software-properties-common,haveged,python,python-dev,'
  515. 'python3,python3-dev,perl-modules,ubuntu-server,iptables',
  516. help="Comma-separated list of packages to add to the container.")
  517. argparser.add_argument('--exclude-packages', type=str, dest="packages_exclude", required=False,
  518. default='lxd,lxd-client,lxd-tools,lxc',
  519. help="Comma-separated list of packages to exclude from the container.")
  520. argparser.add_argument('--users', '--userdata', '--userfile', type=str, dest="user_datafile", required=False,
  521. default=None,
  522. help="Path to a file containing user data, one user per line in USERNAME:PASSWORD:SALT:ADMIN"
  523. " format, where SALT is an optional 8-character alpha numeric string, and ADMIN is "
  524. "'True' or 'False'")
  525.  
  526. args = argparser.parse_args()
  527. args.container_name = args.container_name.strip(''')
  528.  
  529. if not args.container_bootstrap_existing:
  530. if not args.container_arch:
  531. args.container_arch = ARCHITECTURE_MAP[
  532. platform.machine()]
  533.  
  534. if not args.container_dist:
  535. lsb_dist = sp.Popen('/usr/bin/lsb_release -s -i'.split(),
  536. stdout=sp.PIPE, stderr=sp.PIPE).communicate()
  537. if lsb_dist[1]:
  538. raise SystemError("Error getting release distributor ID.")
  539. else:
  540. args.container_dist = lsb_dist[0].lower().strip('rn')
  541.  
  542. if not args.container_release:
  543. lsb_codename = sp.Popen('/usr/bin/lsb_release -s -c'.split(),
  544. stdout=sp.PIPE, stderr=sp.PIPE).communicate()
  545. if lsb_codename[1]:
  546. raise SystemError(
  547. "Error getting release codename from lsb_release")
  548. args.container_release = lsb_codename[0].lower().strip('rn')
  549.  
  550. args.to_add = {'openssh-server', 'software-properties-common', 'haveged', 'python', 'python-dev',
  551. 'python3', 'python3-dev', 'perl-modules', 'ubuntu-server', 'iptables', 'libnetfilter-conntrack3'}
  552. args.to_remove = {'lxd', 'lxd-client', 'lxd-tools', 'lxc'}
  553. args.autoremove_after = False
  554. if args.packages_add:
  555. args.to_add |= set(map(str.lower, args.packages_add.split(',')))
  556.  
  557. if args.packages_exclude:
  558. delpackages = set(map(str.lower, args.packages_exclude.split(',')))
  559. args.to_add -= delpackages
  560. args.to_remove |= delpackages
  561. return args
  562.  
  563.  
  564. def get_users(user_datafile):
  565. users = []
  566. if user_datafile:
  567. with open(user_datafile) as datafile:
  568. for row in datafile:
  569. data = row.split(':')
  570. if len(data) != 4:
  571. raise IOError("Invalid data provided from datafile.")
  572. users.append(User(data[0], data[1], data[2], int(data[3])))
  573. return users
  574.  
  575.  
  576. def run():
  577. args = _parse_arguments()
  578. container = Container(args.container_name,
  579. args.container_arch,
  580. args.container_dist,
  581. args.container_release)
  582.  
  583. users = [User('teward', '47AlphaTango@2012', None, True)]
  584. users += get_users(args.user_datafile)
  585.  
  586. if not args.bootstrap_existing:
  587. container.create()
  588.  
  589. container.start()
  590. container.bootstrap_users(users)
  591. container.bootstrap_packages(args.to_add, args.to_exclude)
  592.  
  593.  
  594. if __name__ == "__main__":
  595. run()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement