lib/forj-account.rb in forj-0.0.43 vs lib/forj-account.rb in forj-0.0.44

- old
+ new

@@ -43,14 +43,42 @@ Dir.foreach($FORJ_ACCOUNTS_PATH) { |x| aAccounts << x if not x.match(/^\..?$/) } aAccounts end end +# ForjAccount manage a list of key/value grouped by section. +# The intent of ForjAccount is to attach some keys/values to +# an account to help end users to switch between each of them. +# +# ForjAccount based on ForjConfig (see forj-config.rb) +# ensure ForjConfig and ForjAccount defines following common functions +# - set (key, value) +# - get (key) +# +# This means that key HAVE to be unique across sections +# By default, keys maps with the same key name in ForjConfig. +# But we can redefine the ForjConfig mapping of any key on need. +# +# ForjConfig, loads Account meta structure from defaults.yaml, sections +# +# defaults.yaml structure is: +# sections: +# default: => defines key/values recognized by ForjAccount to be only managed by ForjConfig. +# <key> : +# :desc : <value> => defines the ForjConfig key description. +# <section>: Define a section name. For each keys on this section, the account file will kept those data under this section. +# <key>: +# :desc: defines the key description. +# :readonly: true if this key cannot be updated by ForjAccount.set +# :account_exclusive: true if this key cannot be predefined on ForjConfig keys list +# :default: <ForjConfig real key name> Used to map the ForjAccount key to a different ForjConfig key name. + class ForjAccount attr_reader :sAccountName attr_reader :hAccountData + attr_reader :oConfig # This object manage data located in oConfig[:hpc_accounts/AccountName] def initialize(oConfig) # Initialize object @@ -65,83 +93,185 @@ sProvider = 'hpcloud' sProvider = @oConfig.get(:provider) if @oConfig.get(:provider) @hAccountData = {} - rhSet(@hAccountData, @sAccountName, [:account, :name]) if rhExist?(@hAccountData, [:account, :name]) != 2 - rhSet(@hAccountData, sProvider, [:account, :provider]) if rhExist?(@hAccountData, [:account, :provider]) != 2 + _set(:account, :name, @sAccountName) if exist?(:name) != 'hash' + _set(:account, :provider, sProvider) if exist?(:provider) != 'hash' + end - # oForjAccount data get are retrieved from the account file under section described in defaults.yaml (:account_section_mapping), as soon as this mapping exists. - # If not found, get the data from the local configuration file. Usually ~/.forj/config.yaml - # If not found, get the data from defaults.yaml + # oForjAccount data get at several levels: + # - get the data from runtime (runtimeSet/runtimeGet) + # - otherwise, get data from account file under section described in defaults.yaml (:account_section_mapping), as soon as this mapping exists. + # - otherwise, get the data from the local configuration file. Usually ~/.forj/config.yaml + # - otherwise, get the data from defaults.yaml # otherwise, use the get default parameter as value. Default is nil. def get(key, default = nil) return nil if not key key = key.to_sym if key.class == String - section = rhGet(@oConfig.getAppDefault(:account_section_mapping, key), :section) - yInterm = nil - if section - yInterm = rhGet(@hAccountData, section) - else + + return @oConfig.runtimeGet(key) if @oConfig.runtimeExist?(key) + + section = ForjDefault.get_meta_section(key) + default_key = key + + if not section Logging.debug("ForjAccount.get: No section found for key '%s'." % [key]) + else + return rhGet(@hAccountData, section, key) if rhExist?(@hAccountData, section, key) == 2 + + hMeta = @oConfig.getAppDefault(:sections) + if rhExist?(hMeta, section, key, :default) == 3 + default_key = rhGet(hMeta, section, key, :default) + Logging.debug("ForjAccount.get: Reading default key '%s' instead of '%s'" % [default_key, key]) + end + return default if rhExist?(hMeta, section, key, :account_exclusive) == 3 end - @oConfig.get(key, yInterm , default ) + + @oConfig.get(default_key , default ) end def exist?(key) return nil if not key key = key.to_sym if key.class == String - section = rhGet(@oConfig.getAppDefault(:account_section_mapping, key), :section) - yInterm = nil - yInterm = rhGet(@hAccountData, section) if section - @oConfig.exist?(key, yInterm) + section = ForjDefault.get_meta_section(key) + if not section + Logging.debug("ForjAccount.exist?: No section found for key '%s'." % [key]) + return nil + end + return @sAccountName if rhExist?(@hAccountData, section, key) == 2 + hMeta = @oConfig.getAppDefault(:sections) + if rhExist?(hMeta, section, key, :default) == 3 + default_key = rhGet(hMeta, section, key, :default) + Logging.debug("ForjAccount.exist?: Reading default key '%s' instead of '%s'" % [default_key, key]) + else + default_key = key + end + return nil if rhExist?(hMeta, section, key, :account_exclusive) == 3 + + @oConfig.exist?(default_key) + end + # Return true if readonly. set won't be able to update this value. + # Only _set (private function) is able. + def readonly?(key) + return nil if not key + + key = key.to_sym if key.class == String + section = ForjDefault.get_meta_section(key) + + rhGet(@oConfig.getAppDefault(:sections, section), key, :readonly) + + end + + def meta_set(key, hMeta) + key = key.to_sym if key.class == String + section = ForjDefault.get_meta_section(key) + hCurMeta = rhGet(@oConfig.getAppDefault(:sections, section), key) + hMeta.each { | mykey, myvalue | + rhSet(hCurMeta, myvalue, mykey) + } + end + + def meta_exist?(key) + return nil if not key + + key = key.to_sym if key.class == String + section = ForjDefault.get_meta_section(key) + rhExist?(@oConfig.getAppDefault(:sections, section), key) == 1 + end + + def get_meta_section(key) + key = key.to_sym if key.class == String + rhGet(@account_section_mapping, key) + end + + def meta_type?(key) + return nil if not key + + section = ForjDefault.get_meta_section(key) + + return section if section == :default + @sAccountName + end + + # Loop on account metadata + def metadata_each + rhGet(ForjDefault.dump(), :sections).each { | section, hValue | + next if section == :default + hValue.each { | key, value | + yield section, key, value + } + } + end + + # Return true if exclusive + def exclusive?(key) + return nil if not key + + key = key.to_sym if key.class == String + section = ForjDefault.get_meta_section(key) + + rhGet(@oConfig.getAppDefault(:sections, section), key, :account_exclusive) + end + + # This function update a section/key=value if the account structure is defined. + # If no section is defined, set it in runtime config. def set(key, value) return nil if not key key = key.to_sym if key.class == String - section = rhGet(@oConfig.getAppDefault(:account_section_mapping, key), :section) - return nil if not section - rhSet(@hAccountData, value, section, key) + section = ForjDefault.get_meta_section(key) + + return @oConfig.set(key, value) if not section + return nil if readonly?(key) + _set(section, key, value) end def del(key) return nil if not key key = key.to_sym if key.class == String - section = rhGet(@oConfig.getAppDefault(:account_section_mapping, key), :section) + section = ForjDefault.get_meta_section(key) return nil if not section rhSet(@hAccountData, nil, section, key) end def getAccountData(section, key, default=nil) return rhGet(@hAccountData, section, key) if rhExist?(@hAccountData, section, key) == 2 default end - def ac_load(sAccountName = @sAccountName) + def ac_new(sAccountName) + return nil if sAccountName.nil? + @sAccountName = sAccountName + @sAccountFile = File.join($FORJ_ACCOUNTS_PATH, @sAccountName) + + @hAccountData = {:account => {:name => sAccountName, :provider => @oConfig.get(:provider_name)}} + end + + def ac_load(sAccountName = @sAccountName, bHPCloudLoad = true) # Load Account Information if sAccountName != @sAccountName - @sAccountName = sAccountName - @sAccountFile = File.join($FORJ_ACCOUNTS_PATH, @sAccountName) + ac_new(sAccountName) end if File.exists?(@sAccountFile) @hAccountData = @oConfig.ExtraLoad(@sAccountFile, :forj_accounts, @sAccountName) # Check if hAccountData are using symbol or needs to be updated. - sProvider = @oConfig.get(:provider, nil, 'hpcloud') + sProvider = @oConfig.get(:provider, 'hpcloud') rhSet(@hAccountData, @sAccountName, :account, :name) if rhExist?(@hAccountData, :account, :name) != 2 rhSet(@hAccountData, sProvider, :account, :provider) if rhExist?(@hAccountData, :account, :provider) != 2 - provider_load() + provider_load() if bHPCloudLoad if rhKeyToSymbol?(@hAccountData, 2) - @hAccountData = rhKeyToSymbol(@hAccountData, 2) + @hAccountData = rhKeyToSymbol(@hAccountData, 2) self.ac_save() end return @hAccountData end nil @@ -176,11 +306,11 @@ # Check/create keypair self.keypair_setup() # Checking cloud connection Logging.message("Checking cloud connection") - ForjConnection.new(@oConfig) + ForjConnection.new(self) Logging.message("Setup '%s' done. Thank you." % @sAccountName) end def setup_provider_account() @@ -234,11 +364,11 @@ tenant_name = nil tenants.each { |elem| tenant_name = elem['name'] if elem['id'] == tenant_id } if tenant_name Logging.debug("Tenant ID '%s': '%s' found." % [tenant_id, tenant_name]) hCompute = { :tenant_name => tenant_name } - rhSet(@hAccountData, hCompute, :compute) + rhSet(@hAccountData, hCompute, :maestro) else Logging.error("Unable to find the tenant Name for '%s' ID." % tenant_id) end @oConfig.set('tenants', tenants) end @@ -332,16 +462,16 @@ key_path = ask ("Please provide the SSH private key path used by default on this account:") do | q | q.default = orig_key_path q.validate = /.*+/ end keys_entered = keypair_detect(key_name, key_path) - if not keys_entered[:private_key_exist?] and not keys_entered[:public_key_exist?] + if not keys_entered[:private_key_exist? ] and not keys_entered[:public_key_exist? ] if agree("The key you entered was not found. Do you want to create this one?") base_dir = keys_entered[:keypair_path] if not File.directory?(base_dir) if agree("'%s' doesn't exist. Do you want to create it?" % base_dir) - Helpers.ensure_dir_exists(base_dir) + AppInit.ensure_dir_exists(base_dir) end end else key_path = nil end @@ -364,19 +494,19 @@ private_key_file = File.join(keys[:keypair_path], keys[:private_key_name]) public_key_file = File.join(keys[:keypair_path], keys[:public_key_name]) # Creation sequences - if not keys[:private_key_exist?] + if not keys[:private_key_exist? ] # Need to create a key. ask if we need so. Logging.message("The private key file attached to keypair named '%s' is not found. forj will propose to create one for you. Please review the proposed private key file name and path.\nYou can press Enter to accept the default value." % keys[:keypair_name]) real_key_path = File.expand_path(ask("Private key file path:") do |q| q.validate = /\w+/ q.default = private_key_file end) if not File.exists?(real_key_path) - Helpers.ensure_dir_exists(File.dirname(real_key_path)) + AppInit.ensure_dir_exists(File.dirname(real_key_path)) command = 'ssh-keygen -t rsa -f %s' % real_key_path Logging.debug("Executing '%s'" % command) system(command) end if not File.exists?(real_key_path) @@ -388,11 +518,11 @@ @oConfig.SaveConfig() end end end - if not keys[:public_key_exist?] + if not keys[:public_key_exist? ] Logging.message("Your public key '%s' was not found. Getting it from the private one. It may require your passphrase." % [public_key_file]) command = 'ssh-keygen -y -f %s > %s' % [private_key_file,public_key_file ] Logging.debug("Executing '%s'" % command) system(command) end @@ -520,26 +650,14 @@ pipe.puts('DNS_SECRET=%s' % [hpc_creds[:secret_key]]) pipe.close_write } Logging.info("'%s' written." % cloud_fog) end -end + # private functions + private + def _set(section, key, value) + return nil if not key or not section -def ensure_forj_dirs_exists() - # Function to create FORJ paths if missing. + rhSet(@hAccountData, value, section, key) + end - # Defining Global variables - $FORJ_DATA_PATH = File.expand_path(File.join('~', '.forj')) - $FORJ_ACCOUNTS_PATH = File.join($FORJ_DATA_PATH, 'accounts') - $FORJ_KEYPAIRS_PATH = File.join($FORJ_DATA_PATH, 'keypairs') - $FORJ_CREDS_PATH = File.expand_path(File.join('~', '.cache', 'forj')) - - # TODO: To move to an hpcloud object. - $HPC_KEYPAIRS = File.expand_path(File.join('~', '.hpcloud', 'keypairs')) - $HPC_ACCOUNTS = File.expand_path(File.join('~', '.hpcloud', 'accounts')) - - Helpers.ensure_dir_exists($FORJ_DATA_PATH) - Helpers.ensure_dir_exists($FORJ_ACCOUNTS_PATH) - Helpers.ensure_dir_exists($FORJ_KEYPAIRS_PATH) - FileUtils.chmod(0700, $FORJ_KEYPAIRS_PATH) - Helpers.ensure_dir_exists($FORJ_CREDS_PATH) end