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
=== modified file 'cloudinit/config/cc_resizefs.py'
--- cloudinit/config/cc_resizefs.py 2014-08-26 19:53:41 +0000
+++ cloudinit/config/cc_resizefs.py 2014-08-28 17:55:48 +0000
@@ -40,8 +40,13 @@
40 return ('xfs_growfs', devpth)40 return ('xfs_growfs', devpth)
4141
4242
43<<<<<<< TREE
43def _resize_ufs(mount_point, devpth):44def _resize_ufs(mount_point, devpth):
44 return ('growfs', devpth)45 return ('growfs', devpth)
46=======
47def _resize_ufs(mount_point, devpth): # pylint: disable=W0613
48 return ('growfs', '-y', devpth)
49>>>>>>> MERGE-SOURCE
4550
46# Do not use a dictionary as these commands should be able to be used51# Do not use a dictionary as these commands should be able to be used
47# for multiple filesystem types if possible, e.g. one command for52# for multiple filesystem types if possible, e.g. one command for
4853
=== modified file 'cloudinit/distros/freebsd.py'
--- cloudinit/distros/freebsd.py 2014-02-28 21:40:08 +0000
+++ cloudinit/distros/freebsd.py 2014-08-28 17:55:48 +0000
@@ -26,6 +26,9 @@
26from cloudinit import ssh_util26from cloudinit import ssh_util
27from cloudinit import util27from cloudinit import util
2828
29from cloudinit.distros import net_util
30from cloudinit.distros.parsers.resolv_conf import ResolvConf
31
29LOG = logging.getLogger(__name__)32LOG = logging.getLogger(__name__)
3033
3134
@@ -33,6 +36,7 @@
33 rc_conf_fn = "/etc/rc.conf"36 rc_conf_fn = "/etc/rc.conf"
34 login_conf_fn = '/etc/login.conf'37 login_conf_fn = '/etc/login.conf'
35 login_conf_fn_bak = '/etc/login.conf.orig'38 login_conf_fn_bak = '/etc/login.conf.orig'
39 resolv_conf_fn = '/etc/resolv.conf'
3640
37 def __init__(self, name, cfg, paths):41 def __init__(self, name, cfg, paths):
38 distros.Distro.__init__(self, name, cfg, paths)42 distros.Distro.__init__(self, name, cfg, paths)
@@ -44,30 +48,53 @@
4448
45 # Updates a key in /etc/rc.conf.49 # Updates a key in /etc/rc.conf.
46 def updatercconf(self, key, value):50 def updatercconf(self, key, value):
47 LOG.debug("updatercconf: %s => %s", key, value)51 LOG.debug("Checking %s for: %s = %s", self.rc_conf_fn, key, value)
48 conf = self.loadrcconf()52 conf = self.loadrcconf()
49 config_changed = False53 config_changed = False
50 for item in conf:54 if key not in conf:
51 if item == key and conf[item] != value:55 LOG.debug("Adding key in %s: %s = %s", self.rc_conf_fn, key,
52 conf[item] = value56 value)
53 LOG.debug("[rc.conf]: Value %s for key %s needs to be changed",57 conf[key] = value
54 value, key)58 config_changed = True
55 config_changed = True59 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
5666
57 if config_changed:67 if config_changed:
58 LOG.debug("Writing new %s file", self.rc_conf_fn)68 LOG.info("Writing %s", self.rc_conf_fn)
59 buf = StringIO()69 buf = StringIO()
60 for keyval in conf.items():70 for keyval in conf.items():
61 buf.write("%s=%s\n" % keyval)71 buf.write('%s="%s"\n' % keyval)
62 util.write_file(self.rc_conf_fn, buf.getvalue())72 util.write_file(self.rc_conf_fn, buf.getvalue())
6373
64 # Load the contents of /etc/rc.conf and store all keys in a dict.74 # Load the contents of /etc/rc.conf and store all keys in a dict. Make sure
75 # quotes are ignored:
76 # hostname="bla"
65 def loadrcconf(self):77 def loadrcconf(self):
78 RE_MATCH = re.compile(r'^(\w+)\s*=\s*(.*)\s*')
66 conf = {}79 conf = {}
67 lines = util.load_file(self.rc_conf_fn).splitlines()80 lines = util.load_file(self.rc_conf_fn).splitlines()
68 for line in lines:81 for line in lines:
69 tok = line.split('=')82 m = RE_MATCH.match(line)
70 conf[tok[0]] = tok[1].rstrip()83 if not m:
84 LOG.debug("Skipping line from /etc/rc.conf: %s", line)
85 continue
86 key = m.group(1).rstrip()
87 val = m.group(2).rstrip()
88 # Kill them quotes (not completely correct, aka won't handle
89 # quoted values, but should be ok ...)
90 if val[0] in ('"', "'"):
91 val = val[1:]
92 if val[-1] in ('"', "'"):
93 val = val[0:-1]
94 if len(val) == 0:
95 LOG.debug("Skipping empty value from /etc/rc.conf: %s", line)
96 continue
97 conf[key] = val
71 return conf98 return conf
7299
73 def readrcconf(self, key):100 def readrcconf(self, key):
@@ -218,7 +245,60 @@
218 ssh_util.setup_user_keys(keys, name, options=None)245 ssh_util.setup_user_keys(keys, name, options=None)
219246
220 def _write_network(self, settings):247 def _write_network(self, settings):
221 return248 entries = net_util.translate_network(settings)
249 nameservers = []
250 searchdomains = []
251 dev_names = entries.keys()
252 for (dev, info) in entries.iteritems():
253 # Skip the loopback interface.
254 if dev.startswith('lo'):
255 continue
256
257 LOG.info('Configuring interface %s', dev)
258
259 if info.get('bootproto') == 'static':
260 LOG.debug('Configuring dev %s with %s / %s', dev, info.get('address'), info.get('netmask'))
261 # Configure an ipv4 address.
262 ifconfig = info.get('address') + ' netmask ' + info.get('netmask')
263
264 # Configure the gateway.
265 self.updatercconf('defaultrouter', info.get('gateway'))
266
267 if 'dns-nameservers' in info:
268 nameservers.extend(info['dns-nameservers'])
269 if 'dns-search' in info:
270 searchservers.extend(info['dns-search'])
271 else:
272 ifconfig = 'DHCP'
273
274 self.updatercconf('ifconfig_' + dev, ifconfig)
275
276 # Try to read the /etc/resolv.conf or just start from scratch if that
277 # fails.
278 try:
279 resolvconf = ResolvConf(util.load_file(self.resolv_conf_fn))
280 resolvconf.parse()
281 except IOError:
282 util.logexc(LOG, "Failed to parse %s, use new empty file", self.resolv_conf_fn)
283 resolvconf = ResolvConf('')
284 resolvconf.parse()
285
286 # Add some nameservers
287 for server in nameservers:
288 try:
289 resolvconf.add_nameserver(server)
290 except ValueError:
291 util.logexc(LOG, "Failed to add nameserver %s", server)
292
293 # And add any searchdomains.
294 for domain in searchdomains:
295 try:
296 resolvconf.add_search_domain(domain)
297 except ValueError:
298 util.logexc(LOG, "Failed to add search domain %s", domain)
299 util.write_file(self.resolv_conf_fn, str(resolvconf), 0644)
300
301 return dev_names
222302
223 def apply_locale(self, locale, out_fn=None):303 def apply_locale(self, locale, out_fn=None):
224 # Adjust the locals value to the new value304 # Adjust the locals value to the new value
225305
=== added file 'config/cloud.cfg-freebsd'
--- config/cloud.cfg-freebsd 1970-01-01 00:00:00 +0000
+++ config/cloud.cfg-freebsd 2014-08-28 17:55:48 +0000
@@ -0,0 +1,88 @@
1# The top level settings are used as module
2# and system configuration.
3
4syslog_fix_perms: root:wheel
5
6# This should not be required, but leave it in place until the real cause of
7# not beeing able to find -any- datasources is resolved.
8datasource_list: ['OpenStack']
9
10# A set of users which may be applied and/or used by various modules
11# when a 'default' entry is found it will reference the 'default_user'
12# from the distro configuration specified below
13users:
14 - default
15
16# If this is set, 'root' will not be able to ssh in and they
17# will get a message to login instead as the above $user (ubuntu)
18disable_root: false
19
20# This will cause the set+update hostname module to not operate (if true)
21preserve_hostname: false
22
23# Example datasource config
24# datasource:
25# Ec2:
26# metadata_urls: [ 'blah.com' ]
27# timeout: 5 # (defaults to 50 seconds)
28# max_wait: 10 # (defaults to 120 seconds)
29
30# The modules that run in the 'init' stage
31cloud_init_modules:
32# - migrator
33 - seed_random
34 - bootcmd
35# - write-files
36 - growpart
37 - resizefs
38 - set_hostname
39 - update_hostname
40# - update_etc_hosts
41# - ca-certs
42# - rsyslog
43 - users-groups
44 - ssh
45
46# The modules that run in the 'config' stage
47cloud_config_modules:
48# - disk_setup
49# - mounts
50 - ssh-import-id
51 - locale
52# - set-passwords
53# - package-update-upgrade-install
54# - landscape
55# - timezone
56# - puppet
57# - chef
58# - salt-minion
59# - mcollective
60 - disable-ec2-metadata
61 - runcmd
62# - byobu
63
64# The modules that run in the 'final' stage
65cloud_final_modules:
66 - rightscale_userdata
67 - scripts-vendor
68 - scripts-per-once
69 - scripts-per-boot
70 - scripts-per-instance
71 - scripts-user
72 - ssh-authkey-fingerprints
73 - keys-to-console
74 - phone-home
75 - final-message
76 - power-state-change
77
78# System and/or distro specific settings
79# (not accessible to handlers/transforms)
80system_info:
81 distro: freebsd
82 default_user:
83 name: beastie
84 lock_passwd: True
85 gecos: FreeBSD
86 groups: [wheel]
87 sudo: ["ALL=(ALL) NOPASSWD:ALL"]
88 shell: /bin/sh
089
=== modified file 'setup.py'
--- setup.py 2014-08-26 19:53:41 +0000
+++ setup.py 2014-08-28 17:55:48 +0000
@@ -63,18 +63,28 @@
6363
64INITSYS_FILES = {64INITSYS_FILES = {
65 'sysvinit': [f for f in glob('sysvinit/redhat/*') if is_f(f)],65 'sysvinit': [f for f in glob('sysvinit/redhat/*') if is_f(f)],
66 'sysvinit_freebsd': [f for f in glob('sysvinit/freebsd/*') if is_f(f)],
66 'sysvinit_deb': [f for f in glob('sysvinit/debian/*') if is_f(f)],67 'sysvinit_deb': [f for f in glob('sysvinit/debian/*') if is_f(f)],
67 'systemd': [f for f in glob('systemd/*') if is_f(f)],68 'systemd': [f for f in glob('systemd/*') if is_f(f)],
68 'upstart': [f for f in glob('upstart/*') if is_f(f)],69 'upstart': [f for f in glob('upstart/*') if is_f(f)],
69}70}
70INITSYS_ROOTS = {71INITSYS_ROOTS = {
71 'sysvinit': '/etc/rc.d/init.d',72 'sysvinit': '/etc/rc.d/init.d',
73 'sysvinit_freebsd': '/usr/local/etc/rc.d',
72 'sysvinit_deb': '/etc/init.d',74 'sysvinit_deb': '/etc/init.d',
73 'systemd': systemd_unitdir(),75 'systemd': systemd_unitdir(),
74 'upstart': '/etc/init/',76 'upstart': '/etc/init/',
75}77}
76INITSYS_TYPES = sorted(list(INITSYS_ROOTS.keys()))78INITSYS_TYPES = sorted(list(INITSYS_ROOTS.keys()))
7779
80# Install everything in the right location and take care of Linux (default) and
81# FreeBSD systems.
82USR = "/usr"
83ETC = "/etc"
84if os.uname()[0] == 'FreeBSD':
85 USR = "/usr/local"
86 ETC = "/usr/local/etc"
87
7888
79def get_version():89def get_version():
80 cmd = ['tools/read-version']90 cmd = ['tools/read-version']
@@ -136,18 +146,17 @@
136 'tools/cloud-init-per',146 'tools/cloud-init-per',
137 ],147 ],
138 license='GPLv3',148 license='GPLv3',
139 data_files=[('/etc/cloud', glob('config/*.cfg')),149 data_files=[(ETC + '/cloud', glob('config/*.cfg')),
140 ('/etc/cloud/cloud.cfg.d', glob('config/cloud.cfg.d/*')),150 (ETC + '/cloud/cloud.cfg.d', glob('config/cloud.cfg.d/*')),
141 ('/etc/cloud/templates', glob('templates/*')),151 (ETC + '/cloud/templates', glob('templates/*')),
142 ('/usr/share/cloud-init', []),152 (USR + '/lib/cloud-init',
143 ('/usr/lib/cloud-init',
144 ['tools/uncloud-init',153 ['tools/uncloud-init',
145 'tools/write-ssh-key-fingerprints']),154 'tools/write-ssh-key-fingerprints']),
146 ('/usr/share/doc/cloud-init',155 (USR + '/share/doc/cloud-init',
147 [f for f in glob('doc/*') if is_f(f)]),156 [f for f in glob('doc/*') if is_f(f)]),
148 ('/usr/share/doc/cloud-init/examples',157 (USR + '/share/doc/cloud-init/examples',
149 [f for f in glob('doc/examples/*') if is_f(f)]),158 [f for f in glob('doc/examples/*') if is_f(f)]),
150 ('/usr/share/doc/cloud-init/examples/seed',159 (USR + '/share/doc/cloud-init/examples/seed',
151 [f for f in glob('doc/examples/seed/*') if is_f(f)]),160 [f for f in glob('doc/examples/seed/*') if is_f(f)]),
152 ],161 ],
153 install_requires=read_requires(),162 install_requires=read_requires(),
154163
=== modified file 'sysvinit/freebsd/cloudconfig'
--- sysvinit/freebsd/cloudconfig 2014-01-18 00:45:23 +0000
+++ sysvinit/freebsd/cloudconfig 2014-08-28 17:55:48 +0000
@@ -6,28 +6,28 @@
66
7. /etc/rc.subr7. /etc/rc.subr
88
9export CLOUD_CFG=/usr/local/etc/cloud/cloud.cfg
10
9name="cloudconfig"11name="cloudconfig"
10command="/usr/bin/cloud-init"12command="/usr/local/bin/cloud-init"
11start_cmd="cloudconfig_start"13start_cmd="cloudconfig_start"
12stop_cmd=":"14stop_cmd=":"
13rcvar="cloudinit_enable"15rcvar="cloudinit_enable"
14start_precmd="cloudinit_override"16start_precmd="cloudinit_override"
15start_cmd="cloudconfig_start"17start_cmd="cloudconfig_start"
1618
17: ${cloudinit_config:="/etc/cloud/cloud.cfg"}
18
19cloudinit_override()19cloudinit_override()
20{20{
21 # If there exist sysconfig/default variable override files use it...21 # If there exist sysconfig/defaults variable override files use it...
22 if [ -f /etc/default/cloud-init ]; then22 if [ -f /etc/defaults/cloud-init ]; then
23 . /etc/default/cloud-init23 . /etc/defaults/cloud-init
24 fi24 fi
25}25}
2626
27cloudconfig_start()27cloudconfig_start()
28{28{
29 echo "${command} starting"29 echo "${command} starting"
30 ${command} ${cloudinit_config} modules --mode config30 ${command} modules --mode config
31}31}
3232
33load_rc_config $name33load_rc_config $name
3434
=== modified file 'sysvinit/freebsd/cloudfinal'
--- sysvinit/freebsd/cloudfinal 2014-01-18 00:45:23 +0000
+++ sysvinit/freebsd/cloudfinal 2014-08-28 17:55:48 +0000
@@ -6,28 +6,28 @@
66
7. /etc/rc.subr7. /etc/rc.subr
88
9export CLOUD_CFG=/usr/local/etc/cloud/cloud.cfg
10
9name="cloudfinal"11name="cloudfinal"
10command="/usr/bin/cloud_init"12command="/usr/local/bin/cloud-init"
11start_cmd="cloudfinal_start"13start_cmd="cloudfinal_start"
12stop_cmd=":"14stop_cmd=":"
13rcvar="cloudinit_enable"15rcvar="cloudinit_enable"
14start_precmd="cloudinit_override"16start_precmd="cloudinit_override"
15start_cmd="cloudfinal_start"17start_cmd="cloudfinal_start"
1618
17: ${cloudinit_config:="/etc/cloud/cloud.cfg"}
18
19cloudinit_override()19cloudinit_override()
20{20{
21 # If there exist sysconfig/default variable override files use it...21 # If there exist sysconfig/defaults variable override files use it...
22 if [ -f /etc/default/cloud-init ]; then22 if [ -f /etc/defaults/cloud-init ]; then
23 . /etc/default/cloud-init23 . /etc/defaults/cloud-init
24 fi24 fi
25}25}
2626
27cloudfinal_start()27cloudfinal_start()
28{28{
29 echo -n "${command} starting"29 echo -n "${command} starting"
30 ${command} ${cloudinit_config} modules --mode final30 ${command} modules --mode final
31}31}
3232
33load_rc_config $name33load_rc_config $name
3434
=== modified file 'sysvinit/freebsd/cloudinit'
--- sysvinit/freebsd/cloudinit 2014-01-18 00:45:23 +0000
+++ sysvinit/freebsd/cloudinit 2014-08-28 17:55:48 +0000
@@ -6,28 +6,28 @@
66
7. /etc/rc.subr7. /etc/rc.subr
88
9export CLOUD_CFG=/usr/local/etc/cloud/cloud.cfg
10
9name="cloudinit"11name="cloudinit"
10command="/usr/bin/cloud_init"12command="/usr/local/bin/cloud-init"
11start_cmd="cloudinit_start"13start_cmd="cloudinit_start"
12stop_cmd=":"14stop_cmd=":"
13rcvar="cloudinit_enable"15rcvar="cloudinit_enable"
14start_precmd="cloudinit_override"16start_precmd="cloudinit_override"
15start_cmd="cloudinit_start"17start_cmd="cloudinit_start"
1618
17: ${cloudinit_config:="/etc/cloud/cloud.cfg"}
18
19cloudinit_override()19cloudinit_override()
20{20{
21 # If there exist sysconfig/default variable override files use it...21 # If there exist sysconfig/defaults variable override files use it...
22 if [ -f /etc/default/cloud-init ]; then22 if [ -f /etc/defaults/cloud-init ]; then
23 . /etc/default/cloud-init23 . /etc/defaults/cloud-init
24 fi24 fi
25}25}
2626
27cloudinit_start()27cloudinit_start()
28{28{
29 echo -n "${command} starting"29 echo -n "${command} starting"
30 ${command} ${cloudinit_config} init30 ${command} init
31}31}
3232
33load_rc_config $name33load_rc_config $name
3434
=== modified file 'sysvinit/freebsd/cloudinitlocal'
--- sysvinit/freebsd/cloudinitlocal 2014-01-18 00:45:23 +0000
+++ sysvinit/freebsd/cloudinitlocal 2014-08-28 17:55:48 +0000
@@ -6,28 +6,28 @@
66
7. /etc/rc.subr7. /etc/rc.subr
88
9export CLOUD_CFG=/usr/local/etc/cloud/cloud.cfg
10
9name="cloudinitlocal"11name="cloudinitlocal"
10command="/usr/bin/cloud-init"12command="/usr/local/bin/cloud-init"
11start_cmd="cloudlocal_start"13start_cmd="cloudlocal_start"
12stop_cmd=":"14stop_cmd=":"
13rcvar="cloudinit_enable"15rcvar="cloudinit_enable"
14start_precmd="cloudinit_override"16start_precmd="cloudinit_override"
15start_cmd="cloudlocal_start"17start_cmd="cloudlocal_start"
1618
17: ${cloudinit_config:="/etc/cloud/cloud.cfg"}
18
19cloudinit_override()19cloudinit_override()
20{20{
21 # If there exist sysconfig/default variable override files use it...21 # If there exist sysconfig/defaults variable override files use it...
22 if [ -f /etc/default/cloud-init ]; then22 if [ -f /etc/defaults/cloud-init ]; then
23 . /etc/default/cloud-init23 . /etc/defaults/cloud-init
24 fi24 fi
25}25}
2626
27cloudlocal_start()27cloudlocal_start()
28{28{
29 echo -n "${command} starting"29 echo -n "${command} starting"
30 ${command} ${cloudinit_config} init --local30 ${command} init --local
31}31}
3232
33load_rc_config $name33load_rc_config $name
3434
=== modified file 'tests/unittests/test_distros/test_netconfig.py'
--- tests/unittests/test_distros/test_netconfig.py 2012-10-11 19:49:45 +0000
+++ tests/unittests/test_distros/test_netconfig.py 2014-08-28 17:55:48 +0000
@@ -173,3 +173,60 @@
173'''173'''
174 self.assertCfgEquals(expected_buf, str(write_buf))174 self.assertCfgEquals(expected_buf, str(write_buf))
175 self.assertEquals(write_buf.mode, 0644)175 self.assertEquals(write_buf.mode, 0644)
176
177 def test_simple_write_freebsd(self):
178 fbsd_distro = self._get_distro('freebsd')
179 util_mock = self.mocker.replace(util.write_file,
180 spec=False, passthrough=False)
181 exists_mock = self.mocker.replace(os.path.isfile,
182 spec=False, passthrough=False)
183 load_mock = self.mocker.replace(util.load_file,
184 spec=False, passthrough=False)
185
186 exists_mock(mocker.ARGS)
187 self.mocker.count(0, None)
188 self.mocker.result(False)
189
190 write_bufs = {}
191 read_bufs = {
192 '/etc/rc.conf': '',
193 }
194
195 def replace_write(filename, content, mode=0644, omode="wb"):
196 buf = WriteBuffer()
197 buf.mode = mode
198 buf.omode = omode
199 buf.write(content)
200 write_bufs[filename] = buf
201
202 def replace_read(fname, read_cb=None, quiet=False):
203 if fname not in read_bufs:
204 if fname in write_bufs:
205 return str(write_bufs[fname])
206 raise IOError("%s not found" % fname)
207 else:
208 if fname in write_bufs:
209 return str(write_bufs[fname])
210 return read_bufs[fname]
211
212 util_mock(mocker.ARGS)
213 self.mocker.call(replace_write)
214 self.mocker.count(0, None)
215
216 load_mock(mocker.ARGS)
217 self.mocker.call(replace_read)
218 self.mocker.count(0, None)
219
220 self.mocker.replay()
221 fbsd_distro.apply_network(BASE_NET_CFG, False)
222
223 self.assertIn('/etc/rc.conf', write_bufs)
224 write_buf = write_bufs['/etc/rc.conf']
225 expected_buf = '''
226ifconfig_eth0="192.168.1.5 netmask 255.255.255.0"
227ifconfig_eth1="DHCP"
228defaultrouter="192.168.1.254"
229'''
230 self.assertCfgEquals(expected_buf, str(write_buf))
231 self.assertEquals(write_buf.mode, 0644)
232
176233
=== added file 'tools/build-on-freebsd'
--- tools/build-on-freebsd 1970-01-01 00:00:00 +0000
+++ tools/build-on-freebsd 2014-08-28 17:55:48 +0000
@@ -0,0 +1,57 @@
1#!/bin/sh
2# Since there is no official FreeBSD port yet, we need some way of building and
3# installing cloud-init. This script takes care of building and installing. It
4# will optionally make a first run at the end.
5
6fail() { echo "FAILED:" "$@" 1>&2; exit 1; }
7
8# Check dependencies:
9depschecked=/tmp/c-i.dependencieschecked
10pkgs="
11 dmidecode
12 py27-argparse
13 py27-boto gpart sudo
14 py27-configobj py27-yaml
15 py27-Jinja2
16 py27-oauth py27-serial
17 py27-prettytable
18 py27-requests py27-six
19 python py27-cheetah
20"
21[ -f "$depschecked" ] || pkg install ${pkgs} || fail "install packages"
22touch $depschecked
23
24# Required but unavailable port/pkg: py27-jsonpatch py27-jsonpointer
25# Luckily, the install step will take care of this by installing it from pypi...
26
27# Build the code and install in /usr/local/:
28python setup.py build
29python setup.py install -O1 --skip-build --prefix /usr/local/ --init-system sysvinit_freebsd
30
31# Install the correct config file:
32cp config/cloud.cfg-freebsd /usr/local/etc/cloud/cloud.cfg
33
34# Enable cloud-init in /etc/rc.conf:
35sed -i.bak -e "/cloudinit_enable=.*/d" /etc/rc.conf
36echo 'cloudinit_enable="YES"' >> /etc/rc.conf
37
38echo "Installation completed."
39
40if [ "$1" = "run" ]; then
41 echo "Ok, now let's see if it works."
42
43 # Backup SSH keys
44 mv /etc/ssh/ssh_host_* /tmp/
45
46 # Remove old metadata
47 rm -rf /var/lib/cloud
48
49 # Just log everything, quick&dirty
50 rm /usr/local/etc/cloud/cloud.cfg.d/05_logging.cfg
51
52 # Start:
53 /usr/local/etc/rc.d/cloudinit start
54
55 # Restore SSH keys
56 mv /tmp/ssh_host_* /etc/ssh/
57fi