class Magellan::Cli::Http

Constants

DEFAULT_HTTPS_PORT
DEFAULT_HTTP_PORT

Attributes

auth_token[R]
base_url[R]
cmd[R]
httpclient[R]
login_auth[R]

Public Class Methods

base_url() click to toggle source
# File lib/magellan/cli/http.rb, line 26
def self.base_url
  @base_url ||= (ENV["MAGELLAN_SITE"] || "https://api-asia.magellanic-clouds.com")
end
new(cmd) click to toggle source

Magellan::Cli::Httpのコンストラクタです。

@param [String] base_url_or_host 接続先の基準となるURLあるいはホスト名 @param [Hash] options オプション @option options [String] :api_version APIのバージョン。デフォルトは “1.0.0”

# File lib/magellan/cli/http.rb, line 35
def initialize(cmd)
  @cmd = cmd
  base_url_or_host = self.class.base_url
  if base_url_or_host =~ URI.regexp
    @base_url = base_url_or_host.sub(/\/\Z/, '')
    uri = URI.parse(@base_url)
  else
    if config_path = search_file(".magellan-cli.yml")
      config = YAML.load_file_with_erb(config_path)
      options = config[base_url_or_host.to_s].deep_symbolize_keys
    else
      options = {}
    end
    uri = URI::Generic.build({scheme: "http", host: base_url_or_host, port: DEFAULT_HTTP_PORT}.update(options))
    @base_url = uri.to_s
  end

  @httpclient = HTTPClient.new
  @httpclient.debug_dev = ColorDebugDev.new($stderr) if cmd.verbose?
  @httpclient.ssl_config.verify_mode = nil # 自己署名の証明書をOKにする
  @login_auth = load_selections["login"]
end

Public Instance Methods

api_login!(email, password) click to toggle source

magellan-apiサーバに接続してログインの検証とアクセストークンの保存を行います。

@return [boolean] login成功/失敗

# File lib/magellan/cli/http.rb, line 91
def api_login!(email, password)
  @auth_token ||= get_auth_token
  params = {
    "user" => {
      "email" => email,
      "password" => password
    },
    "authenticity_token" => @auth_token
  }.to_json
  res2 = Ssl.retry_on_ssl_error("login"){ debug_lf{ @httpclient.post(login_url, params, JSON_HEADER) } }

  case res2.status
  when 200...300 then logined = true
  else logined = false
  end

  if logined
    body = JSON.parse res2.body
    write_login_info!(email, body["token"])
  else
    reset_login_info!
  end
  logined
end
api_login_by_token!(email, token) click to toggle source
# File lib/magellan/cli/http.rb, line 116
def api_login_by_token!(email, token)
  url = "#{base_url}/admin/magellan~auth~organization.json"
  params = {"email" => email, "token" => token}
  res = debug_lf{ httpclient.get(url, params) }

  logined =
    case res.status
    when 200...400 then true
    else false
    end

  if logined
    write_login_info!(email, token)
  else
    reset_login_info!
  end
  logined
end
check_login_auth!() click to toggle source
# File lib/magellan/cli/http.rb, line 81
def check_login_auth!
  auth = login_auth
  if auth.nil? || auth.empty?
    raise Magellan::Cli::Error, I18n.t(:not_logged_in, scope: [:login, :check_login_auth], command: File.basename($0))
  end
end
check_response(res) click to toggle source
# File lib/magellan/cli/http.rb, line 185
def check_response(res)
  case res.status
  when 200...400 then
    begin
      r = JSON.parse(res.body)
    rescue
      # DELETE で 302 Found を返す時に HTML がレンダリングされることがあるので
      # status code 300 台では JSON パースエラーを無視する
      if res.status >= 300
        return nil
      end
      raise
    end
    r
  else
    cmd.process_error_response(res)
  end
end
debug_lf() { || ... } click to toggle source
# File lib/magellan/cli/http.rb, line 67
def debug_lf
  r = yield if block_given?
  @httpclient.debug_dev << "\n" if @httpclient.debug_dev
  r
end
delete(rel_path) click to toggle source

ログインしてDELETEします @param [String] rel_path cli.base_url からの相対パス @return nil

# File lib/magellan/cli/http.rb, line 265
def delete(rel_path)
  params = login_auth
  process_res(:delete, rel_path, params.to_json, JSON_HEADER)
end
get_auth_token() click to toggle source
# File lib/magellan/cli/http.rb, line 144
def get_auth_token
  res = Ssl.retry_on_ssl_error("login_form"){ debug_lf{ @httpclient.get(login_form_url) } }
  case res.status
  when 200
    doc = Nokogiri::HTML.parse(res.body, login_form_url, res.body_encoding.to_s)
    node = doc.xpath('//input[@name="authenticity_token"]').first
    unless node
      raise Cli::Error.new("fail to login Magellan")
    end
    node.attribute('value').value
  when 503
    begin
      obj = JSON.parse(res.body)
      if obj and obj["message"]
        err_message = obj["message"]
      else
        err_message = "Under Maintenance"
      end
    rescue
      err_message = "Under Maintenance"
    end
    raise Cli::Error.new("Under Maintenance")
  else
    raise Cli::Error.new("fail to login Magellan")
  end
end
get_json(rel_path, params = {}) { || ... } click to toggle source

ログインしてGETします @param [String] rel_path cli.base_url からの相対パス @param [Hash] params クエリ文字列 @return [Object] レスポンスのBODYをJSONとしてパースした結果オブジェクト

# File lib/magellan/cli/http.rb, line 208
def get_json(rel_path, params = {})
  url = "#{base_url}#{rel_path}"
  params.update(yield) if block_given?
  params = login_auth.merge(params)
  if params && !params.empty?
    url << '?' << params.map{|k,v| "%s=%s" % [CGI.escape(k.to_s), CGI.escape(v.to_s)] }.join("&")
  end
  # "Unknown key: max-age = 0" というメッセージを表示させないために$stderrを一時的に上書き
  $stderr, bak = StringIO.new, $stderr
  res = nil
  begin
    res = debug_lf{ httpclient.get(url) }
  ensure
    $stderr = bak
  end
  check_response(res)
end
inspect() click to toggle source

@httpclient.inspectの戻り値の文字列が巨大なので、inspectで出力しないようにします。

# File lib/magellan/cli/http.rb, line 172
def inspect
  r = "#<#{self.class.name}:#{self.object_id} "
  fields = (instance_variables - [:@httpclient]).map{|f| "#{f}=#{instance_variable_get(f).inspect}"}
  r << fields.join(", ") << ">"
end
login_form_url() click to toggle source
# File lib/magellan/cli/http.rb, line 74
def login_form_url
  @login_form_url ||= base_url + "/users/sign_in.html"
end
login_url() click to toggle source
# File lib/magellan/cli/http.rb, line 77
def login_url
  @login_url ||= base_url + "/api/sign_in.json"
end
post(rel_path, params) click to toggle source

ログインしてPOSTします @param [String] rel_path cli.base_url からの相対パス @param [Hash] params POSTで渡されるパラメータ @return nil

# File lib/magellan/cli/http.rb, line 230
def post(rel_path, params)
  params = login_auth.update(params || {})
  process_res(:post, rel_path, params)
end
post_json(rel_path, params) click to toggle source

ログインしてJSON形式のbodyをPOSTします @param [String] rel_path cli.base_url からの相対パス @param [Hash] params POSTで渡されるパラメータ @return nil

# File lib/magellan/cli/http.rb, line 239
def post_json(rel_path, params)
  params = login_auth.update(params || {})
  process_res(:post, rel_path, params.to_json, JSON_HEADER)
end
process_res(http_method, rel_path, *args) click to toggle source
# File lib/magellan/cli/http.rb, line 270
def process_res(http_method, rel_path, *args)
  url = "#{base_url}#{rel_path}"
  res = debug_lf{ httpclient.send(http_method, url, *args) }
  check_response(res)
end
put(rel_path, params) click to toggle source

ログインしてPUTします @param [String] rel_path cli.base_url からの相対パス @param [Hash] params PUTで渡されるパラメータ @return nil

# File lib/magellan/cli/http.rb, line 248
def put(rel_path, params)
  params = login_auth.update(params || {})
  process_res(:put, rel_path, params)
end
put_json(rel_path, params) click to toggle source

ログインしてJSON形式のbodyをPUTします @param [String] rel_path cli.base_url からの相対パス @param [Hash] params PUTで渡されるパラメータ @return nil

# File lib/magellan/cli/http.rb, line 257
def put_json(rel_path, params)
  params = login_auth.update(params || {})
  process_res(:put, rel_path, params.to_json, JSON_HEADER)
end
reset_login_info!() click to toggle source
# File lib/magellan/cli/http.rb, line 140
def reset_login_info!
  update_selections("login" => nil)
end
write_login_info!(email, token) click to toggle source
# File lib/magellan/cli/http.rb, line 136
def write_login_info!(email, token)
  update_selections("login" => {"email" => email, "token" => token })
end

Private Instance Methods

search_file(basename) click to toggle source
# File lib/magellan/cli/http.rb, line 178
def search_file(basename)
  dirs = [".", "./config", ENV['HOME']].join(",")
  Dir["{#{dirs}}/#{basename}"].select{|path| File.readable?(path)}.first
end