Add getting_started tutorial for Gophercloud SDK

Add getting_started tutorial for Gophercloud SDK, code had been tested
on a openstack cloud with neutron.

Change-Id: Ife8bc23671ddff175a5ff424e08893c746d97482
This commit is contained in:
Chung Chih, Hung 2016-02-17 11:24:54 +08:00
parent ed11113c62
commit 7f6e20ae5c
4 changed files with 489 additions and 1 deletions

View File

@ -0,0 +1,294 @@
package main
import (
"fmt"
"io/ioutil"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/openstack"
"github.com/rackspace/gophercloud/openstack/compute/v2/flavors"
"github.com/rackspace/gophercloud/openstack/compute/v2/images"
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/floatingip"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups"
"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
"github.com/rackspace/gophercloud/openstack/networking/v2/extensions/external"
)
func main() {
// step-1
var authUsername string = "your_auth_username"
var authPassword string = "your_auth_password"
var authUrl string = "http://controller:5000"
var projectName string = "your_project_id"
var regionName string = "your_region_name"
authOpts := gophercloud.AuthOptions{
IdentityEndpoint: authUrl,
Username: authUsername,
Password: authPassword,
TenantID: projectName,
}
provider, _ := openstack.AuthenticatedClient(authOpts)
client, _ := openstack.NewComputeV2(provider, gophercloud.EndpointOpts{
Region: regionName,
})
// step-2
pager := images.ListDetail(client, images.ListOpts{})
page, _ := pager.AllPages()
imageList, _ := images.ExtractImages(page)
fmt.Println(imageList)
// step-3
pager = flavors.ListDetail(client, flavors.ListOpts{})
page, _ = pager.AllPages()
flavorList, _ := flavors.ExtractFlavors(page)
fmt.Println(flavorList)
// step-4
imageID := "74e6d1ec-9a08-444c-8518-4f232446386d"
image, _ := images.Get(client, imageID).Extract()
fmt.Println(image)
// step-5
flavorID := "1"
flavor, _ := flavors.Get(client, flavorID).Extract()
fmt.Println(flavor)
// step-6
instanceName := "testing"
testingInstance, _ := servers.Create(client, servers.CreateOpts{
Name: instanceName,
ImageRef: imageID,
FlavorRef: flavorID,
}).Extract()
fmt.Println(testingInstance)
// step-7
pager = servers.List(client, servers.ListOpts{})
page, _ = pager.AllPages()
serverList, _ := servers.ExtractServers(page)
fmt.Println(serverList)
// step-8
servers.Delete(client, testingInstance.ID)
// step-9
fmt.Println("Checking for existing SSH key pair...")
keyPairName := "demokey"
pubKeyFile := "~/.ssh/id_rsa.pub"
keyPairExists := false
pager = keypairs.List(client)
page, _ = pager.AllPages()
keypairList, _ := keypairs.ExtractKeyPairs(page)
for _, k := range keypairList {
if k.Name == keyPairName {
keyPairExists = true
break
}
}
if keyPairExists {
fmt.Println("Keypair " + keyPairName + " already exists. Skipping import.")
} else {
fmt.Println("adding keypair...")
bs, _ := ioutil.ReadFile(pubKeyFile)
keypairs.Create(client, keypairs.CreateOpts{
Name: keyPairName,
PublicKey: string(bs),
}).Extract()
}
pager = keypairs.List(client)
page, _ = pager.AllPages()
keypairList, _ = keypairs.ExtractKeyPairs(page)
fmt.Println(keypairList)
// step-10
fmt.Println("Checking for existing security group...")
var allInOneSecurityGroup secgroups.SecurityGroup
securityGroupName := "all-in-one"
securityGroupExists := false
pager = secgroups.List(client)
page, _ = pager.AllPages()
secgroupList, _ := secgroups.ExtractSecurityGroups(page)
for _, secGroup := range secgroupList {
if secGroup.Name == securityGroupName {
allInOneSecurityGroup = secGroup
securityGroupExists = true
break
}
}
if securityGroupExists {
fmt.Println("Security Group " + allInOneSecurityGroup.Name + " already exists. Skipping creation.")
} else {
allInOneSecurityGroup, _ := secgroups.Create(client, secgroups.CreateOpts{
Name: securityGroupName,
Description: "network access for all-in-one application.",
}).Extract()
secgroups.CreateRule(client, secgroups.CreateRuleOpts{
ParentGroupID: allInOneSecurityGroup.ID,
FromPort: 80,
ToPort: 80,
IPProtocol: "TCP",
CIDR: "0.0.0.0/0",
}).Extract()
secgroups.CreateRule(client, secgroups.CreateRuleOpts{
ParentGroupID: allInOneSecurityGroup.ID,
FromPort: 22,
ToPort: 22,
IPProtocol: "TCP",
CIDR: "0.0.0.0/0",
}).Extract()
}
pager = secgroups.List(client)
page, _ = pager.AllPages()
secgroupList, _ = secgroups.ExtractSecurityGroups(page)
fmt.Println(secgroupList)
// step-11
userData := `#!/usr/bin/env bash
curl -L -s https://git.openstack.org/cgit/openstack/faafo/plain/contrib/install.sh | bash -s -- \
-i faafo -i messaging -r api -r worker -r demo
`
// step-12
fmt.Println("Checking for existing instance...")
instanceName = "all-in-one"
instanceExists := false
pager = servers.List(client, servers.ListOpts{})
page, _ = pager.AllPages()
serverList, _ = servers.ExtractServers(page)
for _, s := range serverList {
if s.Name == instanceName {
testingInstance = &s
instanceExists = true
break
}
}
if instanceExists {
fmt.Println("Instance " + testingInstance.Name + " already exists. Skipping creation.")
} else {
opts := servers.CreateOpts{
Name: instanceName,
ImageRef: image.ID,
FlavorRef: flavor.ID,
SecurityGroups: []string{securityGroupName},
UserData: []byte(userData),
}
testingInstance, _ = servers.Create(client, keypairs.CreateOptsExt{
CreateOptsBuilder: opts,
KeyName: keyPairName,
}).Extract()
}
servers.WaitForStatus(client, testingInstance.ID, "ACTIVE", 300)
pager = servers.List(client, servers.ListOpts{})
page, _ = pager.AllPages()
serverList, _ = servers.ExtractServers(page)
fmt.Println(serverList)
// step-13
var privateIP string
for t, addrs := range testingInstance.Addresses {
if t != "private" || len(privateIP) != 0 {
continue
}
addrs, ok := addrs.([]interface{})
if !ok {
continue
}
for _, addr := range addrs {
a, ok := addr.(map[string]interface{})
if !ok || a["version"].(float64) != 4 {
continue
}
ip, ok := a["addr"].(string)
if ok && len(ip) != 0 {
privateIP = ip
fmt.Println("Private IP found: " + privateIP)
break
}
}
}
// step-14
var publicIP string
for t, addrs := range testingInstance.Addresses {
if t != "public" || len(publicIP) != 0 {
continue
}
addrs, ok := addrs.([]interface{})
if !ok {
continue
}
for _, addr := range addrs {
a, ok := addr.(map[string]interface{})
if !ok || a["version"].(float64) != 4 {
continue
}
ip, ok := a["addr"].(string)
if ok && len(ip) != 0 {
publicIP = ip
fmt.Println("Public IP found: " + publicIP)
break
}
}
}
// step-15
fmt.Println("Checking for unused Floating IP...")
var unusedFloatingIP string
pager = floatingip.List(client)
page, _ = pager.AllPages()
floatingIPList, _ := floatingip.ExtractFloatingIPs(page)
for _, ip := range floatingIPList {
if ip.InstanceID == "" {
unusedFloatingIP = ip.IP
break
}
}
networkClient, _ := openstack.NewNetworkV2(provider, gophercloud.EndpointOpts{
Region: regionName,
})
pager = networks.List(networkClient, networks.ListOpts{})
page, _ = pager.AllPages()
poolList, _ := external.ExtractList(page)
for _, pool := range poolList {
if len(unusedFloatingIP) != 0 || !pool.External {
continue
}
fmt.Println("Allocating new Floating IP from pool: " + pool.Name)
f, _ := floatingip.Create(client, floatingip.CreateOpts{Pool: pool.Name}).Extract()
unusedFloatingIP = f.IP
}
// step-16
if len(publicIP) != 0 {
fmt.Println("Instance " + testingInstance.Name + " already has a public ip. Skipping attachment.")
} else {
floatingip.Associate(client, testingInstance.ID, unusedFloatingIP)
}
// step-17
var actualIPAddress string
if len(publicIP) != 0 {
actualIPAddress = publicIP
} else if len(unusedFloatingIP) != 0 {
actualIPAddress = unusedFloatingIP
} else {
actualIPAddress = privateIP
}
fmt.Println("The Fractals app will be deployed to http://" + actualIPAddress)
}

View File

@ -96,6 +96,11 @@ and toolkits with the OpenStack cloud:
- A .NET-based library.
Use it to write C++ or C# code for Microsoft applications.
- https://www.nuget.org/packages/openstack.net
* - Go
- `gophercloud <https://github.com/rackspace/gophercloud>`_
- A go-based SDK.
Use it with multiple clouds.
- http://gophercloud.io/
For a list of available SDKs, see `Software Development Kits <https://wiki.openstack.org/wiki/SDKs>`_.
@ -181,6 +186,11 @@ To interact with the cloud, you must also have
.. note:: Before proceeding, install the latest version of shade.
.. only:: gophercloud
`a recent version of gophercloud installed <https://godoc.org/github.com/rackspace/gophercloud>`_
Obtain the following information from your cloud provider:
* auth URL
@ -307,6 +317,18 @@ to run code snippets in your language of choice.
of the following API calls please double-check your
credentials.
.. only:: gophercloud
To try it, add the following code to go file
.. literalinclude:: ../samples/gophercloud/getting_started.go
:language: go
:start-after: step-1
:end-before: step-2
.. note:: The client object accesses the Compute v2.0 service,
so that version is in this tutorial.
Flavors and images
~~~~~~~~~~~~~~~~~~
@ -425,6 +447,20 @@ To list the images that are available in your cloud, run some API calls:
openstack.image.v1.image.Image(attrs={u'name': u'ubuntu-14.04', u'container_format': u'bare', u'disk_format': u'qcow2', u'checksum': u'6d8f1c8cf05e1fbdc8b543fda1a9fa7f', u'id': u'cb6b7936-d2c5-4901-8678-c88b3a6ed84c', u'size': 258540032}, loaded=True)
...
.. only:: gophercloud
.. literalinclude:: ../samples/gophercloud/getting_started.go
:language: go
:start-after: step-2
:end-before: step-3
This code returns output like this:
.. code-block:: none
[{74e6d1ec-9a08-444c-8518-4f232446386d 2016-02-01T07:20:31Z 0 0 cirros-0.3.4-x86_64-uec 100 ACTIVE 2016-02-01T07:20:32Z}
{f70b7fb0-348a-4519-b358-0f239dc64dc5 2016-02-01T07:20:30Z 0 0 cirros-0.3.4-x86_64-uec-ramdisk 100 ACTIVE 2016-02-01T07:20:31Z}
{e92f5e17-60d2-4cb5-b893-d605b136afab 2016-02-01T07:20:29Z 0 0 cirros-0.3.4-x86_64-uec-kernel 100 ACTIVE 2016-02-01T07:20:30Z}]
You can also get information about available flavors:
@ -545,6 +581,22 @@ You can also get information about available flavors:
...
.. only:: gophercloud
.. literalinclude:: ../samples/gophercloud/getting_started.go
:language: go
:start-after: step-3
:end-before: step-4
This code returns output like this:
.. code-block:: none
[{1 1 512 m1.tiny 1 0 1}
{2 20 2048 m1.small 1 0 1}
{3 40 4096 m1.medium 1 0 2}
...
{84 0 128 m1.micro 1 0 1}]
Your images and flavors will be different, of course.
@ -656,6 +708,19 @@ image that you picked in the previous section:
openstack.image.v1.image.Image(attrs={u'name': u'ubuntu-14.04', u'container_format': u'bare', u'disk_format': u'qcow2', u'checksum': u'6d8f1c8cf05e1fbdc8b543fda1a9fa7f', u'id': u'cb6b7936-d2c5-4901-8678-c88b3a6ed84c', u'size': 258540032}, loaded=True)
.. only:: gophercloud
.. literalinclude:: ../samples/gophercloud/getting_started.go
:language: go
:start-after: step-4
:end-before: step-5
You should see output like this:
.. code-block:: none
&{74e6d1ec-9a08-444c-8518-4f232446386d 2016-02-01T07:20:31Z 0 0 cirros-0.3.4-x86_64-uec 100 ACTIVE 2016-02-01T07:20:32Z}
Next, tell the script which flavor you want to use:
.. only:: fog
@ -755,6 +820,19 @@ Next, tell the script which flavor you want to use:
openstack.compute.v2.flavor.Flavor(attrs={u'name': u'm1.small', u'links': [{u'href': u'http://controller:8774/v2/96ff6aa79e60423d9848b70d5475c415/flavors/2', u'rel': u'self'}, {u'href': u'http://controller:8774/96ff6aa79e60423d9848b70d5475c415/flavors/2', u'rel': u'bookmark'}], u'ram': 2048, u'OS-FLV-DISABLED:disabled': False, u'vcpus': 1, u'swap': u'', u'os-flavor-access:is_public': True, u'rxtx_factor': 1.0, u'OS-FLV-EXT-DATA:ephemeral': 0, u'disk': 20, 'id': u'2'}, loaded=True)
.. only:: gophercloud
.. literalinclude:: ../samples/gophercloud/getting_started.go
:language: go
:start-after: step-5
:end-before: step-6
You should see output like this:
.. code-block:: none
&{1 1 512 m1.tiny 1 0 1}
Now, you can launch the instance.
Launch an instance
@ -836,6 +914,19 @@ Create the instance.
:start-after: step-6
:end-before: step-7
.. only:: gophercloud
.. literalinclude:: ../samples/gophercloud/getting_started.go
:language: go
:start-after: step-6
:end-before: step-7
You should see output like this:
.. code-block:: none
&{739dd964-ae88-461d-9746-f8f1139d20f6 0 map[] map[] map[] map[] ... RPUkTFM8fynn [map[name:default]]}
If you list existing instances:
.. only:: fog
@ -878,6 +969,13 @@ If you list existing instances:
:start-after: step-7
:end-before: step-8
.. only:: gophercloud
.. literalinclude:: ../samples/gophercloud/getting_started.go
:language: go
:start-after: step-7
:end-before: step-8
The new instance appears.
.. only:: libcloud
@ -982,6 +1080,14 @@ The new instance appears.
updated: '2015-07-20T20:31:10Z'
user_id: bfd3dbf1c8a242cd90884408de547bb9
.. only:: gophercloud
.. code-block:: none
[...
{739dd964-ae88-461d-9746-f8f1139d20f6 061fdb617b6c4bdf8694bf5b0d8eefdd bb210009e42c4b509ba75893a757c8e5 testing 2016-02-16T07:16:52Z 2016-02-16T07:16:52Z 2d2f4bba90498fd46c72e7d019dde9189c36637b73e71e1e652d75db BUILD 0 ... [map[name:default]]}
...]
Before you continue, you must do one more thing.
Destroy an instance
@ -1029,6 +1135,13 @@ cost money. To avoid unexpected expenses, destroy cloud resources.
:start-after: step-8
:end-before: step-9
.. only:: gophercloud
.. literalinclude:: ../samples/gophercloud/getting_started.go
:language: go
:start-after: step-8
:end-before: step-9
If you list the instances again, the instance disappears.
Leave your shell open to use it for another instance deployment in this
@ -1101,6 +1214,13 @@ your public SSH key file.
openstack.compute.v2.keypair.Keypair(attrs={u'public_key': u'ssh-rsa ABAAABAQCyyzkyaPf.....', u'name': u'demokey', u'fingerprint': aa:bb:cc:... '}, loaded=True)
.. only:: gophercloud
.. literalinclude:: ../samples/gophercloud/getting_started.go
:language: go
:start-after: step-9
:end-before: step-10
* Network access. By default, OpenStack filters all traffic. You must create
a security group and apply it to your instance. The security group allows HTTP
and SSH access. We will go into more detail in :doc:`/introduction`.
@ -1136,6 +1256,13 @@ your public SSH key file.
:start-after: step-10
:end-before: step-11
.. only:: gophercloud
.. literalinclude:: ../samples/gophercloud/getting_started.go
:language: go
:start-after: step-10
:end-before: step-11
* Userdata. During instance creation, you can provide userdata to OpenStack to
configure instances after they boot. The cloud-init service applies the
user data to an instance. You must pre-install the cloud-init service on your
@ -1174,6 +1301,13 @@ your public SSH key file.
:start-after: step-11
:end-before: step-12
.. only:: gophercloud
.. literalinclude:: ../samples/gophercloud/getting_started.go
:language: go
:start-after: step-11
:end-before: step-12
Now, you can boot and configure the instance.
Boot and configure an instance
@ -1215,6 +1349,13 @@ After you request the instance, wait for it to build.
:start-after: step-12
:end-before: step-13
.. only:: gophercloud
.. literalinclude:: ../samples/gophercloud/getting_started.go
:language: go
:start-after: step-12
:end-before: step-13
When the instance boots, the `ex_userdata` variable value instructs the
instance to deploy the Fractals application.
@ -1339,6 +1480,45 @@ instance.
:start-after: step-14
:end-before: step-15
.. only:: gophercloud
To see whether a private IP address is assigned to your instance:
.. literalinclude:: ../samples/gophercloud/getting_started.go
:language: go
:start-after: step-13
:end-before: step-14
If one is assigned, users can use this address to access the instance on
some OpenStack clouds.
To determine whether a public IP address is assigned to your instance:
.. literalinclude:: ../samples/gophercloud/getting_started.go
:language: go
:start-after: step-14
:end-before: step-15
If one is assigned, users can use this address to access the instance.
To create a floating IP address to use with your instance:
Use network service client to select the first floating IP address pool.
Allocate this pool to your project and use it to get a floating IP address.
.. literalinclude:: ../samples/gophercloud/getting_started.go
:language: go
:start-after: step-15
:end-before: step-16
Attach the floating IP address to the instance:
.. literalinclude:: ../samples/gophercloud/getting_started.go
:language: go
:start-after: step-16
:end-before: step-17
Run the script to start the deployment.
@ -1376,6 +1556,12 @@ interface at the following link.
.. literalinclude:: ../samples/openstacksdk/getting_started.py
:start-after: step-15
.. only:: gophercloud
.. literalinclude:: ../samples/gophercloud/getting_started.go
:language: go
:start-after: step-17
.. note:: If you do not use floating IP addresses, substitute another IP
address, as appropriate.
@ -1442,3 +1628,8 @@ information, the flavor ID, and image ID.
.. literalinclude:: ../samples/openstacksdk/getting_started.py
:language: python
.. only:: gophercloud
.. literalinclude:: ../samples/gophercloud/getting_started.go
:language: go

View File

@ -9,7 +9,7 @@ for tag in libcloud; do
done
# Draft documents
for tag in dotnet fog openstacksdk pkgcloud shade jclouds; do
for tag in dotnet fog openstacksdk pkgcloud shade jclouds gophercloud; do
tools/build-rst.sh firstapp \
--tag ${tag} --target "api-ref/draft/firstapp-${tag}"
done

View File

@ -161,6 +161,9 @@ commands = sphinx-build -E -W -t libcloud firstapp/source firstapp/build/html
[testenv:firstapp-shade]
commands = sphinx-build -E -W -t shade firstapp/source firstapp/build-shade/html
[testenv:firstapp-gophercloud]
commands = sphinx-build -E -W -t gophercloud firstapp/source firstapp/build-gophercloud/html
[testenv:api-quick-start]
commands =
{toxinidir}/tools/build-api-quick-start.sh