class Kitchen::Driver::Scalr
@author Mohammed HAWARI <mohammed@hawari.fr>
Public Instance Methods
cleanup_scalr(scalr_api, state)
click to toggle source
# File lib/kitchen/driver/scalr.rb, line 139 def cleanup_scalr(scalr_api, state) puts "Starting the tear-down process" if state.key?(:farmLaunched) puts "A running server is here, terminate the farm" scalr_api.post('/api/v1beta0/user/%s/farms/%d/actions/terminate/' % [config[:scalr_env_id], state[:farmId]], {}) state.delete(:hostname) state.delete(:port) state.delete(:username) state.delete(:ssh_key) state.delete(:farmLaunched) end if state.key?(:farmRoleId) puts "Now waiting until all the servers are terminated..." wait_for_empty(scalr_api, '/api/v1beta0/user/%s/farms/%d/servers/' % [config[:scalr_env_id], state[:farmId]]) puts "...Done" puts "Cleanup of the farm role..." scalr_api.delete('/api/v1beta0/user/%s/farm-roles/%d/' % [config[:scalr_env_id], state[:farmRoleId]]) puts '...Done' state.delete(:farmRoleId) end if state.key?(:roleId) && config[:scalr_use_role] == -1 puts "Cleanup of the role..." scalr_api.delete('/api/v1beta0/user/%s/roles/%s/' % [config[:scalr_env_id], state[:roleId]]) puts '...Done' state.delete(:roleId) end if state.key?(:farmId) puts "Cleanup of the farm..." scalr_api.delete('/api/v1beta0/user/%s/farms/%d/' % [config[:scalr_env_id], state[:farmId]]) puts '...Done' state.delete(:farmId) end if state.key?(:scriptId) puts "Cleanup of the script..." scalr_api.delete('/api/v1beta0/user/%s/scripts/%d/' % [config[:scalr_env_id], state[:scriptId]]) puts "...Done" state.delete(:scriptId) end if state.key?(:keyfileName) puts "Cleanup of the local keys..." res = `rm -rf #{state[:keyfileName]}` res = `rm -rf #{state[:keyfileName]}.pub` puts "...Done" state.delete(:scriptId) end end
create(state)
click to toggle source
# File lib/kitchen/driver/scalr.rb, line 79 def create(state) if config[:scalr_api_key_id]=='' #We have to find some other way of getting the credentials loadCredentials end #Create a Scalr API object scalr_api = ScalrAPI.new(config[:scalr_api_url], config[:scalr_api_key_id], config[:scalr_api_key_secret]) #Create a farm state[:suuid] = SecureRandom.uuid uuid = 'KITCHEN_FARM_' + instance.name + "_" + state[:suuid] createFarmObject = { 'name' => uuid, 'description' => 'Test Kitchen Farm', 'project' => { 'id' => config[:scalr_project_id] } } puts 'Creating farm with name: %s' % [uuid] response = scalr_api.create('/api/v1beta0/user/%s/farms/' % [config[:scalr_env_id] ], createFarmObject) state[:farmId] = response['id'] puts 'Success: farmId is %d' % [state[:farmId]] if config[:scalr_use_role] == -1 createCustomRole(scalr_api, state) else state[:roleId] = config[:scalr_use_role] state[:imagePlatform] = config[:scalr_platform] state[:imageLocation] = config[:scalr_location] end #Now create the farm role object puts "Creating the Farm Role" farmRoleObject = buildFarmRoleObject(state, config) response = scalr_api.create('/api/v1beta0/user/%s/farms/%d/farm-roles/' % [config[:scalr_env_id], state[:farmId]], farmRoleObject) puts "Farm Role created" state[:farmRoleId] = response['id'] # Creating the configured global variables if !config[:scalr_global_variables].empty? setup_global_vars(config, state, scalr_api) end #Start the farm now response = scalr_api.post('/api/v1beta0/user/%s/farms/%d/actions/launch/' % [config[:scalr_env_id], state[:farmId]], {}) state[:farmLaunched] = 1 #Keep polling for server status wait_for_status(scalr_api, state, 'running') #Generate and upload credentials to the instance setup_credentials(scalr_api,state) #Finally get the IP address response = scalr_api.list('/api/v1beta0/user/%s/farms/%d/servers/' % [config[:scalr_env_id], state[:farmId]] ) if response.size == 0 then raise "No running server in the farm!" end if config[:scalr_use_private_ip] then state[:hostname] = response[0]['privateIp'][0] else state[:hostname] = response[0]['publicIp'][0] end state[:ssh_key] = state[:keyfileName] #state[:proxy_command] = #state[:rdp_port] = end
createCustomRole(scalr_api,state)
click to toggle source
# File lib/kitchen/driver/scalr.rb, line 235 def createCustomRole(scalr_api,state) #Get the imageId for the provided image puts 'Getting the imageId for image %s' % [config[:scalr_server_image]] response = scalr_api.list('/api/v1beta0/user/%s/images/?name=%s' % [config[:scalr_env_id], config[:scalr_server_image] ]) if response.size == 0 then raise 'No matching image was found in this environment!' end state[:imageId] = response[0]['id'] state[:imageOsId] = response[0]['os']['id'] state[:imagePlatform] = response[0]['cloudPlatform'] state[:imageLocation] = response[0]['cloudLocation'] puts 'The image id is %s' % [state[:imageId]] puts 'The image os id is %s' % [state[:imageOsId]] puts 'The image platform is %s' % [state[:imagePlatform]] puts 'The image Location is %s' % [state[:imageLocation]] #Create a matching role on the fly ruuid = 'KITCHEN-ROLE-' + state[:suuid] roleObject = { "builtinAutomation" => ["base"], "category" => { "id" => 1 }, "description" => "test kitchen role", "name" => ruuid, "os" => { "id" => state[:imageOsId] }, "quickStart" => false, "useScalrAgent" => true } puts 'Creating a role with name %s' % [ruuid] response = scalr_api.create('/api/v1beta0/user/%s/roles/' % [config[:scalr_env_id] ], roleObject) state[:roleId] = response['id'] puts 'The role id is %d' % [state[:roleId]] #Create a RoleImage matching roleImageObject = { "image" => { "id" => state[:imageId], }, "role" => { "id" => state[:roleId] } } response = scalr_api.create('/api/v1beta0/user/%s/roles/%d/images/' % [config[:scalr_env_id], state[:roleId]], roleImageObject) puts "RoleImage association created" end
destroy(state)
click to toggle source
# File lib/kitchen/driver/scalr.rb, line 207 def destroy(state) if config[:scalr_api_key_id]=='' then #We have to find some other way of getting the credentials loadCredentials end scalr_api = ScalrAPI.new(config[:scalr_api_url], config[:scalr_api_key_id], config[:scalr_api_key_secret]) cleanup_scalr(scalr_api, state) end
setup_credentials(scalr_api,state)
click to toggle source
# File lib/kitchen/driver/scalr.rb, line 326 def setup_credentials(scalr_api,state) response = scalr_api.list('/api/v1beta0/user/%s/farms/%d/servers/' % [config[:scalr_env_id], state[:farmId]]) state[:serverId] = response[0]['id'] #Handle the Linux case #Generate a key if !windows_os? then keyfileName = 'KEY_' + state[:suuid] state[:username] = 'root' state[:keyfileName] = keyfileName puts "Generating a key named %s" % [keyfileName] res = `yes | ssh-keygen -q -f #{keyfileName} -N ""` f = File.open(keyfileName + ".pub") scriptData = Kitchen::Driver::SCALR_SSH_SCRIPT % { :ssh_pub_key => f.read } if config[:scalr_permit_ssh_root_login] scriptData += Kitchen::Driver::SCALR_SSH_ROOT_PERMIT_SCRIPT end f.close state[:scriptOsType] = "linux" else instance_password = SecureRandom.urlsafe_base64(20) instance_username = "adminchef" scriptData = Kitchen::Driver::SCALR_PS_SCRIPT % {:username => instance_username, :password => instance_password} state[:scriptOsType] = "windows" state[:username] = instance_username state[:password] = instance_password end #Now create a script in Scalr puts "Creating a script in Scalr with this key" response = scalr_api.create('/api/v1beta0/user/%s/scripts/' % [config[:scalr_env_id]], { 'name' => 'TestKitchenScript_%s' % [keyfileName], 'osType' => state[:scriptOsType] }) state[:scriptId] = response['id'] puts "Script created with id %s" % [state[:scriptId]] #Now create a script version with the actual body puts "Creating a script version" # puts "Script content:" # puts scriptData # puts "End of script content" response = scalr_api.create('/api/v1beta0/user/%s/scripts/%d/script-versions/' % [config[:scalr_env_id], state[:scriptId]], { 'body' => scriptData, 'script' => { 'id' => state[:scriptId] } }) puts "Script version created" #Finally try and execute the script puts "Executing the script" response = scalr_api.create('/api/v1beta0/user/%s/scripts/%d/actions/execute/' % [config[:scalr_env_id], state[:scriptId]], { 'server' => { 'id' => state[:serverId] } }) state[:scriptExecutionId] = response['id'] puts "Execution started with id %s" % [state[:scriptExecutionId]] #Wait for execution to be complete elapsed_time = 0 "Waiting for execution to be finished" while (elapsed_time < config[:scalr_server_status_polling_timeout]) do puts "%d seconds elapsed. Polling" % [elapsed_time] response = scalr_api.fetch('/api/v1beta0/user/%s/script-executions/%s/' % [config[:scalr_env_id], state[:scriptExecutionId]]) if (response['status'] == 'finished') puts "Script execution has finished." return end puts "Script execution is still in %s state" % [response['status']] sleep config[:scalr_server_status_polling_period] elapsed_time += config[:scalr_server_status_polling_period] end raise "Error in script execution" end
setup_global_vars(config, state, scalr_api)
click to toggle source
# File lib/kitchen/driver/scalr.rb, line 282 def setup_global_vars(config, state, scalr_api) puts 'Listing existing global variables' # Start by listing the GVs at the Farm scope to know which GVs exist gv_list = scalr_api.list('/api/v1beta0/user/%s/farms/%d/global-variables/' % [config[:scalr_env_id], state[:farmId]]) existing_gvs = {} gv_list.each do |gv| existing_gvs[gv['name']] = gv end config[:scalr_global_variables].each do |key, val| if existing_gvs.has_key? key.to_s puts 'Global variable "%s" exists, setting value "%s"...' % [key, val[:value]] # set global var value if val[:scope] and val[:scope].downcase == 'farm' then gv_set_url = '/api/v1beta0/user/%s/farms/%d/global-variables/%s' % [config[:scalr_env_id], state[:farmId], key] else gv_set_url = '/api/v1beta0/user/%s/farm-roles/%d/global-variables/%s' % [config[:scalr_env_id], state[:farmRoleId], key] end globalVariableObjectEdit = { 'value' => val[:value] } response = scalr_api.edit(gv_set_url, globalVariableObjectEdit) else puts 'Global variable "%s" not found, creating with value: "%s"...' % [key, val[:value]] # create global var if val[:scope] and val[:scope].downcase == 'farm' then gv_create_url = '/api/v1beta0/user/%s/farms/%d/global-variables/' % [config[:scalr_env_id], state[:farmId], key] else gv_create_url = '/api/v1beta0/user/%s/farm-roles/%d/global-variables/' % [config[:scalr_env_id], state[:farmRoleId], key] end val.delete(:scope) globalVariableDefaults = { 'category' => '', 'name' => key, 'description' => '', 'hidden' => false, 'locked' => false } globalVariableObjectCreate = globalVariableDefaults.deep_merge(val) response = scalr_api.create(gv_create_url, globalVariableObjectCreate) end end puts 'Global variables created/updated' end
wait_for_empty(scalr_api, endpoint)
click to toggle source
# File lib/kitchen/driver/scalr.rb, line 186 def wait_for_empty(scalr_api, endpoint) elapsed_time = 0 while elapsed_time < config[:scalr_server_status_polling_timeout] do response = scalr_api.list(endpoint) nbOfNonTerminatedServers = 0 for s in response if s['status'] != 'terminated' nbOfNonTerminatedServers += 1 end end if (nbOfNonTerminatedServers == 0) then return end puts "Still %d servers." % [nbOfNonTerminatedServers] sleep config[:scalr_server_status_polling_period] elapsed_time += config[:scalr_server_status_polling_period] puts "Elapsed time: %d seconds. Still polling for number of servers in farm" % [elapsed_time] end raise "Timeout! And some servers are still running...Try later" end
wait_for_status(scalr_api,state, status)
click to toggle source
# File lib/kitchen/driver/scalr.rb, line 216 def wait_for_status(scalr_api,state, status) elapsed_time = 0 puts 'Waiting for server to be %s.' % [status] while elapsed_time < config[:scalr_server_status_polling_timeout] do response = scalr_api.list('/api/v1beta0/user/%s/farms/%d/servers/' % [config[:scalr_env_id], state[:farmId]] ) if (response.size > 0 && response[0]['status'] == status) then puts 'Server is %s!' % [response[0]['status']] return end if (response.size > 0) then puts 'Server is still %s.' % [response[0]['scalrAgent']['reachabilityStatus']['status']] end sleep config[:scalr_server_status_polling_period] elapsed_time += config[:scalr_server_status_polling_period] puts "Elapsed time: %d seconds. Still polling for server status" % [elapsed_time] end raise "Server status timeout!" end