Skip to content

Instantly share code, notes, and snippets.

@penguin2716
Last active January 6, 2016 11:44
Show Gist options
  • Save penguin2716/cdfbfb5503d2b9be9342 to your computer and use it in GitHub Desktop.
Save penguin2716/cdfbfb5503d2b9be9342 to your computer and use it in GitHub Desktop.
ConoHaのAPIを簡単に叩くためのスクリプト.環境変数に必要な認証情報をセットして使ってね.
#!/usr/bin/env ruby
#-*- coding: utf-8 -*-
require 'net/http'
require 'uri'
require 'json'
require 'pp'
require 'optparse'
PRINT_CREDENTIALS = false
CONOHA_TENANT_ID = ENV["CONOHA_TENANT_ID"]
CONOHA_API_USER = ENV["CONOHA_API_USER"]
CONOHA_API_PASS = ENV["CONOHA_API_PASS"]
CONOHA_API_TOKEN = ENV["CONOHA_API_TOKEN"]
if [CONOHA_TENANT_ID, CONOHA_API_USER, CONOHA_API_PASS].include? nil
puts <<EOS
Please set following environment values first:
- CONOHA_TENANT_ID
- CONOHA_API_USER
- CONOHA_API_PASS
EOS
exit 1
end
if PRINT_CREDENTIALS
puts "CONOHA_TENANT_ID=#{CONOHA_TENANT_ID}"
puts "CONOHA_API_USER=#{CONOHA_API_USER}"
puts "CONOHA_API_PASS=#{CONOHA_API_PASS}"
puts "CONOHA_API_TOKEN=#{CONOHA_API_TOKEN}"
end
# Tokyo only
ACCOUNT_BASE_URI = "https://account.tyo1.conoha.io/v1/#{CONOHA_TENANT_ID}"
DNS_BASE_URI = "https://dns-service.tyo1.conoha.io/"
OBJECT_STORAGE_BASE_URI = "https://object-storage.tyo1.conoha.io/v1/nc_#{CONOHA_TENANT_ID}"
# Region wide
REGION = "tyo1"
COMPUTE_BASE_URI = "https://compute.#{REGION}.conoha.io/v2/#{CONOHA_TENANT_ID}"
VOLUME_BASE_URI = "https://block-storage.#{REGION}.conoha.io/v2/#{CONOHA_TENANT_ID}"
DATABASE_BASE_URI = "https://database-hosting.#{REGION}.conoha.io/v1"
IMAGE_BASE_URI = "https://image-service.#{REGION}.conoha.io/"
MAIL_BASE_URI = "https://mail-hosting.#{REGION}.conoha.io/v1"
IDENTITY_BASE_URI = "https://identity.#{REGION}.conoha.io/v2.0"
NETWORK_BASE_URI = "https://networking.#{REGION}.conoha.io/"
URI_BASE = {
:account => ACCOUNT_BASE_URI,
:dns => DNS_BASE_URI,
:object_storage => OBJECT_STORAGE_BASE_URI,
:compute => COMPUTE_BASE_URI,
:volume => VOLUME_BASE_URI,
:database => DATABASE_BASE_URI,
:image => IMAGE_BASE_URI,
:mail => MAIL_BASE_URI,
:identity => IDENTITY_BASE_URI,
:network => NETWORK_BASE_URI
}
$options = {}
$options[:headers] = []
$options[:method] = :get
$options[:output_priority] = "hbr"
$options[:field_separator] = "/"
$options[:output] = "-"
def call_rest(method, service, api_path, data = nil)
url = URI_BASE[service.to_sym]
until api_path.empty?
url = url + "/" + api_path.first.to_s
api_path.shift
end
response = nil
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
header = {}
header["Accept"] = "application/json"
header["Content-Type"] = "text/json"
header["X-Auth-Token"] = CONOHA_API_TOKEN if CONOHA_API_TOKEN
$options[:headers].each do |key, value|
header[key] = value
end
path = uri.path
path += "?#{uri.query}" if uri.query
if [:post, :put].include? method
res = http.method(method).call(path, data, header)
else
res = http.method(method).call(path, header)
end
return res
end
def request_token
credentials = { "auth" =>
{ "passwordCredentials" =>
{ "username" => CONOHA_API_USER,
"password" => CONOHA_API_PASS },
"tenantId" => CONOHA_TENANT_ID } }.to_json
res = call_rest(:post, "identity", ["tokens"], credentials)
return JSON.parse(res.body)["access"]["token"]["id"] if res
return nil
end
def filter(hash, query)
queries = query.sub(/^\//, "*/").gsub("//", "/*/").gsub("//", "/*/").split($options[:field_separator])
begin
queries.each do |key|
if key =~ /^\d+$/
hash = hash[key.to_i]
elsif key =~ /^select:[^=]+=.+$/
m = /^select:([^=]+)=(.+)$/.match(key)
hash.select!{|item| item[m.captures[0]].to_s == m.captures[1]}
elsif key =~ /^list:.+$/
m = /^list:(.+)$/.match(key)
hash.map!{|item| item[m.captures[0]]}
elsif key == "*"
if hash.instance_of? Array
hash = hash.first
elsif hash.instance_of? Hash
hash = hash[hash.keys.first]
end
else
hash = hash[key]
end
end
hash
rescue
puts "parse error"
exit 1
end
end
def print_help
puts <<EOS
Usage: #{$0} [-s] <service> <path> <options>
Options:
-m, --method={get,post,put,copy,delete}
use specified method. The default is "get".
-d, --data=text
set text data to post.
-T, --upload-file=filename
specify output filename to upload for put method.
-O, --output=filename
write response body to the specified filename. implies "-o b".
-s, --service=text
select a service from the followings.
valid services: account, dns, object_storage, compute, volume, database,
image, mail, identity, network.
Note: "-s" is omissible; "compute" is automatically replaced to "-s compute"
-o, --output-priority=text
set priority of output format.
h: hash
b: body
r: raw
default: "hbr"
-f, --filter=text
filter json output with specified filter string.
special options:
select:key=value
list:key
-F, --field-separator=text
set field separator for the filter option.
The default is "/".
-H, --header=key:value
append additional header.
-h, --help
print this message.
Examples:
#{$0} account billing-invoices
#{$0} compute servers
#{$0} compute servers/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/action -m post -d '{\"vncKeymap\": \"en-us\"}'
#{$0} compute flavors -f "flavors/list:name"
#{$0} compute flavors -f "flavors/select:name=g-2gb"
#{$0} compute flavors -f "flavors/select:name=g-2gb/0/id"
#{$0} object_storage -m post -H "X-Account-Meta-Quota-Giga-Bytes:100"
#{$0} object_storage -m put dir1
#{$0} object_storage -m put dir1/object1.img -T path/to/object1.img
#{$0} object_storage -m copy dir1/object1.img -H Destination:dir1/object2.img
#{$0} object_storage -m get dir1/object1.img -O save/to/object1.img
#{$0} object_storage -m delete dir1
For more information, please visit official API reference: https://www.conoha.jp/docs/index.html
EOS
end
if CONOHA_API_TOKEN.nil?
puts "Please set API token with following command:"
puts "$ export CONOHA_API_TOKEN=#{request_token}"
exit 1
end
if ARGV.empty?
print_help
exit 1
end
parser = OptionParser.new
parser.on('--header=VAL', '-H') { |h|
begin
m = /^([^:=]+)[:=](.+)$/.match(h)
$options[:headers] << [m.captures[0], m.captures[1]]
rescue
puts "invalid option (header)"
exit 1
end
}
parser.on('--data=VAL', '-d') { |d| $options[:data] = d }
parser.on('--method=VAL', '-m') { |m| $options[:method] = m.to_sym }
parser.on('--upload-file=VAL', '-T') { |f| $options[:upload_file] = f }
parser.on('--service=VAL', '-s') { |s| $options[:service] = s }
parser.on('--output-priority=VAL', '-o') { |priority|
$options[:output_priority] = priority
}
parser.on('--filter=VAL', '-f') { |filter| $options[:filter] = filter }
parser.on('--field-separator=VAL', '-F') { |fs| $options[:field_separator] = fs }
parser.on('--help', '-h') {
print_help
exit 0
}
parser.on('--output=VAL', '-O') { |output| $options[:output] = output }
parser.parse!(ARGV)
case ARGV.first
when "account", "dns", "object_storage", "compute", "volume", "database", "image", "mail", "identity", "network"
ARGV.insert(0, "-s")
end
parser.parse!(ARGV)
method = $options[:method]
response = nil
case method
when :get, :delete, :copy
response = call_rest(method, $options[:service], ARGV)
when :post, :put
response = nil
if $options[:upload_file]
binary = open($options[:upload_file], 'r').read
response = call_rest(method, $options[:service], ARGV, binary)
elsif $options[:data]
response = call_rest(method, $options[:service], ARGV, $options[:data])
else
response = call_rest(method, $options[:service], ARGV, nil)
end
else
print_help
end
$options[:output_priority].split("").each do |type|
begin
case type
when "h"
hash = JSON.parse(response.body)
if $options[:filter]
pp filter(hash, $options[:filter])
else
pp hash
end
when "b"
if response.body
next if response.body.empty?
if $options[:output] != "-"
file = open($options[:output], 'w')
file.write(response.body)
file.close
else
pp response.body
end
else
next
end
when "r"
pp response
end
break
rescue
next
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment