Class: Magellan::Cli::Http

Inherits:
Object
  • Object
show all
Includes:
FileAccess
Defined in:
lib/magellan/cli/http.rb

Defined Under Namespace

Classes: ColorDebugDev

Constant Summary collapse

DEFAULT_HTTP_PORT =
(ENV['DEFAULT_HTTP_PORT' ] ||  80).to_i
DEFAULT_HTTPS_PORT =
(ENV['DEFAULT_HTTPS_PORT'] || 443).to_i

Constants included from FileAccess

FileAccess::DEFAULT_SELECTION_FILENAME

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from FileAccess

ensure_config_dir, load_selection, load_selections, remove_selection_file, selection_filename, update_selections

Constructor Details

#initialize(cmd) ⇒ Http

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

Parameters:

  • base_url_or_host (String)

    接続先の基準となるURLあるいはホスト名

  • options (Hash)

    オプション



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/magellan/cli/http.rb', line 36

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

Instance Attribute Details

#auth_tokenObject (readonly)

Returns the value of attribute auth_token.



24
25
26
# File 'lib/magellan/cli/http.rb', line 24

def auth_token
  @auth_token
end

#base_urlObject (readonly)

Returns the value of attribute base_url.



22
23
24
# File 'lib/magellan/cli/http.rb', line 22

def base_url
  @base_url
end

#cmdObject (readonly)

Returns the value of attribute cmd.



20
21
22
# File 'lib/magellan/cli/http.rb', line 20

def cmd
  @cmd
end

#httpclientObject (readonly)

Returns the value of attribute httpclient.



21
22
23
# File 'lib/magellan/cli/http.rb', line 21

def httpclient
  @httpclient
end

#login_authObject (readonly)

Returns the value of attribute login_auth.



25
26
27
# File 'lib/magellan/cli/http.rb', line 25

def 
  @login_auth
end

Class Method Details

.base_urlObject



27
28
29
# File 'lib/magellan/cli/http.rb', line 27

def self.base_url
  @base_url ||= (ENV["MAGELLAN_SITE"] || "https://api-asia.magellanic-clouds.com")
end

Instance Method Details

#api_login!(email, password) ⇒ boolean

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

Returns:

  • (boolean)

    login成功/失敗



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/magellan/cli/http.rb', line 92

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(, params, JSON_HEADER) } }

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

  if logined
    body = JSON.parse res2.body
    (email, body["token"])
  else
    
  end
  logined
end

#api_login_by_token!(email, token) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/magellan/cli/http.rb', line 117

def (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
    (email, token)
  else
    
  end
  logined
end

#check_login_auth!Object



82
83
84
85
86
87
# File 'lib/magellan/cli/http.rb', line 82

def 
  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) ⇒ Object



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/magellan/cli/http.rb', line 186

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_lfObject



68
69
70
71
72
# File 'lib/magellan/cli/http.rb', line 68

def debug_lf
  r = yield if block_given?
  @httpclient.debug_dev << "\n" if @httpclient.debug_dev
  r
end

#delete(rel_path) ⇒ Object

ログインしてDELETEします

Parameters:

  • rel_path (String)

    cli.base_url からの相対パス

Returns:

  • nil



266
267
268
269
# File 'lib/magellan/cli/http.rb', line 266

def delete(rel_path)
  params = 
  process_res(:delete, rel_path, params.to_json, JSON_HEADER)
end

#get_auth_tokenObject



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/magellan/cli/http.rb', line 145

def get_auth_token
  res = Ssl.retry_on_ssl_error("login_form"){ debug_lf{ @httpclient.get() } }
  case res.status
  when 200
    doc = Nokogiri::HTML.parse(res.body, , 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 = {}) ⇒ Object

ログインしてGETします

Parameters:

  • rel_path (String)

    cli.base_url からの相対パス

  • params (Hash) (defaults to: {})

    クエリ文字列

Returns:

  • (Object)

    レスポンスのBODYをJSONとしてパースした結果オブジェクト



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/magellan/cli/http.rb', line 209

def get_json(rel_path, params = {})
  url = "#{base_url}#{rel_path}"
  params.update(yield) if block_given?
  params = .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

#inspectObject

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



173
174
175
176
177
# File 'lib/magellan/cli/http.rb', line 173

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_urlObject



75
76
77
# File 'lib/magellan/cli/http.rb', line 75

def 
  @login_form_url ||= base_url + "/users/sign_in.html"
end

#login_urlObject



78
79
80
# File 'lib/magellan/cli/http.rb', line 78

def 
  @login_url ||= base_url + "/api/sign_in.json"
end

#post(rel_path, params) ⇒ Object

ログインしてPOSTします

Parameters:

  • rel_path (String)

    cli.base_url からの相対パス

  • params (Hash)

    POSTで渡されるパラメータ

Returns:

  • nil



231
232
233
234
# File 'lib/magellan/cli/http.rb', line 231

def post(rel_path, params)
  params = .update(params || {})
  process_res(:post, rel_path, params)
end

#post_json(rel_path, params) ⇒ Object

ログインしてJSON形式のbodyをPOSTします

Parameters:

  • rel_path (String)

    cli.base_url からの相対パス

  • params (Hash)

    POSTで渡されるパラメータ

Returns:

  • nil



240
241
242
243
# File 'lib/magellan/cli/http.rb', line 240

def post_json(rel_path, params)
  params = .update(params || {})
  process_res(:post, rel_path, params.to_json, JSON_HEADER)
end

#process_res(http_method, rel_path, *args) ⇒ Object



271
272
273
274
275
# File 'lib/magellan/cli/http.rb', line 271

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) ⇒ Object

ログインしてPUTします

Parameters:

  • rel_path (String)

    cli.base_url からの相対パス

  • params (Hash)

    PUTで渡されるパラメータ

Returns:

  • nil



249
250
251
252
# File 'lib/magellan/cli/http.rb', line 249

def put(rel_path, params)
  params = .update(params || {})
  process_res(:put, rel_path, params)
end

#put_json(rel_path, params) ⇒ Object

ログインしてJSON形式のbodyをPUTします

Parameters:

  • rel_path (String)

    cli.base_url からの相対パス

  • params (Hash)

    PUTで渡されるパラメータ

Returns:

  • nil



258
259
260
261
# File 'lib/magellan/cli/http.rb', line 258

def put_json(rel_path, params)
  params = .update(params || {})
  process_res(:put, rel_path, params.to_json, JSON_HEADER)
end

#reset_login_info!Object



141
142
143
# File 'lib/magellan/cli/http.rb', line 141

def 
  update_selections("login" => nil)
end

#write_login_info!(email, token) ⇒ Object



137
138
139
# File 'lib/magellan/cli/http.rb', line 137

def (email, token)
  update_selections("login" => {"email" => email, "token" => token })
end