在通过了keyStone验证通过后,openstack响应endpoints数组,这些数组对应的是openstack的主要模块访问地址,例如nova,neutron等。
neutron:
{
"endpoints": [{
"region_id": "RegionOne",
"url": "http://xxx:9696",
"region": "RegionOne",
"interface": "internal",
"id": "1b6abf4194024a5a88ad536836918d34"
}, {
"region_id": "RegionOne",
"url": "http://xxx:9696",
"region": "RegionOne",
"interface": "admin",
"id": "8b7315fa74654cb8b86641bd44351da4"
}, {
"region_id": "RegionOne",
"url": "http://xxx:9696", // 这个就是可以通过外部访问的api,http schema
"region": "RegionOne",
"interface": "public",
"id": "f895dc01a3424c1e955da86b7bdc63f2"
}],
"type": "network",
"id": "27c04c9ee6be457fa73671cf967aae19",
"name": "neutron"
}
在需要获取network相关的api时,就可以通过这个public的url进行访问。
用户就可以与openstack进行交互查询image,flavor,networks等数据,作为创建虚拟机的参数。
curl方式
在验证keystone的请求中,需要加上参数 -i ,这样才能获取返回的header(token在header中存放),x-Subject-Token
HTTP/1.1 201 Created
Date: Fri, 28 Oct 2016 09:22:22 GMT
Server: Apache
X-Subject-Token: gAAAAABYExjOa0G6p-5HkVwVxwFDJ7Dc_eXrkfGxQYUVF8sgD8WfQICNuQi76FAcQCvsayDPwiYGLOUQKjdmA2jA9FpGrmWWacBhn_fMbggN0gHAwkeWUrXg01JySJh7szvjHi0LqGo_OOY7NuJ34xpSPIp1A1sC__ETXvwpqMli9Va6JqqG8do
Vary: X-Auth-Token
x-openstack-request-id: req-4fbf6557-066b-4135-818e-cc935e45e313
Content-Length: 5407
Content-Type: application/json
为了方便测试,可以将keystone验证返回的token和对应的url存放在变量中,
export OS_TOKEN=gAAAAABYExjOa0G6p-5HkVwVxwFDJ7Dc_eXrkfGxQYUVF8sgD8WfQICNuQi76FAcQCvsayDPwiYGLOUQKjdmA2jA9FpGrmWWacBhn_fMbggN0gHAwkeWUrXg01JySJh7szvjHi0LqGo_OOY7NuJ34xpSPIp1A1sC__ETXvwpqMli9Va6JqqG8do
获取flavors
curl -s -H "X-Auth-Token: $OS_TOKEN" \
$OS_COMPUTE_API/flavors \
| python -m json.tool
可以根据自己的需要从返回的配置中获取flavor
{
"flavors": [
{
"id": "1",
"links": [
{
"href": "http://223.202.32.35:8774/v2.1/fc6ac8c46d8147fd9ffa7a32e373ff9a/flavors/1",
"rel": "self"
},
{
"href": "http://223.202.32.35:8774/fc6ac8c46d8147fd9ffa7a32e373ff9a/flavors/1",
"rel": "bookmark"
}
],
"name": "m1.tiny"
},
{
"id": "2",
"links": [
{
"href": "http://223.202.32.35:8774/v2.1/fc6ac8c46d8147fd9ffa7a32e373ff9a/flavors/2",
"rel": "self"
},
{
"href": "http://223.202.32.35:8774/fc6ac8c46d8147fd9ffa7a32e373ff9a/flavors/2",
"rel": "bookmark"
}
],
"name": "m1.small"
}
}
获取image
curl -s -H "X-Auth-Token: $OS_TOKEN" \
$OS_IMAGE_API/v2/images \
| python -m json.tool
返回的json数据
{
"first": "/v2/images",
"images": [
{
"checksum": "0d7ba90f5923297ee53351ce7e72ab76",
"container_format": "bare",
"created_at": "2016-10-19T09:19:36Z",
"description": "",
"disk_format": "qcow2",
"file": "/v2/images/ea99659a-5109-49e3-9b0f-bf5345eb7d97/file",
"id": "ea99659a-5109-49e3-9b0f-bf5345eb7d97",
"min_disk": 10,
"min_ram": 512,
"name": "Centos 7",
"owner": "4f9cfde31f7d42f096b766e4b95855e8",
"protected": false,
"schema": "/v2/schemas/image",
"self": "/v2/images/ea99659a-5109-49e3-9b0f-bf5345eb7d97",
"size": 377880576,
"status": "active",
"tags": [],
"updated_at": "2016-10-26T08:56:33Z",
"virtual_size": null,
"visibility": "public"
}]
}
获取networks信息
curl -s -H "X-Auth-Token: $OS_TOKEN" \
$OS_NETWORKS_API/v2.0/networks \
| python -m json.tool
返回的json,其中在后面需要使用的一个是service,主要负责内网ip的分配,另一个是public,进行公网IP的分配
{
"networks": [
{
"admin_state_up": true,
"availability_zone_hints": [],
"availability_zones": [
"nova"
],
"created_at": "2016-10-08T07:09:20",
"description": "",
"id": "38d9d825-256b-4477-939b-42714a28776d",
"ipv4_address_scope": null,
"ipv6_address_scope": null,
"mtu": 1450,
"name": "HA network tenant 4f9cfde31f7d42f096b766e4b95855e8",
"port_security_enabled": true,
"provider:network_type": "vxlan",
"provider:physical_network": null,
"provider:segmentation_id": 9,
"router:external": false,
"shared": false,
"status": "ACTIVE",
"subnets": [
"2aea08cf-4027-4569-86b4-63646f6dd2b2"
],
"tags": [],
"tenant_id": "",
"updated_at": "2016-10-08T07:09:20"
},
{
"admin_state_up": true,
"availability_zone_hints": [],
"availability_zones": [
"nova"
],
"created_at": "2016-10-08T09:11:03",
"description": "",
"id": "baa3dbad-5994-4837-9263-32304ee7d035",
"ipv4_address_scope": null,
"ipv6_address_scope": null,
"is_default": false,
"mtu": 1500,
"name": "public",
"port_security_enabled": true,
"provider:network_type": "vlan",
"provider:physical_network": "vlan",
"provider:segmentation_id": 40,
"router:external": true,
"shared": true,
"status": "ACTIVE",
"subnets": [
"a2c44a10-6f23-42dd-b7d8-c3319d542628"
],
"tags": [],
"tenant_id": "4f9cfde31f7d42f096b766e4b95855e8",
"updated_at": "2016-10-08T09:19:18"
},
{
"admin_state_up": true,
"availability_zone_hints": [],
"availability_zones": [
"nova"
],
"created_at": "2016-10-09T04:04:29",
"description": "",
"id": "f3411c78-f02a-4556-9171-4e9e5b102b20",
"ipv4_address_scope": null,
"ipv6_address_scope": null,
"mtu": 1450,
"name": "service",
"port_security_enabled": true,
"provider:network_type": "vxlan",
"provider:physical_network": null,
"provider:segmentation_id": 71,
"router:external": false,
"shared": true,
"status": "ACTIVE",
"subnets": [
"a76d00f6-752a-40af-bbcd-fefb6a33fef0"
],
"tags": [],
"tenant_id": "4f9cfde31f7d42f096b766e4b95855e8",
"updated_at": "2016-10-10T05:43:49"
}
]
}
有了这些参数基本上就可以创建一个虚拟机实例了。
curl -is -H "X-Auth-Token: $OS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"server": {
"name": "patrick-vm",
"imageRef": "fff2aa1b-dd06-4dbf-b259-652057615f4b",
"flavorRef": "2",
"networks": [{"uuid": "f3411c78-f02a-4556-9171-4e9e5b102b20"}]
}}' \
$OS_COMPUTE_API/servers
如果需要采用keyPairs的方式登录创建的虚拟机。添加参数key_name即可,对应的value就是秘钥对的名字
如果需要在虚拟机创建后,执行相应的脚本。则需要添加user_data这个参数,脚本的编写方式需要满足cloud-init要求,该参数填写前,需要将脚本编码为base64格式。
添加参数后的请求如下:
curl -is -H "X-Auth-Token: $OS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"server": {
"name": "patrick-vm",
"imageRef": "fff2aa1b-dd06-4dbf-b259-652057615f4b",
"flavorRef": "2",
"networks": [{"uuid": "f3411c78-f02a-4556-9171-4e9e5b102b20"}],
"user_data": "IyEvYmluL3NoIAplY2hvICJIZWxsbyBXb3JsZC4gIFRoZSB0aW1lIGlzIG5vdyAkKGRhdGUgLVIpISIgfCB0ZWUgL3Jvb3Qvb3V0cHV0LnR4dCAK",
"key_name": "op-key"
}}' \
$OS_COMPUTE_API/servers
其中user_data对应的原文为
#!/bin/sh
echo "Hello World. The time is now $(date -R)!" | tee /root/output.txt
pkgcloud
由于pkgcloud在createClient后将对应的url和token都存放在client对象中,所以过程相对简单很多
var pkgcloud = require('pkgcloud'),
_ = require('lodash');
var cc = pkgcloud.compute.createClient({
provider: 'openstack', // required
username: '$user_name', // required
password: '$user_pass', // required
region: 'RegionOne',
keystoneAuthVersion: 'v3',
domainId: 'Default',
tenantId: 'fc6ac8c46d8147fd9ffa7a32e373ff9a',
domainName: 'Default',
authUrl: 'http://xxxx:5000' // required
});
var nc = pkgcloud.network.createClient({
provider: 'openstack', // required
username: '$user_name', // required
password: '$user_pass', // required
region: 'RegionOne',
keystoneAuthVersion: 'v3',
domainId: 'Default',
tenantId: 'fc6ac8c46d8147fd9ffa7a32e373ff9a',
domainName: 'Default',
authUrl: 'http://xxxx:5000' // required
});
cc.getFlavors(function(err, flavors) {
if (err) {
console.error(err);
return;
}
cc.getImages(function(err, images) {
if (err) {
console.log(err);
return;
}
var flavor = _.findWhere(flavors, { name: 'm1.small' });
var image = _.findWhere(images, { name: 'ubuntu14.04' });
var userData = '#!/bin/sh \n';
userData += 'echo "Hello World. The time is now $(date -R)!" | tee /root/output.txt \n';
var userData64 = new Buffer(userData).toString("base64");
cc.createServer({
name: 'patrick_client',
image: image,
flavor: flavor,
networks: [{ uuid: 'f3411c78-f02a-4556-9171-4e9e5b102b20' }],
cloudConfig: userData64,
securityGroups: [{ name: 'default' }],
keyname: 'op-key'
}, handleServerResponse);
});
});
过程虽然比较简单,但是参数比较坑,比如user_data的参数映射为了cloudConfig