/analyzer/automation/Studio_Fx_On_Rails_5.0/lib/mu_api.rb
Ruby | 329 lines | 273 code | 24 blank | 32 comment | 11 complexity | 87ce5bb61c0d6e5842731d4fc96690c2 MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0
- require 'rubygems'
- require 'net/https'
- require 'libxml'
- require 'uri'
- $api_version = '1.0'
- # Class for Mu Api commands. UUID and JobId for most calls are remembered
- # but can be overridden when needed.
- class Mu_Api
- include LibXML
-
- attr_accessor :host, :docroot, :posted_uuid, :run_uuid, :job_id, :username, :password, :params, :expected_error
- def initialize(host=ENV['MU_IP'], docroot="/api/v3" )
- @host = host
- @username = (ENV['MU_ADMIN_USER'].nil?) ? "admin" : ENV['MU_ADMIN_USER']
- @password = (ENV['MU_ADMIN_PASS'].nil?) ? "admin" : ENV['MU_ADMIN_PASS']
- @docroot = docroot
- @params = nil
- @expected_error = nil
- $DEBUG and puts "Created API object to :#{@host}"
- end
- # send request to api
- def request(doc,verbose=false)
- uri = URI.parse("https://#{@host}/")
- resp = response = "";
- http = Net::HTTP.new(uri.host, uri.port)
- http.use_ssl = true
- escaped = URI.escape(doc)
- $DEBUG and puts "DOC: #{@docroot}/#{escaped}"
- http.start do |http|
- req = Net::HTTP::Get.new("#{@docroot}/#{escaped}", {"User-Agent" => @username})
- req.basic_auth(@username, @password)
- response = http.request(req)
- resp = response.body
- end
- begin
- if (/<.+>/).match(resp)
- xmldoc = XML::Document.string(resp)
- else
- xmldoc = XML::Document.new
- xmldoc.root = XML::Node.new('err_node', resp)
- end
-
- # a test case may set the expected_error string if it expects
- # there to be an error in the http request.
- # if there was an expected error, and we find it in the response,
- # then set it to the 'found' string (which the test case will check for)
- @expected_error = "found expected error" if xmldoc.to_s.include?(@expected_error) unless @expected_error.nil?
-
- rescue SocketError
- raise "Host " + @host + " nicht erreichbar"
- rescue Exception => e
- print "Error parsing XML " + e.to_s
- ensure
- return xmldoc
- end
- end
- # Post the analysis/template object to the muserver.
- def post(doc)
- xmldoc = nil
- uri = URI.parse("https://#{@host}/")
- resp = response = "";
- http = Net::HTTP.new(uri.host, uri.port)
- http.use_ssl = true
- begin
- http.start do |http|
- req = Net::HTTP::Post.new("#{@docroot}/templates/import", {"User-Agent" => @username})
- req.basic_auth(@username, @password)
- req.body = doc.to_s
- response = http.request(req)
- resp = response.body
- end
- # XML Document
- if (/<.+>/).match(resp)
- xmldoc = XML::Document.string(resp)
- else
- xmldoc = XML::Document.new
- xmldoc.root = XML::Node.new('err_node', resp)
- end
- rescue SocketError
- raise "Host " + host + " nicht erreichbar"
- rescue Exception => e
- $DEBUG and puts "error parsing XML " + e.to_s
- end
- $DEBUG and puts resp
- if (xmldoc.nil? || xmldoc.find("//err_node"))
- $DEBUG and puts xmldoc
- @posted_uuid = nil
- end
- @posted_uuid = xmldoc.find_first("//uuid").content if xmldoc.find_first("//uuid")
- return xmldoc
- end
- # used by archive(get) to access report.zip, returns the size of the zipfile
- def download(doc, filename="tmp.zip")
- escaped = URI.escape(doc)
- resp = href = "";
- http = Net::HTTP.new(@host, 443)
- http.use_ssl = true
- $DEBUG and puts "DOC: #{@docroot}/#{escaped}"
- http.start do |http|
- req = Net::HTTP::Get.new("#{@docroot}/#{escaped}", {"User-Agent" => @username})
- req.basic_auth(@username, @password)
- resp = http.request(req)
- if resp.body.include?("Could not download archive")
- puts "==> Could not download archive"
- return -1
- end
- open(filename, "wb") { |f|
- f.write(resp.body)
- }
- return File.size(filename)
- end
- end
- # For any of the possible status values, returns a list of analysis
- def list_by_status(status)
- uuid_list = Array.new()
- doc = request("analysis/list?status=#{status}")
- unless doc.find_first("//analysis").nil?
- doc.find('//analysis').each { |e| uuid_list << e['uuid'] }
- end
- return uuid_list
- end
- # Get the status of a particular analysis, reference is the uuid
- def status(uuid=@run_uuid)
- doc = request("analysis/status?uuid=#{uuid}")
- unless doc.find_first("//analysis").nil?
- status = doc.find_first("//status").content
- return status
- end
- return doc
- end
- # Run an analysis, reference is the posted uuid. A name parameter can
- # be included so that each successive run of the same uuid yields a
- # new name
- # ex: run(1234-1234-1234-1234, "new_name")
- def run(uuid=@posted_uuid, rename="")
- req = "analysis/run?uuid=#{uuid}"
- unless rename.empty?
- req = "#{req}&rename=#{rename}"
- end
- doc = request(req)
- unless doc.find_first("//analysis").nil?
- @run_uuid = doc.find_first("//analysis").attributes['uuid']
- return @run_uuid
- end
- return doc
- end
- # abort a running analysis. Next queued analysis will start
- def stop(uuid=@run_uuid)
- doc = request("analysis/stop?uuid=#{uuid}")
- unless doc.find_first("//analysis").nil?
- status = doc.find_first("//analysis").attributes['status']
- return status
- end
- return false
- end
- # pause a running analysis. Note that any queued analysis will NOT begin
- def pause(uuid=@run_uuid)
- doc = request("analysis/pause?uuid=#{uuid}")
- unless doc.find_first("//analysis").nil?
- status = doc.find_first("//analysis").attributes['status']
- return status
- end
- return false
- end
- # anti-pause
- def resume(uuid=@run_uuid)
- doc = request("analysis/resume?uuid=#{uuid}")
- unless doc.find_first("//analysis").nil?
- status = doc.find_first("//analysis").attributes['status']
- return status
- end
- return false
- end
- # delete analysis or template of any type
- def delete(uuid=@run_uuid)
- doc = request("analysis/delete?uuid=#{uuid}")
- unless doc.find_first("//analysis").nil?
- status = doc.find_first("//analysis").attributes['status']
- return status
- end
- return true
- end
- # return a list of faults (if any) for the analysis
- def get_faults(uuid=@run_uuid)
- doc = request("templates/export?uuid=#{uuid}")
- unless doc.find_first("//analysis").nil?
- faults = request("analysis/getFaultList?uuid=#{uuid}",true)
- return faults
- end
- return "error: no analysis with uuid: #{uuid} found"
- end
- # return the name of an analysis referenced by uuid
- def get_name(uuid=@run_uuid)
- doc = request("templates/export?uuid=#{uuid}")
- unless doc.find_first("//analysis").nil?
- return doc.find_first("//analysis").attributes['name']
- end
- return
- end
- # list all templates of type
- def list(type="analysis", templates_only='')
- case templates_only
- when "true"
- template_param = "?templatesOnly=true"
- when "false"
- template_param = "?templatesOnly=false"
- else
- template_param = ""
- end
- doc = request("#{type}/list#{template_param}")
- return doc
- end
-
- # return a list of template names for a Type,
- # Type can be any of those returned by "request('tempates/types')"
- def list_names(type)
- names = Array.new
- doc = request("templates/list?type=#{type}")
- doc.find("//templates/*").each {|a| names << a['name'] }
- return names
- end
-
- def export_byname(name)
- return request("templates/export?name=#{name}")
- end
-
- # archive has a set of three commands that are used to
- # generate and download an archive of all data produced by
- # a particular analysis
- # ex:
- # * achive(run)
- # * archive(status)
- # * archive(get) if archive(status) == "Finished"
- def archive(command="run", id=@run_uuid)
- case command
- when 'run'
- request_string = "archive/run?uuid=#{id}"
- request_string += @params unless @params.nil?
- doc = request(request_string)
- unless doc.find_first("//job").nil?
- @job_id = doc.find_first("//job").attributes['id']
- return @job_id
- end
- return doc
- when 'status'
- id = @job_id if id == @run_uuid
- $DEBUG and puts id
- doc = request("archive/status?jobId=#{id}")
- unless doc.find_first("//status").nil?
- status = doc.find_first("//status").content
- return status
- end
- return doc
- when 'get'
- id = @job_id if id == @run_uuid
- file_size = download("archive/get?jobId=#{id}","#{id}.zip")
- return file_size
- end
- return false
- end
- def backup(command="run")
- case command
- when 'run'
- doc = request("backup/run")
- unless doc.find_first("//job").nil?
- @job_id = doc.find_first("//job").attributes['id']
- return @job_id
- end
- return doc
- when 'status'
- id = @job_id
- $DEBUG and puts id
- doc = request("backup/status?jobId=#{id}")
- unless doc.find_first("//status").nil?
- status = doc.find_first("//status").content
- return status
- end
- return doc
- when 'get'
- id = @job_id
- file_size = download("backup/get?jobId=#{id}","#{id}.dat")
- return file_size
- end
- return false
- end
- def capture(command='run',port='a1')
- case command
- when 'run'
- doc = request("capture/run?port=#{port}")
- unless doc.find_first("//job").nil?
- @job_id = doc.find_first("//job").attributes['id']
- return @job_id
- end
- return doc
- when 'status'
- id = @job_id
- $DEBUG and puts id
- doc = request("capture/status?jobId=#{id}")
- unless doc.find_first("//status").nil?
- status = doc.find_first("//status").content
- return status
- end
- return doc
- when 'get'
- id = @job_id
- file_size = download("capture/get?jobId=#{id}","#{id}.pcap")
- return file_size
- end
- return false
- end
- end