def apply_cloud_providers_config(overrides, defaults=None): ''' Apply the loaded cloud providers configuration. ''' if defaults is None: defaults = PROVIDER_CONFIG_DEFAULTS config = defaults.copy() if overrides: config.update(overrides) # Is the user still using the old format in the new configuration file?! for name, settings in config.copy().items(): if '.' in name: log.warn( 'Please switch to the new providers configuration syntax' ) # Let's help out and migrate the data config = old_to_new(config) # old_to_new will migrate the old data into the 'providers' key of # the config dictionary. Let's map it correctly for prov_name, prov_settings in config.pop('providers').items(): config[prov_name] = prov_settings break providers = {} for key, val in config.items(): if key in ('conf_file', 'include', 'default_include'): continue if not isinstance(val, (list, tuple)): val = [val] else: # Need to check for duplicate cloud provider entries per "alias" or # we won't be able to properly reference it. handled_providers = set() for details in val: if 'provider' not in details: if 'extends' not in details: log.error( 'Please check your cloud providers configuration. ' 'There\'s no \'provider\' nor \'extends\' ' 'definition. So it\'s pretty useless.' ) continue if details['provider'] in handled_providers: log.error( 'You can only have one entry per cloud provider. For ' 'example, if you have a cloud provider configuration ' 'section named, \'production\', you can only have a ' 'single entry for EC2, Joyent, Openstack, and so ' 'forth.' ) raise salt.cloud.exceptions.SaltCloudConfigError( 'The cloud provider alias {0!r} has multiple entries ' 'for the {1[provider]!r} driver.'.format(key, details) ) handled_providers.add(details['provider']) for entry in val: if 'provider' not in entry: entry['provider'] = '-only-extendable-' if key not in providers: providers[key] = {} provider = entry['provider'] if provider in providers[key] and provider == '-only-extendable-': raise salt.cloud.exceptions.SaltCloudConfigError( 'There\'s multiple entries under {0!r} which do not set ' 'a provider setting. This is most likely just a holder ' 'for data to be extended from, however, there can be ' 'only one entry which does not define it\'s \'provider\' ' 'setting.'.format(key) ) elif provider not in providers[key]: providers[key][provider] = entry # Is any provider extending data!? while True: keep_looping = False for provider_alias, entries in providers.copy().items(): for driver, details in entries.iteritems(): # Set a holder for the defined profiles providers[provider_alias][driver]['profiles'] = {} if 'extends' not in details: continue extends = details.pop('extends') if ':' in extends: alias, provider = extends.split(':') if alias not in providers: raise salt.cloud.exceptions.SaltCloudConfigError( 'The {0!r} cloud provider entry in {1!r} is ' 'trying to extend data from {2!r} though {2!r} ' 'is not defined in the salt cloud providers ' 'loaded data.'.format( details['provider'], provider_alias, alias ) ) if provider not in providers.get(alias): raise salt.cloud.exceptions.SaltCloudConfigError( 'The {0!r} cloud provider entry in {1!r} is ' 'trying to extend data from \'{2}:{3}\' though ' '{3!r} is not defined in {1!r}'.format( details['provider'], provider_alias, alias, provider ) ) details['extends'] = '{0}:{1}'.format(alias, provider) elif providers.get(extends) and len(providers[extends]) > 1: raise salt.cloud.exceptions.SaltCloudConfigError( 'The {0!r} cloud provider entry in {1!r} is trying ' 'to extend from {2!r} which has multiple entries ' 'and no provider is being specified. Not ' 'extending!'.format( details['provider'], provider_alias, extends ) ) elif extends not in providers: raise salt.cloud.exceptions.SaltCloudConfigError( 'The {0!r} cloud provider entry in {1!r} is trying ' 'to extend data from {2!r} though {2!r} is not ' 'defined in the salt cloud providers loaded ' 'data.'.format( details['provider'], provider_alias, extends ) ) else: provider = providers.get(extends) if driver in providers.get(extends): details['extends'] = '{0}:{1}'.format(extends, driver) elif '-only-extendable-' in providers.get(extends): details['extends'] = '{0}:{1}'.format( extends, '-only-extendable-' ) else: # We're still not aware of what we're trying to extend # from. Let's try on next iteration details['extends'] = extends keep_looping = True if not keep_looping: break while True: # Merge provided extends keep_looping = False for alias, entries in providers.copy().items(): for driver, details in entries.iteritems(): if 'extends' not in details: # Extends resolved or non existing, continue! continue if 'extends' in details['extends']: # Since there's a nested extends, resolve this one in the # next iteration keep_looping = True continue # Let's get a reference to what we're supposed to extend extends = details.pop('extends') # Split the setting in (alias, driver) ext_alias, ext_driver = extends.split(':') # Grab a copy of what should be extended extended = providers.get(ext_alias).get(ext_driver).copy() # Merge the data to extend with the details extended.update(details) # Update the providers dictionary with the merged data providers[alias][driver] = extended if not keep_looping: break # Now clean up any providers entry that was just used to be a data tree to # extend from for provider_alias, entries in providers.copy().items(): for driver, details in entries.copy().iteritems(): if driver != '-only-extendable-': continue log.info( 'There\'s at least one cloud driver details under the {0!r} ' 'cloud provider alias which does not have the required ' '\'provider\' setting. Was probably just used as a holder ' 'for additional data. Removing it from the available ' 'providers listing'.format( provider_alias ) ) providers[provider_alias].pop(driver) if not providers[provider_alias]: providers.pop(provider_alias) return providers
def apply_cloud_providers_config(overrides, defaults=None): ''' Apply the loaded cloud providers configuration. ''' if defaults is None: defaults = PROVIDER_CONFIG_DEFAULTS config = defaults.copy() if overrides: config.update(overrides) # Is the user still using the old format in the new configuration file?! for name, settings in config.copy().items(): if '.' in name: log.warn('Please switch to the new providers configuration syntax') # Let's help out and migrate the data config = old_to_new(config) # old_to_new will migrate the old data into the 'providers' key of # the config dictionary. Let's map it correctly for prov_name, prov_settings in config.pop('providers').items(): config[prov_name] = prov_settings break providers = {} for key, val in config.items(): if key in ('conf_file', 'include', 'default_include'): continue if not isinstance(val, (list, tuple)): val = [val] else: # Need to check for duplicate cloud provider entries per "alias" or # we won't be able to properly reference it. handled_providers = set() for details in val: if 'provider' not in details: if 'extends' not in details: log.error( 'Please check your cloud providers configuration. ' 'There\'s no \'provider\' nor \'extends\' ' 'definition. So it\'s pretty useless.') continue if details['provider'] in handled_providers: log.error( 'You can only have one entry per cloud provider. For ' 'example, if you have a cloud provider configuration ' 'section named, \'production\', you can only have a ' 'single entry for EC2, Joyent, Openstack, and so ' 'forth.') raise salt.cloud.exceptions.SaltCloudConfigError( 'The cloud provider alias {0!r} has multiple entries ' 'for the {1[provider]!r} driver.'.format(key, details)) handled_providers.add(details['provider']) for entry in val: if 'provider' not in entry: entry['provider'] = '-only-extendable-' if key not in providers: providers[key] = {} provider = entry['provider'] if provider in providers[key] and provider == '-only-extendable-': raise salt.cloud.exceptions.SaltCloudConfigError( 'There\'s multiple entries under {0!r} which do not set ' 'a provider setting. This is most likely just a holder ' 'for data to be extended from, however, there can be ' 'only one entry which does not define it\'s \'provider\' ' 'setting.'.format(key)) elif provider not in providers[key]: providers[key][provider] = entry # Is any provider extending data!? while True: keep_looping = False for provider_alias, entries in providers.copy().items(): for driver, details in entries.iteritems(): # Set a holder for the defined profiles providers[provider_alias][driver]['profiles'] = {} if 'extends' not in details: continue extends = details.pop('extends') if ':' in extends: alias, provider = extends.split(':') if alias not in providers: raise salt.cloud.exceptions.SaltCloudConfigError( 'The {0!r} cloud provider entry in {1!r} is ' 'trying to extend data from {2!r} though {2!r} ' 'is not defined in the salt cloud providers ' 'loaded data.'.format(details['provider'], provider_alias, alias)) if provider not in providers.get(alias): raise salt.cloud.exceptions.SaltCloudConfigError( 'The {0!r} cloud provider entry in {1!r} is ' 'trying to extend data from \'{2}:{3}\' though ' '{3!r} is not defined in {1!r}'.format( details['provider'], provider_alias, alias, provider)) details['extends'] = '{0}:{1}'.format(alias, provider) elif providers.get(extends) and len(providers[extends]) > 1: raise salt.cloud.exceptions.SaltCloudConfigError( 'The {0!r} cloud provider entry in {1!r} is trying ' 'to extend from {2!r} which has multiple entries ' 'and no provider is being specified. Not ' 'extending!'.format(details['provider'], provider_alias, extends)) elif extends not in providers: raise salt.cloud.exceptions.SaltCloudConfigError( 'The {0!r} cloud provider entry in {1!r} is trying ' 'to extend data from {2!r} though {2!r} is not ' 'defined in the salt cloud providers loaded ' 'data.'.format(details['provider'], provider_alias, extends)) else: provider = providers.get(extends) if driver in providers.get(extends): details['extends'] = '{0}:{1}'.format(extends, driver) elif '-only-extendable-' in providers.get(extends): details['extends'] = '{0}:{1}'.format( extends, '-only-extendable-') else: # We're still not aware of what we're trying to extend # from. Let's try on next iteration details['extends'] = extends keep_looping = True if not keep_looping: break while True: # Merge provided extends keep_looping = False for alias, entries in providers.copy().items(): for driver, details in entries.iteritems(): if 'extends' not in details: # Extends resolved or non existing, continue! continue if 'extends' in details['extends']: # Since there's a nested extends, resolve this one in the # next iteration keep_looping = True continue # Let's get a reference to what we're supposed to extend extends = details.pop('extends') # Split the setting in (alias, driver) ext_alias, ext_driver = extends.split(':') # Grab a copy of what should be extended extended = providers.get(ext_alias).get(ext_driver).copy() # Merge the data to extend with the details extended.update(details) # Update the providers dictionary with the merged data providers[alias][driver] = extended if not keep_looping: break # Now clean up any providers entry that was just used to be a data tree to # extend from for provider_alias, entries in providers.copy().items(): for driver, details in entries.copy().iteritems(): if driver != '-only-extendable-': continue log.info( 'There\'s at least one cloud driver details under the {0!r} ' 'cloud provider alias which does not have the required ' '\'provider\' setting. Was probably just used as a holder ' 'for additional data. Removing it from the available ' 'providers listing'.format(provider_alias)) providers[provider_alias].pop(driver) if not providers[provider_alias]: providers.pop(provider_alias) return providers
def apply_vm_profiles_config(providers, overrides, defaults=None): if defaults is None: defaults = VM_CONFIG_DEFAULTS config = defaults.copy() if overrides: config.update(overrides) vms = {} for key, val in config.items(): if key in ('conf_file', 'include', 'default_include'): continue if not isinstance(val, dict): raise salt.cloud.exceptions.SaltCloudConfigError( 'The VM profiles configuration found in {0[conf_file]!r} is ' 'not in the proper format'.format(config) ) val['profile'] = key vms[key] = val # Is any VM profile extending data!? for profile, details in vms.copy().items(): if 'extends' not in details: if ':' in details['provider']: alias, driver = details['provider'].split(':') if alias not in providers or driver not in providers[alias]: log.warning( 'The profile {0!r} is defining {1[provider]!r} as the ' 'provider. Since there\'s no valid configuration for ' 'that provider, the profile will be removed from the ' 'available listing'.format(profile, details) ) vms.pop(profile) continue if 'profiles' not in providers[alias][driver]: providers[alias][driver]['profiles'] = {} providers[alias][driver]['profiles'][profile] = details if details['provider'] not in providers: log.warning( 'The profile {0!r} is defining {1[provider]!r} as the ' 'provider. Since there\'s no valid configuration for ' 'that provider, the profile will be removed from the ' 'available listing'.format(profile, details) ) vms.pop(profile) continue driver = providers[details['provider']].keys()[0] providers[details['provider']][driver].setdefault( 'profiles', {}).update({profile: details}) details['provider'] = '{0[provider]}:{1}'.format(details, driver) vms[profile] = details continue extends = details.pop('extends') if extends not in vms: log.error( 'The {0!r} profile is trying to extend data from {1!r} ' 'though {1!r} is not defined in the salt profiles loaded ' 'data. Not extending and removing from listing!'.format( profile, extends ) ) vms.pop(profile) continue extended = vms.get(extends).copy() extended.pop('profile') extended.update(details) if ':' not in extended['provider']: if extended['provider'] not in providers: log.warning( 'The profile {0!r} is defining {1[provider]!r} as the ' 'provider. Since there\'s no valid configuration for ' 'that provider, the profile will be removed from the ' 'available listing'.format(profile, extended) ) vms.pop(profile) continue driver = providers[extended['provider']].keys()[0] providers[extended['provider']][driver].setdefault( 'profiles', {}).update({profile: extended}) extended['provider'] = '{0[provider]}:{1}'.format(extended, driver) else: alias, driver = extended['provider'].split(':') if alias not in providers or driver not in providers[alias]: log.warning( 'The profile {0!r} is defining {1[provider]!r} as the ' 'provider. Since there\'s no valid configuration for ' 'that provider, the profile will be removed from the ' 'available listing'.format(profile, extended) ) vms.pop(profile) continue providers[alias][driver].setdefault('profiles', {}).update( {profile: extended} ) # Update the profile's entry with the extended data vms[profile] = extended return vms
def apply_vm_profiles_config(providers, overrides, defaults=None): if defaults is None: defaults = VM_CONFIG_DEFAULTS config = defaults.copy() if overrides: config.update(overrides) vms = {} for key, val in config.items(): if key in ('conf_file', 'include', 'default_include'): continue if not isinstance(val, dict): raise salt.cloud.exceptions.SaltCloudConfigError( 'The VM profiles configuration found in {0[conf_file]!r} is ' 'not in the proper format'.format(config)) val['profile'] = key vms[key] = val # Is any VM profile extending data!? for profile, details in vms.copy().items(): if 'extends' not in details: if ':' in details['provider']: alias, driver = details['provider'].split(':') if alias not in providers or driver not in providers[alias]: log.warning( 'The profile {0!r} is defining {1[provider]!r} as the ' 'provider. Since there\'s no valid configuration for ' 'that provider, the profile will be removed from the ' 'available listing'.format(profile, details)) vms.pop(profile) continue if 'profiles' not in providers[alias][driver]: providers[alias][driver]['profiles'] = {} providers[alias][driver]['profiles'][profile] = details if details['provider'] not in providers: log.warning( 'The profile {0!r} is defining {1[provider]!r} as the ' 'provider. Since there\'s no valid configuration for ' 'that provider, the profile will be removed from the ' 'available listing'.format(profile, details)) vms.pop(profile) continue driver = providers[details['provider']].keys()[0] providers[details['provider']][driver].setdefault( 'profiles', {}).update({profile: details}) details['provider'] = '{0[provider]}:{1}'.format(details, driver) vms[profile] = details continue extends = details.pop('extends') if extends not in vms: log.error( 'The {0!r} profile is trying to extend data from {1!r} ' 'though {1!r} is not defined in the salt profiles loaded ' 'data. Not extending and removing from listing!'.format( profile, extends)) vms.pop(profile) continue extended = vms.get(extends).copy() extended.pop('profile') extended.update(details) if ':' not in extended['provider']: if extended['provider'] not in providers: log.warning( 'The profile {0!r} is defining {1[provider]!r} as the ' 'provider. Since there\'s no valid configuration for ' 'that provider, the profile will be removed from the ' 'available listing'.format(profile, extended)) vms.pop(profile) continue driver = providers[extended['provider']].keys()[0] providers[extended['provider']][driver].setdefault( 'profiles', {}).update({profile: extended}) extended['provider'] = '{0[provider]}:{1}'.format(extended, driver) else: alias, driver = extended['provider'].split(':') if alias not in providers or driver not in providers[alias]: log.warning( 'The profile {0!r} is defining {1[provider]!r} as the ' 'provider. Since there\'s no valid configuration for ' 'that provider, the profile will be removed from the ' 'available listing'.format(profile, extended)) vms.pop(profile) continue providers[alias][driver].setdefault('profiles', {}).update({profile: extended}) # Update the profile's entry with the extended data vms[profile] = extended return vms