Created
December 7, 2015 16:26
-
-
Save m-shibata/a67eef729aba045bb6eb to your computer and use it in GitHub Desktop.
swift for swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env swift | |
import Glibc | |
let config = [ | |
"tenantName": "", | |
"tenantId": "", | |
"username": "", | |
"password": "", | |
"configfile": ".conoha", | |
] | |
enum ConoHaMethod { | |
case Put | |
case Get | |
case Unknown | |
} | |
let CURL_GET = "curl -s -X GET -H \"Accept: application/json\"" | |
let CURL_PUT = "curl -s -X PUT -H \"Accept: application/json\"" | |
let CURL_POST = "curl -s -X POST -H \"Accept: application/json\"" | |
let CURL_HEAD = "curl -s --head -H \"Accept: application/json\"" | |
let CONOHA_API_IDENTIFY = "https://identity.tyo1.conoha.io/v2.0/tokens" | |
let CONOHA_API_SWIFT = "https://object-storage.tyo1.conoha.io/v1" | |
func usage() { | |
print("Usage: conoha put | get container file") | |
} | |
func execToString(command: String) -> String { | |
let fp = popen(command, "r") | |
if fp == nil { | |
return "" | |
} | |
var data = String() | |
let buffer = [CChar](count: 1024, repeatedValue: 0) | |
while fgets(UnsafeMutablePointer(buffer), Int32(buffer.count), fp) != nil { | |
if let read = String.fromCString(buffer) { | |
data += read | |
} | |
} | |
if pclose(fp) != 0 { | |
return "" | |
} | |
return data | |
} | |
func isExpired(expire: String) -> Bool { | |
var expireTm = tm() | |
var buffer: [Character] = [] | |
// parse YYYY-mm-ddTHH:MM:SSZ | |
for i in 0...3 { buffer.append(expire[expire.startIndex.advancedBy(i)]) } | |
expireTm.tm_year = Int32(String(buffer))! - 1900 | |
buffer = [] | |
for i in 5...6 { buffer.append(expire[expire.startIndex.advancedBy(i)]) } | |
expireTm.tm_mon = Int32(String(buffer))! - 1 | |
buffer = [] | |
for i in 8...9 { buffer.append(expire[expire.startIndex.advancedBy(i)]) } | |
expireTm.tm_mday = Int32(String(buffer))! | |
buffer = [] | |
for i in 11...12 { buffer.append(expire[expire.startIndex.advancedBy(i)]) } | |
expireTm.tm_hour = Int32(String(buffer))! | |
buffer = [] | |
for i in 14...15 { buffer.append(expire[expire.startIndex.advancedBy(i)]) } | |
expireTm.tm_min = Int32(String(buffer))! | |
buffer = [] | |
for i in 17...18 { buffer.append(expire[expire.startIndex.advancedBy(i)]) } | |
expireTm.tm_sec = Int32(String(buffer))! | |
buffer = [] | |
let expireTime = mktime(&expireTm) | |
// get current time | |
var currentTime = time(nil) | |
currentTime += 60 | |
return currentTime > expireTime | |
} | |
func getToken() -> String { | |
// set config file name | |
let pwent = getpwuid(getuid()) | |
let homeDir = String.fromCString(pwent.memory.pw_dir) | |
if homeDir == nil { | |
print("Error: failed to get home directory") | |
exit(1) | |
} | |
let configFile = homeDir! + "/" + config["configfile"]! | |
// check old token | |
var token = ["", ""] | |
if access(configFile, R_OK) == 0 { | |
var data = String() | |
let buffer = [CChar](count: 1024, repeatedValue: 0) | |
let fp = fopen(configFile, "r") | |
while fgets(UnsafeMutablePointer(buffer), Int32(buffer.count), fp) != nil { | |
if let read = String.fromCString(buffer) { | |
data += read | |
} | |
} | |
fclose(fp) | |
token = data.characters.split("\n").map { String($0) } | |
if token.count == 2 { | |
// check expires | |
if !isExpired(token[1]) { | |
return token[0] | |
} else { | |
print("Token is expired, retrieve new token") | |
} | |
} | |
} | |
// get new token | |
var json_auth = "'{ \"auth\": { \"tenantName\": \"\(config["tenantName"]!)\", " | |
json_auth += "\"passwordCredentials\": { \"username\": \"\(config["username"]!)\", " | |
json_auth += "\"password\": \"\(config["password"]!)\" } } }'" | |
var cmd = "\(CURL_POST) -d \(json_auth) \(CONOHA_API_IDENTIFY) | " | |
cmd += "jq -r \".access.token.id, .access.token.expires\"" | |
token = execToString(cmd).characters.split("\n").map { String($0) } | |
if token.count != 2 { | |
print("Error: failed to get tokenId/expires") | |
exit(1) | |
} | |
// save new token | |
cmd = "echo -n \"\(token[0])\\n\(token[1])\" > \(configFile)" | |
execToString(cmd) | |
return token[0] | |
} | |
func createContainer(token: String, container: String) -> Bool { | |
let api = CONOHA_API_SWIFT + "/nc_" + config["tenantId"]! | |
// container already exists? | |
var cmd_check = "\(CURL_HEAD) -H \"X-Auth-Token: \(token)\" " | |
cmd_check += "\(api)/\(container) | " | |
cmd_check += "head -1 | grep \" 20[0-9] \"" | |
if execToString(cmd_check) != "" { | |
return true | |
} | |
// create container | |
var cmd_create = "\(CURL_PUT) -H \"X-Auth-Token: \(token)\" " | |
cmd_create += "\(api)/\(container)" | |
if execToString(cmd_create) != "" { | |
print("Error: failed to create \"\(container)\" container") | |
return false | |
} | |
// recheck container exists | |
if execToString(cmd_check) != "" { | |
return true | |
} | |
print("Error: \"\(container)\" container not found") | |
return false | |
} | |
func upload(token: String, container: String, file: String) -> Bool { | |
let api = CONOHA_API_SWIFT + "/nc_" + config["tenantId"]! | |
// upload_file | |
var cmd = "\(CURL_PUT) -H \"X-Auth-Token: \(token)\" " | |
cmd += "\(api)/\(container)/\(file) -T \(file)" | |
if execToString(cmd) != "" { | |
print("Error: failed to upload \"\(container)/\(file)\"") | |
return false | |
} | |
return true | |
} | |
func download(token: String, container: String, file: String) -> Bool { | |
let api = CONOHA_API_SWIFT + "/nc_" + config["tenantId"]! | |
// file exits? | |
var cmd_check = "\(CURL_HEAD) -H \"X-Auth-Token: \(token)\" " | |
cmd_check += "\(api)/\(container)/\(file) | " | |
cmd_check += "head -1 | grep \" 20[0-9] \"" | |
if execToString(cmd_check) == "" { | |
print("\"\(container)/\(file)\" is not found") | |
return false | |
} | |
// download_file | |
var cmd = "\(CURL_GET) -H \"X-Auth-Token: \(token)\" " | |
cmd += "\(api)/\(container)/\(file) -O \(file)" | |
if execToString(cmd) != "" { | |
print("Error: failed to download \"\(container)/\(file)\"") | |
return false | |
} | |
return true | |
} | |
// main routine | |
if Process.argc != 4 { | |
usage() | |
exit(1) | |
} | |
var method = ConoHaMethod.Unknown | |
var container = String() | |
var file = String() | |
switch Process.arguments[1] { | |
case "put": | |
method = ConoHaMethod.Put | |
container = Process.arguments[2] | |
file = Process.arguments[3] | |
if access(file, R_OK) != 0 { | |
print("\(file) not found") | |
exit(1) | |
} | |
break | |
case "get": | |
method = ConoHaMethod.Get | |
container = Process.arguments[2] | |
file = Process.arguments[3] | |
if access(file, R_OK) == 0 { | |
print("Warning: \(file) will be overwritten") | |
} | |
break | |
default: | |
method = ConoHaMethod.Unknown | |
} | |
if method == ConoHaMethod.Unknown { | |
print("Error: unknown method: \(Process.arguments[1])") | |
usage() | |
exit(1) | |
} | |
if execToString("which jq") == "" { | |
print("Error: not found jq command") | |
} | |
let token = getToken() | |
if !createContainer(token, container: container) { | |
exit(1) | |
} | |
switch (method) { | |
case ConoHaMethod.Get: | |
if !download(token, container: container, file: file) { | |
exit(1) | |
} | |
break | |
case ConoHaMethod.Put: | |
if !upload(token, container: container, file: file) { | |
exit(1) | |
} | |
break | |
case ConoHaMethod.Unknown: | |
assert(false, "unexpected method value") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment