Merge lp:~nuclearbob/utah/cobbler-desktop into lp:utah

Proposed by Max Brustkern
Status: Merged
Merged at revision: 693
Proposed branch: lp:~nuclearbob/utah/cobbler-desktop
Merge into: lp:utah
Diff against target: 245 lines (+103/-32)
2 files modified
utah/config.py (+6/-2)
utah/provisioning/baremetal/cobbler.py (+97/-30)
To merge this branch: bzr merge lp:~nuclearbob/utah/cobbler-desktop
Reviewer Review Type Date Requested Status
Joe Talbott (community) Approve
Review via email: mp+123281@code.launchpad.net

Description of the change

This branch adds support for mini and desktop images to the CobblerMachine class. Desktop images currently require nfs, and are configured via the nfs options in the updated config.py. I haven't yet incorporated a dependency or check for nfs, so feedback on the ideal way to do that would be welcome. I've tested both types in magners-orchestra. Currently, the desktop install requires this latecommand:
chroot /target apt-get update
To get python-jsonschema from the PPA correctly in magners-orchestra, but once we have a different fix in place for that, we won't need that in the preseed anymore.

To post a comment you must log in.
Revision history for this message
Joe Talbott (joetalbott) wrote :

Looks good to me.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'utah/config.py'
--- utah/config.py 2012-08-22 15:20:25 +0000
+++ utah/config.py 2012-09-07 14:03:40 +0000
@@ -42,6 +42,9 @@
42 machineid=None,42 machineid=None,
43 name=None,43 name=None,
44 new=False,44 new=False,
45 nfscommand=['sudo', os.path.join('/', 'etc', 'init.d', 'nfs-kernel-server'), 'reload'],
46 nfsconfigfile=os.path.join('/', 'etc', 'exports'),
47 nfsoptions='*(ro,async,no_root_squash,no_subtree_check)',
45 powertimeout=5,48 powertimeout=5,
46 preseed=None,49 preseed=None,
47 qemupath='qemu:///system',50 qemupath='qemu:///system',
@@ -55,6 +58,7 @@
55"""58"""
56LOCALDEFAULTS = dict(59LOCALDEFAULTS = dict(
57 bridge=getbridge(),60 bridge=getbridge(),
61 hostname=socket.gethostname(),
58 sshprivatekey=os.path.join(os.path.expanduser('~'), '.ssh', 'utah'),62 sshprivatekey=os.path.join(os.path.expanduser('~'), '.ssh', 'utah'),
59 sshpublickey=os.path.join(os.path.expanduser('~'), '.ssh', 'utah.pub'),63 sshpublickey=os.path.join(os.path.expanduser('~'), '.ssh', 'utah.pub'),
60 sshknownhosts=os.path.join(os.path.expanduser('~'), '.ssh', 'known_hosts'),64 sshknownhosts=os.path.join(os.path.expanduser('~'), '.ssh', 'known_hosts'),
@@ -66,9 +70,9 @@
66These depend on other config options, so they're added last.70These depend on other config options, so they're added last.
67"""71"""
68LOCALDEFAULTS['logfile'] = os.path.join(DEFAULTS['logpath'],72LOCALDEFAULTS['logfile'] = os.path.join(DEFAULTS['logpath'],
69 socket.gethostname() + '.log')73 LOCALDEFAULTS['hostname'] + '.log')
70LOCALDEFAULTS['debuglog'] = os.path.join(DEFAULTS['logpath'],74LOCALDEFAULTS['debuglog'] = os.path.join(DEFAULTS['logpath'],
71 socket.gethostname() + '-debug.log')75 LOCALDEFAULTS['hostname'] + '-debug.log')
7276
73DEFAULTS.update(LOCALDEFAULTS)77DEFAULTS.update(LOCALDEFAULTS)
7478
7579
=== modified file 'utah/provisioning/baremetal/cobbler.py'
--- utah/provisioning/baremetal/cobbler.py 2012-08-30 08:34:34 +0000
+++ utah/provisioning/baremetal/cobbler.py 2012-09-07 14:03:40 +0000
@@ -2,7 +2,9 @@
2Support bare metal provisioning through cobbler.2Support bare metal provisioning through cobbler.
3"""3"""
44
5import netifaces
5import os6import os
7import pipes
6import shutil8import shutil
7import tempfile9import tempfile
8import time10import time
@@ -42,17 +44,14 @@
42 'Image file required for cobbler installation')44 'Image file required for cobbler installation')
43 self._custominit(arch=self.arch, boot=boot,45 self._custominit(arch=self.arch, boot=boot,
44 installtype=self.installtype, series=self.series)46 installtype=self.installtype, series=self.series)
45 # TODO: support mini,47 # TODO: verify we have nfs support for desktop image
46 # then desktop once we can figure out how48
49 # TODO: Rework cinitrd to be less of a confusing collection of kludges
47 self.cinitrd = None50 self.cinitrd = None
48 if self.installtype in ['alternate', 'server']:51 if self.installtype in ['alternate', 'server']:
49 self.cinitrd = os.path.join('install', 'netboot',52 self.cinitrd = os.path.join('install', 'netboot',
50 'ubuntu-installer', self.arch,53 'ubuntu-installer', self.arch,
51 'initrd.gz')54 'initrd.gz')
52 else:
53 raise UTAHBMProvisioningException(
54 'Only alternate and server images currently supported '
55 'for cobbler provisioning')
56 if self.arch == 'amd64':55 if self.arch == 'amd64':
57 self.carch = 'x86_64'56 self.carch = 'x86_64'
58 else:57 else:
@@ -72,19 +71,34 @@
7271
73 # TODO: try to remove this step, mount the iso and import that72 # TODO: try to remove this step, mount the iso and import that
74 # with a specified kernel/preseed/initrd from the tmpdir73 # with a specified kernel/preseed/initrd from the tmpdir
75 self.logger.info('Extracting image to ' + self.tmpdir)74 if self.installtype in ['alternate', 'desktop', 'server']:
76 self.image.extractall()75 self.logger.info('Extracting image to ' + self.tmpdir)
76 self.image.extractall()
7777
78 self._preparekernel()78 kernel = self._preparekernel()
79 cinitrd = os.path.join(self.tmpdir, self.cinitrd)79 if self.cinitrd is None:
80 cinitrd = None
81 else:
82 cinitrd = os.path.join(self.tmpdir, self.cinitrd)
80 initrd = self._prepareinitrd(initrd=cinitrd)83 initrd = self._prepareinitrd(initrd=cinitrd)
81 self._unpackinitrd(initrd=initrd)84 self._unpackinitrd(initrd=initrd)
82 self._setuplatecommand()85 self._setuplatecommand()
86 if self.installtype == 'desktop':
87 self.logger.info('Configuring latecommand for desktop')
88 myfile = open(os.path.join(self.tmpdir, 'initrd.d',
89 'utah-latecommand'), 'a')
90 myfile.write(
91"""
92chroot /target sh -c 'sed "/eth[0-9]/d" -i /etc/network/interfaces'
93cp /etc/resolv.conf /target/etc/resolv.conf
94""")
95 myfile.close()
83 self._setuppreseed()96 self._setuppreseed()
84 initrd = self._repackinitrd()97 initrd = self._repackinitrd()
8598
86 os.chmod(cinitrd, 0755)99 if cinitrd is not None and initrd != cinitrd:
87 shutil.copyfile(initrd, cinitrd)100 os.chmod(cinitrd, 0755)
101 shutil.copyfile(initrd, cinitrd)
88102
89 self.logger.info('Setting up system with cobbler')103 self.logger.info('Setting up system with cobbler')
90 self.logger.debug('Removing old system')104 self.logger.debug('Removing old system')
@@ -93,28 +107,67 @@
93 self._cobble(['profile', 'remove', '--name=' + self.cname])107 self._cobble(['profile', 'remove', '--name=' + self.cname])
94 self.logger.info('Removing old distro')108 self.logger.info('Removing old distro')
95 self._cobble(['distro', 'remove', '--name=' + self.cname])109 self._cobble(['distro', 'remove', '--name=' + self.cname])
96 # TODO: support more image types, maybe do this without unpacking ISO110
97 self.logger.info('Importing image')111 preseed = os.path.join(self.tmpdir, 'initrd.d', 'preseed.cfg')
98 self._cobble(['import', '--name=' + self.cname,112
99 '--path=' + self.tmpdir, '--arch=' + self.carch])113 if self.installtype in ['alternate', 'server']:
100 # TODO: figure out if I need kopts in both places114 # TODO: support more image types,
115 # maybe do this without unpacking ISO
116 self.logger.info('Importing image')
117 self._cobble(['import', '--name=' + self.cname,
118 '--path=' + self.tmpdir, '--arch=' + self.carch])
119 elif self.installtype in ['mini', 'desktop']:
120 self.logger.info('Creating distro')
121 self._cobble(['distro', 'add', '--name=' + self.cname,
122 '--kernel=' + kernel, '--initrd=' + initrd])
123 self.logger.info('Creating profile')
124 self._cobble(['profile', 'add', '--name=' + self.cname,
125 '--distro=' + self.cname])
126
127 if self.installtype == 'desktop':
128 self.logger.info('Setting up NFS for desktop install')
129 self.logger.debug('Adding export to NFS config file')
130# nfsfile = open(config.nfsconfigfile, 'a')
131# nfsfile.write("\n" + self.tmpdir + ' ' + config.nfsoptions + "\n")
132# nfsfile.close()
133 pipe = pipes.Template()
134 pipe.append('sudo tee -a ' + config.nfsconfigfile + ' >/dev/null',
135 '-.')
136 pipe.open('/dev/null', 'w').write(self.tmpdir + ' ' +
137 config.nfsoptions + "\n")
138 self.logger.debug('Reloading NFS config')
139 self._runargs(config.nfscommand)
140 self.logger.debug('Adding NFS boot options')
141 try:
142 iface = config.nfsiface
143 except AttributeError:
144 iface = config.bridge
145 ip = netifaces.ifaddresses(iface)[netifaces.AF_INET][0]['addr']
146 self.cmdline += (' root=/dev/nfs netboot=nfs nfsroot=' +
147 ip + ':' + self.tmpdir)
148 self.cmdline = self.cmdline.strip()
149
101 self.logger.info('Adding kernel boot options to distro')150 self.logger.info('Adding kernel boot options to distro')
102 self._cobble(['distro', 'edit', '--name=' + self.cname,151 self._cobble(['distro', 'edit', '--name=' + self.cname,
103 '--kopts=' + self.cmdline])152 '--kopts=' + self.cmdline])
104 self.logger.info('Adding kernel boot options '153
105 'and kickstart to profile')154 self.logger.info('Adding kickstart to profile')
106 preseed = os.path.join(self.tmpdir, 'initrd.d', 'preseed.cfg')
107 self._cobble(['profile', 'edit', '--name=' + self.cname,155 self._cobble(['profile', 'edit', '--name=' + self.cname,
108 '--kickstart=' + preseed,156 '--kickstart=' + preseed])
109 '--kopts=' + self.cmdline])157
110 self.logger.info('Adding system')158 self.logger.info('Adding system')
111 self._cobble(['system', 'add', '--name=' + self.name,159 self._cobble(['system', 'add', '--name=' + self.name,
112 '--profile=' + self.cname, '--netboot-enabled=Y']160 '--profile=' + self.cname, '--netboot-enabled=Y']
113 + ['--' + arg + '=' + self.cargs[arg]161 + ['--' + arg + '=' + self.cargs[arg]
114 for arg in self.cargs])162 for arg in self.cargs])
115163
116 self.logger.info('Syncing cobbler')164 # Things seem to be working fine without this, but sometimes things still get broken
117 self._cobble(['sync'])165 #self.logger.info('Syncing cobbler')
166 #self._cobble(['sync'])
167 try:
168 self._runargs(config.cobblerfix)
169 except AttributeError:
170 pass
118 self.restart()171 self.restart()
119172
120 self.logger.info('Waiting for installation to begin')173 self.logger.info('Waiting for installation to begin')
@@ -122,11 +175,21 @@
122 self._cobble(['system', 'edit', '--name=' + self.name,175 self._cobble(['system', 'edit', '--name=' + self.name,
123 '--netboot-enabled=N'])176 '--netboot-enabled=N'])
124177
178 self.logger.info('System installing')
179 self.logger.info('Checking every ' + str(checktimeout) +
180 ' seconds until system is installed')
181 self.logger.info('Will time out after ' + str(installtimeout)
182 + ' seconds')
183 retry(self.sshcheck, checktimeout, logmethod=self.logger.info)
184
125 if self.debug:185 if self.debug:
126 self.logger.info('Leaving temp directory '186 self.logger.info('Leaving temp directory '
127 'because debug is enabled: ' + self.tmpdir)187 'because debug is enabled: ' + self.tmpdir)
128 else:188 else:
129 self.logger.info('Cleaning up temp directory')189 self.logger.info('Cleaning up temp directory')
190 if self.installtype == 'desktop':
191 self.logger.info('Removing NFS share')
192 self._removenfs()
130 # Cribbed from http://svn.python.org193 # Cribbed from http://svn.python.org
131 # /projects/python/trunk/Mac/BuildScript/build-installer.py194 # /projects/python/trunk/Mac/BuildScript/build-installer.py
132 for dirpath, dirnames, filenames in os.walk(self.tmpdir):195 for dirpath, dirnames, filenames in os.walk(self.tmpdir):
@@ -138,12 +201,6 @@
138 os.chmod(filename, 0775)201 os.chmod(filename, 0775)
139 shutil.rmtree(self.tmpdir)202 shutil.rmtree(self.tmpdir)
140203
141 self.logger.info('System installing')
142 self.logger.info('Checking every ' + str(checktimeout) +
143 ' seconds until system is installed')
144 self.logger.info('Will time out after ' + str(installtimeout)
145 + ' seconds')
146 retry(self.sshcheck, checktimeout, logmethod=self.logger.info)
147 self.provisioned = True204 self.provisioned = True
148 self.active = True205 self.active = True
149 uuid_check_command = ('[ "{uuid}" == "$(cat /etc/utah/uuid)" ]'206 uuid_check_command = ('[ "{uuid}" == "$(cat /etc/utah/uuid)" ]'
@@ -204,10 +261,20 @@
204 """261 """
205 If the machine has an inventory, tell the inventory to release the262 If the machine has an inventory, tell the inventory to release the
206 machine when the object is deleted.263 machine when the object is deleted.
264 If we exported a directory over NFS, remove it.
207 """265 """
266 if self.installtype == 'desktop':
267 self._removenfs()
208 if self.inventory is not None:268 if self.inventory is not None:
209 self.inventory.release(machine=self)269 self.inventory.release(machine=self)
210270
271 def _removenfs(self):
272 self.logger.info('Removing NFS share')
273 self._runargs(['sudo', 'sed', '/' + self.tmpdir.replace('/', '\/') +
274 '/d', '-i', config.nfsconfigfile])
275 self.logger.debug('Reloading NFS config')
276 self._runargs(config.nfscommand)
277
211 def activecheck(self):278 def activecheck(self):
212 """279 """
213 Start the machine if needed, and check for SSH login.280 Start the machine if needed, and check for SSH login.

Subscribers

People subscribed via source and target branches