Merge lp:~harmw/cloud-init/freebsd into lp:~cloud-init-dev/cloud-init/trunk

Proposed by Harm Weites
Status: Merged
Merged at revision: 1003
Proposed branch: lp:~harmw/cloud-init/freebsd
Merge into: lp:~cloud-init-dev/cloud-init/trunk
Diff against target: 606 lines (+345/-49) (has conflicts)
10 files modified
cloudinit/config/cc_resizefs.py (+5/-0)
cloudinit/distros/freebsd.py (+93/-13)
config/cloud.cfg-freebsd (+88/-0)
setup.py (+17/-8)
sysvinit/freebsd/cloudconfig (+7/-7)
sysvinit/freebsd/cloudfinal (+7/-7)
sysvinit/freebsd/cloudinit (+7/-7)
sysvinit/freebsd/cloudinitlocal (+7/-7)
tests/unittests/test_distros/test_netconfig.py (+57/-0)
tools/build-on-freebsd (+57/-0)
Text conflict in cloudinit/config/cc_resizefs.py
To merge this branch: bzr merge lp:~harmw/cloud-init/freebsd
Reviewer Review Type Date Requested Status
cloud-init Commiters Pending
Review via email: mp+231024@code.launchpad.net

Description of the change

Several FreeBSD fixes, a full changelog can be viewed in the commitlog.

Most notable fix is in the initscripts and configuration file, needed for it to 'just work'. The current trunk is broken.

There is one unresolved issue regarding path resolving of modules (?), which is why there is one DataSource explicitly enabled in the configuration file (and working/being used). This however shouldn't affect much people, since most cloud users just run c-i on Linux :)

Once we have these fixes in place (together with a version bump), the port can be submitted to bugs.freebsd.org/bugzilla as well.

To post a comment you must log in.
lp:~harmw/cloud-init/freebsd updated
1015. By Harm Weites

fix: Don't create a directory that will never be used anyway.

Revision history for this message
Scott Moser (smoser) wrote :

some comments:
a.) please merge/pull the changes i have in my branch at lp:~smoser/cloud-init/freebsd-cleanups
b.) test_simple_write_freebsd is failing for me on ubuntu

I think that cloud.freebsd.cfg can't be put into config/
as I think it will be copied/installed/used on linux and screw things up.

- Drop some of your debug comments 'UBUNTU FORMAT START' stuff.
- "reading" rc.conf... not the greatest, wish there was something better.
  something you can fix, though, is compiling the 're' and using that rather
  than using 're.match'. that should be faster.

I think thats it.
sorry it took me so long to look at this.

lp:~harmw/cloud-init/freebsd updated
1016. By Harm Weites

merge: Trunk.

1017. By Harm Weites

merge: Pull in the fixes from Scott.

1018. By Harm Weites

fix: Use the correct variable.

1019. By Harm Weites

fix: Syntax.

1020. By Harm Weites

change: Rename the config file to cloud.cfg-freebsd so it doesn't
get copied per default. Packaging will take care of installing this
configfile on the BSD platform.

1021. By Harm Weites

fix: Drop some overly loud debug messages.

Revision history for this message
Harm Weites (harmw) wrote :

ok, I've merged your bikeshedding work and added some minor fixes/changes on top.

I realy have no clue why that test suddenly fails, nor do have an idea how to fix it. How should I go and fix this?

About your suggestion to compile the re instead of using re.match, I'm afraid I don't know what you exactly mean here.

> some comments:
> a.) please merge/pull the changes i have in my branch at lp:~smoser/cloud-init
> /freebsd-cleanups
> b.) test_simple_write_freebsd is failing for me on ubuntu
>
> I think that cloud.freebsd.cfg can't be put into config/
> as I think it will be copied/installed/used on linux and screw things up.
>
> - Drop some of your debug comments 'UBUNTU FORMAT START' stuff.
> - "reading" rc.conf... not the greatest, wish there was something better.
> something you can fix, though, is compiling the 're' and using that rather
> than using 're.match'. that should be faster.
>
> I think thats it.
> sorry it took me so long to look at this.

Revision history for this message
Scott Moser (smoser) wrote :

The test that fails is the one you added. it fails because I'm running it on linux, where there is no /etc/rc.conf. I stuffed a 'raise Exception("FOO")' in to show the stack trace.

======================================================================
ERROR: test_simple_write_freebsd (tests.unittests.test_distros.test_netconfig.TestNetCfgDistro)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/mocker.py", line 146, in test_method_wrapper
    result = test_method()
  File "/home/smoser-public/src/cloud-init/freebsd.new/tests/unittests/test_distros/test_netconfig.py", line 200, in test_simple_write_freebsd
    fbsd_distro.apply_network(BASE_NET_CFG, False)
  File "/home/smoser-public/src/cloud-init/freebsd.new/cloudinit/distros/__init__.py", line 120, in apply_network
    dev_names = self._write_network(settings)
  File "/home/smoser-public/src/cloud-init/freebsd.new/cloudinit/distros/freebsd.py", line 261, in _write_network
    self.updatercconf('ifconfig_' + dev, ifconfig)
  File "/home/smoser-public/src/cloud-init/freebsd.new/cloudinit/distros/freebsd.py", line 52, in updatercconf
    conf = self.loadrcconf()
  File "/home/smoser-public/src/cloud-init/freebsd.new/cloudinit/distros/freebsd.py", line 72, in loadrcconf
    raise Exception("FOO")
Exception: FOO

You can use patchOS and patchUtils to provide consistent content for that file.

Regarding 're.compile', using 're.compile' basically caches the compiled regex, and then you can later re-use it more quickly. Example:
$ python -m timeit --number=100000 --setup="import re; MY_RE=re.compile(r'^\"|\"$')" 'MY_RE.sub("", "abcd")'
100000 loops, best of 3: 1.07 usec per loop
$ python -m timeit --setup="import re;" "re.sub(r'^\"|\"$', \"\", \"abcd\")"
100000 loops, best of 3: 3.14 usec per loop

The quoting is annoying because of shell getting in the way, but essentially, see that re-using the output of re.compile is 3 x faster in this case on that code.

since both of your uses of re (re.match and re.compile) are on static input, you might as well re.compile them.

Thanks, other than test case and that (which is admittedly minor), i'm good with this.

again, thanks for your patience.

lp:~harmw/cloud-init/freebsd updated
1022. By Harm Weites

change: Use a compiled regex and use the included match groups instead
of matching yet again.

1023. By Harm Weites

fix: Make sure this freebsd test succeeds on all platforms (harlowja).

1024. By Harm Weites

fix: The original regex was a little harsh, the rest of the bits
regarding keys and values from /etc/rc.conf is tweaked as well
(harlowja).

Revision history for this message
Joshua Harlow (harlowja) :
Revision history for this message
Joshua Harlow (harlowja) :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cloudinit/config/cc_resizefs.py'
2--- cloudinit/config/cc_resizefs.py 2014-08-26 19:53:41 +0000
3+++ cloudinit/config/cc_resizefs.py 2014-08-28 17:55:48 +0000
4@@ -40,8 +40,13 @@
5 return ('xfs_growfs', devpth)
6
7
8+<<<<<<< TREE
9 def _resize_ufs(mount_point, devpth):
10 return ('growfs', devpth)
11+=======
12+def _resize_ufs(mount_point, devpth): # pylint: disable=W0613
13+ return ('growfs', '-y', devpth)
14+>>>>>>> MERGE-SOURCE
15
16 # Do not use a dictionary as these commands should be able to be used
17 # for multiple filesystem types if possible, e.g. one command for
18
19=== modified file 'cloudinit/distros/freebsd.py'
20--- cloudinit/distros/freebsd.py 2014-02-28 21:40:08 +0000
21+++ cloudinit/distros/freebsd.py 2014-08-28 17:55:48 +0000
22@@ -26,6 +26,9 @@
23 from cloudinit import ssh_util
24 from cloudinit import util
25
26+from cloudinit.distros import net_util
27+from cloudinit.distros.parsers.resolv_conf import ResolvConf
28+
29 LOG = logging.getLogger(__name__)
30
31
32@@ -33,6 +36,7 @@
33 rc_conf_fn = "/etc/rc.conf"
34 login_conf_fn = '/etc/login.conf'
35 login_conf_fn_bak = '/etc/login.conf.orig'
36+ resolv_conf_fn = '/etc/resolv.conf'
37
38 def __init__(self, name, cfg, paths):
39 distros.Distro.__init__(self, name, cfg, paths)
40@@ -44,30 +48,53 @@
41
42 # Updates a key in /etc/rc.conf.
43 def updatercconf(self, key, value):
44- LOG.debug("updatercconf: %s => %s", key, value)
45+ LOG.debug("Checking %s for: %s = %s", self.rc_conf_fn, key, value)
46 conf = self.loadrcconf()
47 config_changed = False
48- for item in conf:
49- if item == key and conf[item] != value:
50- conf[item] = value
51- LOG.debug("[rc.conf]: Value %s for key %s needs to be changed",
52- value, key)
53- config_changed = True
54+ if key not in conf:
55+ LOG.debug("Adding key in %s: %s = %s", self.rc_conf_fn, key,
56+ value)
57+ conf[key] = value
58+ config_changed = True
59+ else:
60+ for item in conf.keys():
61+ if item == key and conf[item] != value:
62+ conf[item] = value
63+ LOG.debug("Changing key in %s: %s = %s", self.rc_conf_fn,
64+ key, value)
65+ config_changed = True
66
67 if config_changed:
68- LOG.debug("Writing new %s file", self.rc_conf_fn)
69+ LOG.info("Writing %s", self.rc_conf_fn)
70 buf = StringIO()
71 for keyval in conf.items():
72- buf.write("%s=%s\n" % keyval)
73+ buf.write('%s="%s"\n' % keyval)
74 util.write_file(self.rc_conf_fn, buf.getvalue())
75
76- # Load the contents of /etc/rc.conf and store all keys in a dict.
77+ # Load the contents of /etc/rc.conf and store all keys in a dict. Make sure
78+ # quotes are ignored:
79+ # hostname="bla"
80 def loadrcconf(self):
81+ RE_MATCH = re.compile(r'^(\w+)\s*=\s*(.*)\s*')
82 conf = {}
83 lines = util.load_file(self.rc_conf_fn).splitlines()
84 for line in lines:
85- tok = line.split('=')
86- conf[tok[0]] = tok[1].rstrip()
87+ m = RE_MATCH.match(line)
88+ if not m:
89+ LOG.debug("Skipping line from /etc/rc.conf: %s", line)
90+ continue
91+ key = m.group(1).rstrip()
92+ val = m.group(2).rstrip()
93+ # Kill them quotes (not completely correct, aka won't handle
94+ # quoted values, but should be ok ...)
95+ if val[0] in ('"', "'"):
96+ val = val[1:]
97+ if val[-1] in ('"', "'"):
98+ val = val[0:-1]
99+ if len(val) == 0:
100+ LOG.debug("Skipping empty value from /etc/rc.conf: %s", line)
101+ continue
102+ conf[key] = val
103 return conf
104
105 def readrcconf(self, key):
106@@ -218,7 +245,60 @@
107 ssh_util.setup_user_keys(keys, name, options=None)
108
109 def _write_network(self, settings):
110- return
111+ entries = net_util.translate_network(settings)
112+ nameservers = []
113+ searchdomains = []
114+ dev_names = entries.keys()
115+ for (dev, info) in entries.iteritems():
116+ # Skip the loopback interface.
117+ if dev.startswith('lo'):
118+ continue
119+
120+ LOG.info('Configuring interface %s', dev)
121+
122+ if info.get('bootproto') == 'static':
123+ LOG.debug('Configuring dev %s with %s / %s', dev, info.get('address'), info.get('netmask'))
124+ # Configure an ipv4 address.
125+ ifconfig = info.get('address') + ' netmask ' + info.get('netmask')
126+
127+ # Configure the gateway.
128+ self.updatercconf('defaultrouter', info.get('gateway'))
129+
130+ if 'dns-nameservers' in info:
131+ nameservers.extend(info['dns-nameservers'])
132+ if 'dns-search' in info:
133+ searchservers.extend(info['dns-search'])
134+ else:
135+ ifconfig = 'DHCP'
136+
137+ self.updatercconf('ifconfig_' + dev, ifconfig)
138+
139+ # Try to read the /etc/resolv.conf or just start from scratch if that
140+ # fails.
141+ try:
142+ resolvconf = ResolvConf(util.load_file(self.resolv_conf_fn))
143+ resolvconf.parse()
144+ except IOError:
145+ util.logexc(LOG, "Failed to parse %s, use new empty file", self.resolv_conf_fn)
146+ resolvconf = ResolvConf('')
147+ resolvconf.parse()
148+
149+ # Add some nameservers
150+ for server in nameservers:
151+ try:
152+ resolvconf.add_nameserver(server)
153+ except ValueError:
154+ util.logexc(LOG, "Failed to add nameserver %s", server)
155+
156+ # And add any searchdomains.
157+ for domain in searchdomains:
158+ try:
159+ resolvconf.add_search_domain(domain)
160+ except ValueError:
161+ util.logexc(LOG, "Failed to add search domain %s", domain)
162+ util.write_file(self.resolv_conf_fn, str(resolvconf), 0644)
163+
164+ return dev_names
165
166 def apply_locale(self, locale, out_fn=None):
167 # Adjust the locals value to the new value
168
169=== added file 'config/cloud.cfg-freebsd'
170--- config/cloud.cfg-freebsd 1970-01-01 00:00:00 +0000
171+++ config/cloud.cfg-freebsd 2014-08-28 17:55:48 +0000
172@@ -0,0 +1,88 @@
173+# The top level settings are used as module
174+# and system configuration.
175+
176+syslog_fix_perms: root:wheel
177+
178+# This should not be required, but leave it in place until the real cause of
179+# not beeing able to find -any- datasources is resolved.
180+datasource_list: ['OpenStack']
181+
182+# A set of users which may be applied and/or used by various modules
183+# when a 'default' entry is found it will reference the 'default_user'
184+# from the distro configuration specified below
185+users:
186+ - default
187+
188+# If this is set, 'root' will not be able to ssh in and they
189+# will get a message to login instead as the above $user (ubuntu)
190+disable_root: false
191+
192+# This will cause the set+update hostname module to not operate (if true)
193+preserve_hostname: false
194+
195+# Example datasource config
196+# datasource:
197+# Ec2:
198+# metadata_urls: [ 'blah.com' ]
199+# timeout: 5 # (defaults to 50 seconds)
200+# max_wait: 10 # (defaults to 120 seconds)
201+
202+# The modules that run in the 'init' stage
203+cloud_init_modules:
204+# - migrator
205+ - seed_random
206+ - bootcmd
207+# - write-files
208+ - growpart
209+ - resizefs
210+ - set_hostname
211+ - update_hostname
212+# - update_etc_hosts
213+# - ca-certs
214+# - rsyslog
215+ - users-groups
216+ - ssh
217+
218+# The modules that run in the 'config' stage
219+cloud_config_modules:
220+# - disk_setup
221+# - mounts
222+ - ssh-import-id
223+ - locale
224+# - set-passwords
225+# - package-update-upgrade-install
226+# - landscape
227+# - timezone
228+# - puppet
229+# - chef
230+# - salt-minion
231+# - mcollective
232+ - disable-ec2-metadata
233+ - runcmd
234+# - byobu
235+
236+# The modules that run in the 'final' stage
237+cloud_final_modules:
238+ - rightscale_userdata
239+ - scripts-vendor
240+ - scripts-per-once
241+ - scripts-per-boot
242+ - scripts-per-instance
243+ - scripts-user
244+ - ssh-authkey-fingerprints
245+ - keys-to-console
246+ - phone-home
247+ - final-message
248+ - power-state-change
249+
250+# System and/or distro specific settings
251+# (not accessible to handlers/transforms)
252+system_info:
253+ distro: freebsd
254+ default_user:
255+ name: beastie
256+ lock_passwd: True
257+ gecos: FreeBSD
258+ groups: [wheel]
259+ sudo: ["ALL=(ALL) NOPASSWD:ALL"]
260+ shell: /bin/sh
261
262=== modified file 'setup.py'
263--- setup.py 2014-08-26 19:53:41 +0000
264+++ setup.py 2014-08-28 17:55:48 +0000
265@@ -63,18 +63,28 @@
266
267 INITSYS_FILES = {
268 'sysvinit': [f for f in glob('sysvinit/redhat/*') if is_f(f)],
269+ 'sysvinit_freebsd': [f for f in glob('sysvinit/freebsd/*') if is_f(f)],
270 'sysvinit_deb': [f for f in glob('sysvinit/debian/*') if is_f(f)],
271 'systemd': [f for f in glob('systemd/*') if is_f(f)],
272 'upstart': [f for f in glob('upstart/*') if is_f(f)],
273 }
274 INITSYS_ROOTS = {
275 'sysvinit': '/etc/rc.d/init.d',
276+ 'sysvinit_freebsd': '/usr/local/etc/rc.d',
277 'sysvinit_deb': '/etc/init.d',
278 'systemd': systemd_unitdir(),
279 'upstart': '/etc/init/',
280 }
281 INITSYS_TYPES = sorted(list(INITSYS_ROOTS.keys()))
282
283+# Install everything in the right location and take care of Linux (default) and
284+# FreeBSD systems.
285+USR = "/usr"
286+ETC = "/etc"
287+if os.uname()[0] == 'FreeBSD':
288+ USR = "/usr/local"
289+ ETC = "/usr/local/etc"
290+
291
292 def get_version():
293 cmd = ['tools/read-version']
294@@ -136,18 +146,17 @@
295 'tools/cloud-init-per',
296 ],
297 license='GPLv3',
298- data_files=[('/etc/cloud', glob('config/*.cfg')),
299- ('/etc/cloud/cloud.cfg.d', glob('config/cloud.cfg.d/*')),
300- ('/etc/cloud/templates', glob('templates/*')),
301- ('/usr/share/cloud-init', []),
302- ('/usr/lib/cloud-init',
303+ data_files=[(ETC + '/cloud', glob('config/*.cfg')),
304+ (ETC + '/cloud/cloud.cfg.d', glob('config/cloud.cfg.d/*')),
305+ (ETC + '/cloud/templates', glob('templates/*')),
306+ (USR + '/lib/cloud-init',
307 ['tools/uncloud-init',
308 'tools/write-ssh-key-fingerprints']),
309- ('/usr/share/doc/cloud-init',
310+ (USR + '/share/doc/cloud-init',
311 [f for f in glob('doc/*') if is_f(f)]),
312- ('/usr/share/doc/cloud-init/examples',
313+ (USR + '/share/doc/cloud-init/examples',
314 [f for f in glob('doc/examples/*') if is_f(f)]),
315- ('/usr/share/doc/cloud-init/examples/seed',
316+ (USR + '/share/doc/cloud-init/examples/seed',
317 [f for f in glob('doc/examples/seed/*') if is_f(f)]),
318 ],
319 install_requires=read_requires(),
320
321=== modified file 'sysvinit/freebsd/cloudconfig'
322--- sysvinit/freebsd/cloudconfig 2014-01-18 00:45:23 +0000
323+++ sysvinit/freebsd/cloudconfig 2014-08-28 17:55:48 +0000
324@@ -6,28 +6,28 @@
325
326 . /etc/rc.subr
327
328+export CLOUD_CFG=/usr/local/etc/cloud/cloud.cfg
329+
330 name="cloudconfig"
331-command="/usr/bin/cloud-init"
332+command="/usr/local/bin/cloud-init"
333 start_cmd="cloudconfig_start"
334 stop_cmd=":"
335 rcvar="cloudinit_enable"
336 start_precmd="cloudinit_override"
337 start_cmd="cloudconfig_start"
338
339-: ${cloudinit_config:="/etc/cloud/cloud.cfg"}
340-
341 cloudinit_override()
342 {
343- # If there exist sysconfig/default variable override files use it...
344- if [ -f /etc/default/cloud-init ]; then
345- . /etc/default/cloud-init
346+ # If there exist sysconfig/defaults variable override files use it...
347+ if [ -f /etc/defaults/cloud-init ]; then
348+ . /etc/defaults/cloud-init
349 fi
350 }
351
352 cloudconfig_start()
353 {
354 echo "${command} starting"
355- ${command} ${cloudinit_config} modules --mode config
356+ ${command} modules --mode config
357 }
358
359 load_rc_config $name
360
361=== modified file 'sysvinit/freebsd/cloudfinal'
362--- sysvinit/freebsd/cloudfinal 2014-01-18 00:45:23 +0000
363+++ sysvinit/freebsd/cloudfinal 2014-08-28 17:55:48 +0000
364@@ -6,28 +6,28 @@
365
366 . /etc/rc.subr
367
368+export CLOUD_CFG=/usr/local/etc/cloud/cloud.cfg
369+
370 name="cloudfinal"
371-command="/usr/bin/cloud_init"
372+command="/usr/local/bin/cloud-init"
373 start_cmd="cloudfinal_start"
374 stop_cmd=":"
375 rcvar="cloudinit_enable"
376 start_precmd="cloudinit_override"
377 start_cmd="cloudfinal_start"
378
379-: ${cloudinit_config:="/etc/cloud/cloud.cfg"}
380-
381 cloudinit_override()
382 {
383- # If there exist sysconfig/default variable override files use it...
384- if [ -f /etc/default/cloud-init ]; then
385- . /etc/default/cloud-init
386+ # If there exist sysconfig/defaults variable override files use it...
387+ if [ -f /etc/defaults/cloud-init ]; then
388+ . /etc/defaults/cloud-init
389 fi
390 }
391
392 cloudfinal_start()
393 {
394 echo -n "${command} starting"
395- ${command} ${cloudinit_config} modules --mode final
396+ ${command} modules --mode final
397 }
398
399 load_rc_config $name
400
401=== modified file 'sysvinit/freebsd/cloudinit'
402--- sysvinit/freebsd/cloudinit 2014-01-18 00:45:23 +0000
403+++ sysvinit/freebsd/cloudinit 2014-08-28 17:55:48 +0000
404@@ -6,28 +6,28 @@
405
406 . /etc/rc.subr
407
408+export CLOUD_CFG=/usr/local/etc/cloud/cloud.cfg
409+
410 name="cloudinit"
411-command="/usr/bin/cloud_init"
412+command="/usr/local/bin/cloud-init"
413 start_cmd="cloudinit_start"
414 stop_cmd=":"
415 rcvar="cloudinit_enable"
416 start_precmd="cloudinit_override"
417 start_cmd="cloudinit_start"
418
419-: ${cloudinit_config:="/etc/cloud/cloud.cfg"}
420-
421 cloudinit_override()
422 {
423- # If there exist sysconfig/default variable override files use it...
424- if [ -f /etc/default/cloud-init ]; then
425- . /etc/default/cloud-init
426+ # If there exist sysconfig/defaults variable override files use it...
427+ if [ -f /etc/defaults/cloud-init ]; then
428+ . /etc/defaults/cloud-init
429 fi
430 }
431
432 cloudinit_start()
433 {
434 echo -n "${command} starting"
435- ${command} ${cloudinit_config} init
436+ ${command} init
437 }
438
439 load_rc_config $name
440
441=== modified file 'sysvinit/freebsd/cloudinitlocal'
442--- sysvinit/freebsd/cloudinitlocal 2014-01-18 00:45:23 +0000
443+++ sysvinit/freebsd/cloudinitlocal 2014-08-28 17:55:48 +0000
444@@ -6,28 +6,28 @@
445
446 . /etc/rc.subr
447
448+export CLOUD_CFG=/usr/local/etc/cloud/cloud.cfg
449+
450 name="cloudinitlocal"
451-command="/usr/bin/cloud-init"
452+command="/usr/local/bin/cloud-init"
453 start_cmd="cloudlocal_start"
454 stop_cmd=":"
455 rcvar="cloudinit_enable"
456 start_precmd="cloudinit_override"
457 start_cmd="cloudlocal_start"
458
459-: ${cloudinit_config:="/etc/cloud/cloud.cfg"}
460-
461 cloudinit_override()
462 {
463- # If there exist sysconfig/default variable override files use it...
464- if [ -f /etc/default/cloud-init ]; then
465- . /etc/default/cloud-init
466+ # If there exist sysconfig/defaults variable override files use it...
467+ if [ -f /etc/defaults/cloud-init ]; then
468+ . /etc/defaults/cloud-init
469 fi
470 }
471
472 cloudlocal_start()
473 {
474 echo -n "${command} starting"
475- ${command} ${cloudinit_config} init --local
476+ ${command} init --local
477 }
478
479 load_rc_config $name
480
481=== modified file 'tests/unittests/test_distros/test_netconfig.py'
482--- tests/unittests/test_distros/test_netconfig.py 2012-10-11 19:49:45 +0000
483+++ tests/unittests/test_distros/test_netconfig.py 2014-08-28 17:55:48 +0000
484@@ -173,3 +173,60 @@
485 '''
486 self.assertCfgEquals(expected_buf, str(write_buf))
487 self.assertEquals(write_buf.mode, 0644)
488+
489+ def test_simple_write_freebsd(self):
490+ fbsd_distro = self._get_distro('freebsd')
491+ util_mock = self.mocker.replace(util.write_file,
492+ spec=False, passthrough=False)
493+ exists_mock = self.mocker.replace(os.path.isfile,
494+ spec=False, passthrough=False)
495+ load_mock = self.mocker.replace(util.load_file,
496+ spec=False, passthrough=False)
497+
498+ exists_mock(mocker.ARGS)
499+ self.mocker.count(0, None)
500+ self.mocker.result(False)
501+
502+ write_bufs = {}
503+ read_bufs = {
504+ '/etc/rc.conf': '',
505+ }
506+
507+ def replace_write(filename, content, mode=0644, omode="wb"):
508+ buf = WriteBuffer()
509+ buf.mode = mode
510+ buf.omode = omode
511+ buf.write(content)
512+ write_bufs[filename] = buf
513+
514+ def replace_read(fname, read_cb=None, quiet=False):
515+ if fname not in read_bufs:
516+ if fname in write_bufs:
517+ return str(write_bufs[fname])
518+ raise IOError("%s not found" % fname)
519+ else:
520+ if fname in write_bufs:
521+ return str(write_bufs[fname])
522+ return read_bufs[fname]
523+
524+ util_mock(mocker.ARGS)
525+ self.mocker.call(replace_write)
526+ self.mocker.count(0, None)
527+
528+ load_mock(mocker.ARGS)
529+ self.mocker.call(replace_read)
530+ self.mocker.count(0, None)
531+
532+ self.mocker.replay()
533+ fbsd_distro.apply_network(BASE_NET_CFG, False)
534+
535+ self.assertIn('/etc/rc.conf', write_bufs)
536+ write_buf = write_bufs['/etc/rc.conf']
537+ expected_buf = '''
538+ifconfig_eth0="192.168.1.5 netmask 255.255.255.0"
539+ifconfig_eth1="DHCP"
540+defaultrouter="192.168.1.254"
541+'''
542+ self.assertCfgEquals(expected_buf, str(write_buf))
543+ self.assertEquals(write_buf.mode, 0644)
544+
545
546=== added file 'tools/build-on-freebsd'
547--- tools/build-on-freebsd 1970-01-01 00:00:00 +0000
548+++ tools/build-on-freebsd 2014-08-28 17:55:48 +0000
549@@ -0,0 +1,57 @@
550+#!/bin/sh
551+# Since there is no official FreeBSD port yet, we need some way of building and
552+# installing cloud-init. This script takes care of building and installing. It
553+# will optionally make a first run at the end.
554+
555+fail() { echo "FAILED:" "$@" 1>&2; exit 1; }
556+
557+# Check dependencies:
558+depschecked=/tmp/c-i.dependencieschecked
559+pkgs="
560+ dmidecode
561+ py27-argparse
562+ py27-boto gpart sudo
563+ py27-configobj py27-yaml
564+ py27-Jinja2
565+ py27-oauth py27-serial
566+ py27-prettytable
567+ py27-requests py27-six
568+ python py27-cheetah
569+"
570+[ -f "$depschecked" ] || pkg install ${pkgs} || fail "install packages"
571+touch $depschecked
572+
573+# Required but unavailable port/pkg: py27-jsonpatch py27-jsonpointer
574+# Luckily, the install step will take care of this by installing it from pypi...
575+
576+# Build the code and install in /usr/local/:
577+python setup.py build
578+python setup.py install -O1 --skip-build --prefix /usr/local/ --init-system sysvinit_freebsd
579+
580+# Install the correct config file:
581+cp config/cloud.cfg-freebsd /usr/local/etc/cloud/cloud.cfg
582+
583+# Enable cloud-init in /etc/rc.conf:
584+sed -i.bak -e "/cloudinit_enable=.*/d" /etc/rc.conf
585+echo 'cloudinit_enable="YES"' >> /etc/rc.conf
586+
587+echo "Installation completed."
588+
589+if [ "$1" = "run" ]; then
590+ echo "Ok, now let's see if it works."
591+
592+ # Backup SSH keys
593+ mv /etc/ssh/ssh_host_* /tmp/
594+
595+ # Remove old metadata
596+ rm -rf /var/lib/cloud
597+
598+ # Just log everything, quick&dirty
599+ rm /usr/local/etc/cloud/cloud.cfg.d/05_logging.cfg
600+
601+ # Start:
602+ /usr/local/etc/rc.d/cloudinit start
603+
604+ # Restore SSH keys
605+ mv /tmp/ssh_host_* /etc/ssh/
606+fi