require "cloud_job_aws/version" require "cloud_job_base" require "aws-sdk" require "net/ssh" require "logger" module CloudJobAws class AwsConnector < CloudJobBase::CloudConnector attr_reader :ec2client, :ec2resource, :security_group, :key_pair def set_log_level(log_level) Aws.config.update({log_level: log_level}) end def set_region(region) @region = region end def check_credentials raise "Key not set." if ENV['AWS_ACCESS_KEY_ID'].nil? @key = ENV['AWS_ACCESS_KEY_ID'] raise "Secret not set." if ENV['AWS_SECRET_ACCESS_KEY'].nil? @secret = ENV['AWS_SECRET_ACCESS_KEY'] end def create_client # credentials aren't mandatory if they are set in ENV, though having it here for extendability @ec2client = Aws::EC2::Client.new(region: @region, credentials: Aws::Credentials.new(@key, @secret)) @ec2resource = Aws::EC2::Resource.new(client: @ec2client) create_security_group create_key_pair end def create_security_group begin @security_group = @ec2resource.create_security_group({ group_name: "SSH #{SecureRandom.uuid}", description: "ssh" }) puts @security_group.inspect # allow port for ssh @security_group.authorize_ingress({ip_permissions: [{ ip_protocol: 'tcp', from_port: 22, to_port: 22, ip_ranges: [{ cidr_ip: '0.0.0.0/0'}] }] }) rescue => ex puts ex.message end end def create_key_pair @key_pair = @ec2resource.create_key_pair({ key_name: "key-pair #{SecureRandom.uuid}"}) puts @key_pair.inspect end end class AwsVmHandler < CloudJobBase::VmHandler def provision begin allowed_types = ["t2.micro", "t1.micro"] raise ArgumentError, "AWS VM type not supported." if !(allowed_types.include?(@vm.series)) # free tier AMI for Ireland Microsoft Windows Server 2008 R2 Base - ami-a7ed50de # free tier AMI for Amazon Linux AMI 2017.09.1 (HVM), SSD Volume Type - ami-1a962263 @vm.image == "" ? image = "ami-1a962263" : image = @vm.image instance = @cloudConnector.ec2resource.create_instances({ instance_type: @vm.series, image_id: image, min_count: 1, max_count: 1, key_name: @cloudConnector.key_pair.key_name, security_group_ids: [@cloudConnector.security_group.id]}) @cloudConnector.ec2client.wait_until(:instance_status_ok, {instance_ids: [instance[0].id]}) @vm.instance_id = instance[0].id # set the observable's field @status = :ok rescue => ex # aws exceptions are subclasses of StandardError, thus must be caught by this rescue puts "provision request failed" # observer's fields: @exception = ex @status = :failed end end def deploy_exe(exe_bucket_key) puts "In aws deploy_exe" begin instance = @cloudConnector.ec2resource.instance(@vm.instance_id) if (instance.exists?) # start VM if it's not in pending/started state puts instance.state.code case instance.state.code when 0 # pending instance.wait_until_started when 16 # started - do nothing puts "VM already started." else puts "start request sent" instance.start instance.wait_until_started end # deploy exe @copied_exe_name = :copied_exe_name Net::SSH.start(instance.public_dns_name, "ec2-user", key_data: [ @cloudConnector.key_pair.key_material ], verbose: :info) do |ssh| result = ssh.exec!("wget #{exe_bucket_key}") puts result result = ssh.exec!("wget https:#{exe_bucket_key}") puts result result = ssh.exec!("wget -O #{@copied_exe_name} http:#{exe_bucket_key}") puts result result = ssh.exec!("ls -l") puts result end @status = :ok else raise "VM doesn't exist." end rescue => ex puts "run exe request failed" @exception = ex @status = :failed end end def run_exe(exe_bucket_key) puts "In aws run_exe" begin instance = @cloudConnector.ec2resource.instance(@vm.instance_id) if (instance.exists?) # run exe Net::SSH.start(instance.public_dns_name, "ec2-user", key_data: [ @cloudConnector.key_pair.key_material ], verbose: :info) do |ssh| result = ssh.exec!("#{@copied_exe_name}") puts result end @status = :ok else raise "VM doesn't exist." end rescue => ex puts "run exe request failed" @exception = ex @status = :failed end end def delete begin instance = @cloudConnector.ec2resource.instance(@vm.instance_id) if (instance.exists? and instance.state.code != 48) puts "terminate request sent" instance.terminate instance.wait_until_terminated @status = :ok end rescue => ex puts "terminate request failed" @exception = ex @status = :failed end end end end