404
# Normalizes a input group configuration
405
# which can be a comma seperated list of
406
# group names, or a list of group names
407
# or a python dictionary of group names
408
# to a list of members of that group.
410
# The output is a dictionary of group
411
# names => members of that group which
412
# is the standard form used in the rest
414
def _normalize_groups(grp_cfg):
415
if isinstance(grp_cfg, (str, basestring, list)):
417
for i in util.uniq_merge(grp_cfg):
422
if isinstance(grp_cfg, (dict)):
423
for (grp_name, grp_members) in grp_cfg.items():
424
groups[grp_name] = util.uniq_merge_sorted(grp_members)
426
raise TypeError(("Group config must be list, dict "
427
" or string types only and not %s") %
428
util.obj_name(grp_cfg))
432
# Normalizes a input group configuration
433
# which can be a comma seperated list of
434
# user names, or a list of string user names
435
# or a list of dictionaries with components
436
# that define the user config + 'name' (if
437
# a 'name' field does not exist then the
438
# default user is assumed to 'own' that
441
# The output is a dictionary of user
442
# names => user config which is the standard
443
# form used in the rest of cloud-init. Note
444
# the default user will have a special config
445
# entry 'default' which will be marked as true
446
# all other users will be marked as false.
447
def _normalize_users(u_cfg, def_user_cfg=None):
448
if isinstance(u_cfg, (dict)):
450
for (k, v) in u_cfg.items():
451
if isinstance(v, (bool, int, basestring, str, float)):
453
ad_ucfg.append(str(k))
454
elif isinstance(v, (dict)):
458
raise TypeError(("Unmappable user value type %s"
459
" for key %s") % (util.obj_name(v), k))
461
elif isinstance(u_cfg, (str, basestring)):
462
u_cfg = util.uniq_merge_sorted(u_cfg)
465
for user_config in u_cfg:
466
if isinstance(user_config, (str, basestring, list)):
467
for u in util.uniq_merge(user_config):
468
if u and u not in users:
470
elif isinstance(user_config, (dict)):
471
if 'name' in user_config:
472
n = user_config.pop('name')
473
prev_config = users.get(n) or {}
474
users[n] = util.mergemanydict([prev_config,
477
# Assume the default user then
478
prev_config = users.get('default') or {}
479
users['default'] = util.mergemanydict([prev_config,
482
raise TypeError(("User config must be dictionary/list "
483
" or string types only and not %s") %
484
util.obj_name(user_config))
486
# Ensure user options are in the right python friendly format
489
for (uname, uconfig) in users.items():
491
for (k, v) in uconfig.items():
492
k = k.replace('-', '_').strip()
495
c_users[uname] = c_uconfig
498
# Fixup the default user into the real
499
# default user name and replace it...
501
if users and 'default' in users:
502
def_config = users.pop('default')
504
# Pickup what the default 'real name' is
505
# and any groups that are provided by the
507
def_user = def_user_cfg.pop('name')
508
def_groups = def_user_cfg.pop('groups', [])
509
# Pickup any config + groups for that user name
510
# that we may have previously extracted
511
parsed_config = users.pop(def_user, {})
512
parsed_groups = parsed_config.get('groups', [])
513
# Now merge our extracted groups with
514
# anything the default config provided
515
users_groups = util.uniq_merge_sorted(parsed_groups, def_groups)
516
parsed_config['groups'] = ",".join(users_groups)
517
# The real config for the default user is the
518
# combination of the default user config provided
519
# by the distro, the default user config provided
520
# by the above merging for the user 'default' and
521
# then the parsed config from the user's 'real name'
522
# which does not have to be 'default' (but could be)
523
users[def_user] = util.mergemanydict([def_user_cfg,
527
# Ensure that only the default user that we
528
# found (if any) is actually marked as being
531
for (uname, uconfig) in users.items():
532
if def_user and uname == def_user:
533
uconfig['default'] = True
535
uconfig['default'] = False
540
# Normalizes a set of user/users and group
541
# dictionary configuration into a useable
542
# format that the rest of cloud-init can
543
# understand using the default user
544
# provided by the input distrobution (if any)
545
# to allow for mapping of the 'default' user.
547
# Output is a dictionary of group names -> [member] (list)
548
# and a dictionary of user names -> user configuration (dict)
550
# If 'user' exists it will override
551
# the 'users'[0] entry (if a list) otherwise it will
552
# just become an entry in the returned dictionary (no override)
553
def normalize_users_groups(cfg, distro):
559
groups = _normalize_groups(cfg['groups'])
561
# Handle the previous style of doing this...
563
if 'user' in cfg and cfg['user']:
564
old_user = str(cfg['user'])
565
if not 'users' in cfg:
566
cfg['users'] = old_user
569
default_user_config = None
571
default_user_config = distro.get_default_user()
572
except NotImplementedError:
573
LOG.warn(("Distro has not implemented default user "
574
"access. No default user will be normalized."))
575
base_users = cfg['users']
577
if isinstance(base_users, (list)):
579
# The old user replaces user[0]
580
base_users[0] = {'name': old_user}
582
# Just add it on at the end...
583
base_users.append({'name': old_user})
584
elif isinstance(base_users, (dict)):
585
if old_user not in base_users:
586
base_users[old_user] = True
587
elif isinstance(base_users, (str, basestring)):
588
# Just append it on to be re-parsed later
589
base_users += ",%s" % (old_user)
590
users = _normalize_users(base_users, default_user_config)
591
return (users, groups)
594
# Given a user dictionary config it will
595
# extract the default user name and user config
596
# from that list and return that tuple or
597
# return (None, None) if no default user is
598
# found in the given input
599
def extract_default(users, default_name=None, default_config=None):
603
def safe_find(entry):
605
if not config or 'default' not in config:
608
return config['default']
610
tmp_users = users.items()
611
tmp_users = dict(itertools.ifilter(safe_find, tmp_users))
613
return (default_name, default_config)
615
name = tmp_users.keys()[0]
616
config = tmp_users[name]
617
config.pop('default', None)
618
return (name, config)
434
622
locs = importer.find_module(name,