Merge lp:~harlowja/cloud-init/legacy-user-make-default into lp:~cloud-init-dev/cloud-init/trunk

Proposed by Joshua Harlow
Status: Merged
Merged at revision: 764
Proposed branch: lp:~harlowja/cloud-init/legacy-user-make-default
Merge into: lp:~cloud-init-dev/cloud-init/trunk
Diff against target: 146 lines (+63/-32)
2 files modified
cloudinit/distros/__init__.py (+56/-29)
tests/unittests/test_distros/test_user_data_normalize.py (+7/-3)
To merge this branch: bzr merge lp:~harlowja/cloud-init/legacy-user-make-default
Reviewer Review Type Date Requested Status
Joshua Harlow (community) Approve
Clint Byrum (community) Approve
Review via email: mp+143933@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Clint Byrum (clint-fewbar) wrote :

Tested on a stock Ubuntu 12.10 cloud image with just cloud-init replaced. The test case of 'user: ec2-user' results in ec2-user being treated as the default user and getting the host's ssh keypair added.

review: Approve
Revision history for this message
Clint Byrum (clint-fewbar) wrote :

So, while this does make sure the SSH keys get installed, it doesn't configure ec2-user with the 'admin' group or setup passwordless sudo.. so the ec2-user is still not equivalent to the normal distro default user.

review: Needs Fixing
Revision history for this message
Joshua Harlow (harlowja) wrote :

Can you upload your cloud.cfg, that might help me see why the user should also show up in the admin group and such.

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

If its just the default, let me know. I think i have a reason why! :-P

760. By harlowja <email address hidden>

Merge the old user style with the distro provided config.

When the old user: style entry is found, don't forget that
we need to use the distro settings that are provided but
override the name with the new name, this is now accomplished
by merging them together in the correct order (using the standard
cloud-init merging algo).

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

Can you try again, this should now be merging with the distro config (and overriding the name) so that the 'user:' 'becomes' the distro user.

Revision history for this message
Clint Byrum (clint-fewbar) wrote :

Just now got around to testing r760. It works! As I discussed with Joshua in IRC, it probably won't be backportable to quantal because of the missing default_user section in cloud.cfg.

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cloudinit/distros/__init__.py'
2--- cloudinit/distros/__init__.py 2013-01-07 16:36:10 +0000
3+++ cloudinit/distros/__init__.py 2013-01-20 01:54:22 +0000
4@@ -705,41 +705,68 @@
5 def normalize_users_groups(cfg, distro):
6 if not cfg:
7 cfg = {}
8+
9 users = {}
10 groups = {}
11 if 'groups' in cfg:
12 groups = _normalize_groups(cfg['groups'])
13
14- # Handle the previous style of doing this...
15- old_user = None
16+ # Handle the previous style of doing this where the first user
17+ # overrides the concept of the default user if provided in the user: XYZ
18+ # format.
19+ old_user = {}
20 if 'user' in cfg and cfg['user']:
21- old_user = str(cfg['user'])
22- if not 'users' in cfg:
23- cfg['users'] = old_user
24- old_user = None
25- if 'users' in cfg:
26- default_user_config = None
27- try:
28- default_user_config = distro.get_default_user()
29- except NotImplementedError:
30- LOG.warn(("Distro has not implemented default user "
31- "access. No default user will be normalized."))
32- base_users = cfg['users']
33- if old_user:
34- if isinstance(base_users, (list)):
35- if len(base_users):
36- # The old user replaces user[0]
37- base_users[0] = {'name': old_user}
38- else:
39- # Just add it on at the end...
40- base_users.append({'name': old_user})
41- elif isinstance(base_users, (dict)):
42- if old_user not in base_users:
43- base_users[old_user] = True
44- elif isinstance(base_users, (str, basestring)):
45- # Just append it on to be re-parsed later
46- base_users += ",%s" % (old_user)
47- users = _normalize_users(base_users, default_user_config)
48+ old_user = cfg['user']
49+ # Translate it into the format that is more useful
50+ # going forward
51+ if isinstance(old_user, (basestring, str)):
52+ old_user = {
53+ 'name': old_user,
54+ }
55+ if not isinstance(old_user, (dict)):
56+ LOG.warn(("Format for 'user' key must be a string or "
57+ "dictionary and not %s"), util.obj_name(old_user))
58+ old_user = {}
59+
60+ # If no old user format, then assume the distro
61+ # provides what the 'default' user maps to, but notice
62+ # that if this is provided, we won't automatically inject
63+ # a 'default' user into the users list, while if a old user
64+ # format is provided we will.
65+ distro_user_config = {}
66+ try:
67+ distro_user_config = distro.get_default_user()
68+ except NotImplementedError:
69+ LOG.warn(("Distro has not implemented default user "
70+ "access. No distribution provided default user"
71+ " will be normalized."))
72+
73+ # Merge the old user (which may just be an empty dict when not
74+ # present with the distro provided default user configuration so
75+ # that the old user style picks up all the distribution specific
76+ # attributes (if any)
77+ default_user_config = util.mergemanydict([old_user, distro_user_config])
78+
79+ base_users = cfg.get('users', [])
80+ if not isinstance(base_users, (list, dict, str, basestring)):
81+ LOG.warn(("Format for 'users' key must be a comma separated string"
82+ " or a dictionary or a list and not %s"),
83+ util.obj_name(base_users))
84+ base_users = []
85+
86+ if old_user:
87+ # Ensure that when user: is provided that this user
88+ # always gets added (as the default user)
89+ if isinstance(base_users, (list)):
90+ # Just add it on at the end...
91+ base_users.append({'name': 'default'})
92+ elif isinstance(base_users, (dict)):
93+ base_users['default'] = base_users.get('default', True)
94+ elif isinstance(base_users, (str, basestring)):
95+ # Just append it on to be re-parsed later
96+ base_users += ",default"
97+
98+ users = _normalize_users(base_users, default_user_config)
99 return (users, groups)
100
101
102
103=== modified file 'tests/unittests/test_distros/test_user_data_normalize.py'
104--- tests/unittests/test_distros/test_user_data_normalize.py 2012-11-09 23:35:48 +0000
105+++ tests/unittests/test_distros/test_user_data_normalize.py 2013-01-20 01:54:22 +0000
106@@ -173,26 +173,29 @@
107 'users': 'default'
108 }
109 (users, _groups) = self._norm(ug_cfg, distro)
110- self.assertIn('bob', users)
111+ self.assertNotIn('bob', users) # Bob is not the default now, zetta is
112 self.assertIn('zetta', users)
113+ self.assertTrue(users['zetta']['default'])
114 self.assertNotIn('default', users)
115 ug_cfg = {
116 'user': 'zetta',
117 'users': 'default, joe'
118 }
119 (users, _groups) = self._norm(ug_cfg, distro)
120- self.assertIn('bob', users)
121+ self.assertNotIn('bob', users) # Bob is not the default now, zetta is
122 self.assertIn('joe', users)
123 self.assertIn('zetta', users)
124+ self.assertTrue(users['zetta']['default'])
125 self.assertNotIn('default', users)
126 ug_cfg = {
127 'user': 'zetta',
128 'users': ['bob', 'joe']
129 }
130 (users, _groups) = self._norm(ug_cfg, distro)
131- self.assertNotIn('bob', users)
132+ self.assertIn('bob', users)
133 self.assertIn('joe', users)
134 self.assertIn('zetta', users)
135+ self.assertTrue(users['zetta']['default'])
136 ug_cfg = {
137 'user': 'zetta',
138 'users': {
139@@ -204,6 +207,7 @@
140 self.assertIn('bob', users)
141 self.assertIn('joe', users)
142 self.assertIn('zetta', users)
143+ self.assertTrue(users['zetta']['default'])
144 ug_cfg = {
145 'user': 'zetta',
146 }