cloudstack
CloudStack 4.5,用于管理XenServer。CloudStack和OpenStack类似,是一个开源的云计算资源管理平台,整体结构大致如下图:
Region翻译过来就是区域,是CloudStack中最大的组织单元,一般由多个物理上分离的数据中心组成,每个数据中心又对应一个Zone,叫资源域,当然一个数据中心也可以有多个资源域(Zone),这并不是严格要求的。一般来说,不同Zone之间物理上隔离,可用于冗余灾备。Zone又由Pod(提供点)组成,一个Pod一般对应一个机柜,每个Pod中可以有多个集群,集群中就是物理主机了。一般来说,每个集群有自己的主存储,一个Zone共用一个二级存储。主存储主要用于存放正在运行的虚拟机的磁盘文件,二级存储主要用来存放虚拟机模板、iso文件和虚拟机的快照。
CloudStack根据不同的帐户等级对于API的访问权限有不同的限制.账户分为管理员,域管理员,用户等. 管理员是所有的API都可以调用,用户API则受限,是管理员API的一个子集。在安装好CloudStack管理服务器节点后,也可以在如下配置文件找到系统支持的所有API及对应权限:/etc/cloud/management/*commands*.properties
CloudStack自身的API定义都可以在commands.properties和commands-ext.properties里找到, 有一些第三方硬件支持添加的API可以在自己单独的文件里找到,比如nicira-nvp_commands.properties,f5bigip_commands.properties,junipersrx_commands.properties等.
在*commands*.properties文件中,定义的所有命令或者称所有的API,都是相同的格式:
Command=<class>:<level>,比如列出CloudStack所有账号信息:
listAccounts=com.cloud.api.commands.ListAccountsCmd;15
Command是Http请求时的命令参数, Class是处理当前请求命令的类, 数字15表示当前API支持的运行级别或者称权限. CloudStack里API有四个权限级别: ADMIN:1, RESOURCE_DOMAIN_ADMIN:2, DOMAIN_ADMIN:4, USER:8. 它们之前做与操作得出此命令可供哪些权限的账户操作. 15(1 & 2 & 4 & 8)表示四种账户权限都可以访问此API.
http://120.219.105.5:8080/client/api?command=listVirtualMachines&response=json
以CloudStack管理员的身份(admin)为例, 可以先在CloudStack UI上生成用户的apikey和secretkey, 只有管理员权限可以生成这两个key.上述请求的apikey直接填生成的即可, signature是通过请求的命令及参数 + Secretkey 再通过HmacSHA1哈希算法共同生成的,
在CloudStack中可以参考测试类:test/src/com/cloud/test/utils/UtilsForTest.java
里的实现, 或直接用其产生signature, 这个测试类要生成上述API调用的signature, 输入参数为(apikey, secretkey省略):-u "command=listUsers" -a "apikey" -s "secretkey"<br><br>
Programmer Guide
http://docs.cloudstack.apache.org/en/master/dev.html
Base URL+API Path+Command String+Signature
1、对所有的值进行url编码:URL encode each value “%20” rather than “+”.
2、将Command String 都改成小写并按照域的字母排序:Lower case the entire Command String and sort it alphabetically via the field for each field-value pair
'apikey=plgwjfzk4gys3momtvmjuvg-x-jlwlnfauj9gabbbf9edm-kaymmailqzzq1elzlyq_u38zcm0bewzgudp66mg&command=listusers&response=json'
3、使用 user‘s Secret key 将Command String 进行 HMAC SHA-1 ,得到的结果(UTF-8编码)再进行Base64 encode
Base URL:http://localhost:8080
API Path:/client/api?
Command String:command=deployVirtualMachine&serviceOfferingId=1&diskOfferingId=1&templateId=2&zoneId=4&apiKey=miVr6X7u6bN_sdahOBpjNejPgEsT35eXq-jB8CG20YI3yaxXcgpyuaIRmFI_EJTVwZ0nUkkJbPmY3y2bciKwFQ
Signature:&signature=Lxx1DM40AjcXU%2FcaiK8RAP0O1hU%3D
防攻击:&signatureVersion=3&expires=2011-10-10T12:00:00+0530
The timestamp is expressed in the YYYY-MM-DDThh:mm:ssZ format, as specified in the ISO 8601 standard
sign生成实现
package main
import (
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"fmt"
"net/url"
"strings"
)
const API_KEY = "plgWJfZK4gyS3mOMTVmjUVg-X-jlWlnfaUJ9GAbBbf9EdM-kAYMmAiLqzzq1ElZLYq_u38zCm0bewzGUdP66mg"
const SECRET_KEY = "VDaACYb0LV9eNjTetIOElcVQkvJck_J_QljX_FcHRj87ZKiy0z0ty0ZsYBkoXkY9b7eq1EhwJaw7FF3akA3KBQ"
func ComputeHmacSHA1(message string, secretKey string) string {
key := []byte(secretKey)
h := hmac.New(sha1.New, key)
h.Write([]byte(message))
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}
func GenerateSignature(aURL string, secretKey string) string {
//解析url的query部分(全部转为小写字母),排序和url编码后返回command string
u, _ := url.ParseRequestURI(strings.ToLower(aURL))
commandStr := u.Query().Encode()
return ComputeHmacSHA1(commandStr, secretKey)
}
func SignAPI(aURL string, apiKey string, secretKey string) string {
aurl := aURL + "&apiKey=" + apiKey
signature := GenerateSignature(aurl, secretKey)
return aurl + "&signature=" + url.QueryEscape(signature)
}
func Sign(aURL string) string {
return SignAPI(aURL, API_KEY, SECRET_KEY)
}
func main() {
aurl := "http://localhost:8080/client/api?command=listUsers&response=json"
fmt.Println(aurl)
fmt.Println(Sign(aurl))
//&signature=TTpdDq%2F7j%2FJ58XCRHomKoQXEQds%3D
}