Basic Rackspace cloud support
This enables all but Load Balancer support for the Rackspace public cloud platform.
This commit is contained in:
4
Godeps/Godeps.json
generated
4
Godeps/Godeps.json
generated
@@ -203,8 +203,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/rackspace/gophercloud",
|
"ImportPath": "github.com/rackspace/gophercloud",
|
||||||
"Comment": "v1.0.0",
|
"Comment": "v1.0.0-336-g2a6e319",
|
||||||
"Rev": "da56de6a59e53fdd61be1b5d9b87df34c47ac420"
|
"Rev": "2a6e3190447abe5d000f951595ead1cf98df72d8"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/skynetservices/skydns/msg",
|
"ImportPath": "github.com/skynetservices/skydns/msg",
|
||||||
|
3
Godeps/_workspace/src/github.com/rackspace/gophercloud/.travis.yml
generated
vendored
3
Godeps/_workspace/src/github.com/rackspace/gophercloud/.travis.yml
generated
vendored
@@ -4,6 +4,8 @@ install:
|
|||||||
go:
|
go:
|
||||||
- 1.1
|
- 1.1
|
||||||
- 1.2
|
- 1.2
|
||||||
|
- 1.3
|
||||||
|
- 1.4
|
||||||
- tip
|
- tip
|
||||||
script: script/cibuild
|
script: script/cibuild
|
||||||
after_success:
|
after_success:
|
||||||
@@ -12,3 +14,4 @@ after_success:
|
|||||||
- go get github.com/mattn/goveralls
|
- go get github.com/mattn/goveralls
|
||||||
- export PATH=$PATH:$HOME/gopath/bin/
|
- export PATH=$PATH:$HOME/gopath/bin/
|
||||||
- goveralls 2k7PTU3xa474Hymwgdj6XjqenNfGTNkO8
|
- goveralls 2k7PTU3xa474Hymwgdj6XjqenNfGTNkO8
|
||||||
|
sudo: false
|
||||||
|
2
Godeps/_workspace/src/github.com/rackspace/gophercloud/CONTRIBUTING.md
generated
vendored
2
Godeps/_workspace/src/github.com/rackspace/gophercloud/CONTRIBUTING.md
generated
vendored
@@ -11,7 +11,7 @@ As a contributor you will need to setup your workspace in a slightly different
|
|||||||
way than just downloading it. Here are the basic installation instructions:
|
way than just downloading it. Here are the basic installation instructions:
|
||||||
|
|
||||||
1. Configure your `$GOPATH` and run `go get` as described in the main
|
1. Configure your `$GOPATH` and run `go get` as described in the main
|
||||||
[README](/#how-to-install).
|
[README](/README.md#how-to-install).
|
||||||
|
|
||||||
2. Move into the directory that houses your local repository:
|
2. Move into the directory that houses your local repository:
|
||||||
|
|
||||||
|
4
Godeps/_workspace/src/github.com/rackspace/gophercloud/UPGRADING.md
generated
vendored
4
Godeps/_workspace/src/github.com/rackspace/gophercloud/UPGRADING.md
generated
vendored
@@ -238,7 +238,7 @@ err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
|||||||
imageList, err := images.ExtractImages(page)
|
imageList, err := images.ExtractImages(page)
|
||||||
|
|
||||||
for _, i := range imageList {
|
for _, i := range imageList {
|
||||||
// "i" will be a images.Image
|
// "i" will be an images.Image
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
@@ -284,7 +284,7 @@ err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
|||||||
imageList, err := images.ExtractImages(page)
|
imageList, err := images.ExtractImages(page)
|
||||||
|
|
||||||
for _, i := range imageList {
|
for _, i := range imageList {
|
||||||
// "i" will be a images.Image
|
// "i" will be an images.Image
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
@@ -13,9 +13,9 @@ import (
|
|||||||
|
|
||||||
func TestSnapshots(t *testing.T) {
|
func TestSnapshots(t *testing.T) {
|
||||||
|
|
||||||
client, err := newClient()
|
client, err := newClient(t)
|
||||||
th.AssertNoErr(t, err)
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
v, err := volumes.Create(client, &volumes.CreateOpts{
|
v, err := volumes.Create(client, &volumes.CreateOpts{
|
||||||
Name: "gophercloud-test-volume",
|
Name: "gophercloud-test-volume",
|
||||||
Size: 1,
|
Size: 1,
|
||||||
|
@@ -13,7 +13,7 @@ import (
|
|||||||
th "github.com/rackspace/gophercloud/testhelper"
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newClient() (*gophercloud.ServiceClient, error) {
|
func newClient(t *testing.T) (*gophercloud.ServiceClient, error) {
|
||||||
ao, err := openstack.AuthOptionsFromEnv()
|
ao, err := openstack.AuthOptionsFromEnv()
|
||||||
th.AssertNoErr(t, err)
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ func newClient() (*gophercloud.ServiceClient, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestVolumes(t *testing.T) {
|
func TestVolumes(t *testing.T) {
|
||||||
client, err := newClient()
|
client, err := newClient(t)
|
||||||
th.AssertNoErr(t, err)
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
cv, err := volumes.Create(client, &volumes.CreateOpts{
|
cv, err := volumes.Create(client, &volumes.CreateOpts{
|
||||||
|
@@ -12,7 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestVolumeTypes(t *testing.T) {
|
func TestVolumeTypes(t *testing.T) {
|
||||||
client, err := newClient()
|
client, err := newClient(t)
|
||||||
th.AssertNoErr(t, err)
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
vt, err := volumetypes.Create(client, &volumetypes.CreateOpts{
|
vt, err := volumetypes.Create(client, &volumetypes.CreateOpts{
|
||||||
|
@@ -5,10 +5,10 @@ package v2
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud/acceptance/tools"
|
||||||
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume"
|
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume"
|
||||||
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
"github.com/smashwilson/gophercloud/acceptance/tools"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBootFromVolume(t *testing.T) {
|
func TestBootFromVolume(t *testing.T) {
|
||||||
@@ -37,14 +37,19 @@ func TestBootFromVolume(t *testing.T) {
|
|||||||
|
|
||||||
serverCreateOpts := servers.CreateOpts{
|
serverCreateOpts := servers.CreateOpts{
|
||||||
Name: name,
|
Name: name,
|
||||||
FlavorRef: "3",
|
FlavorRef: choices.FlavorID,
|
||||||
|
ImageRef: choices.ImageID,
|
||||||
}
|
}
|
||||||
server, err := bootfromvolume.Create(client, bootfromvolume.CreateOptsExt{
|
server, err := bootfromvolume.Create(client, bootfromvolume.CreateOptsExt{
|
||||||
serverCreateOpts,
|
serverCreateOpts,
|
||||||
bd,
|
bd,
|
||||||
}).Extract()
|
}).Extract()
|
||||||
th.AssertNoErr(t, err)
|
th.AssertNoErr(t, err)
|
||||||
|
if err = waitForStatus(client, server, "ACTIVE"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
t.Logf("Created server: %+v\n", server)
|
t.Logf("Created server: %+v\n", server)
|
||||||
//defer deleteServer(t, client, server)
|
defer servers.Delete(client, server.ID)
|
||||||
t.Logf("Deleting server [%s]...", name)
|
t.Logf("Deleting server [%s]...", name)
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
// +build acceptance
|
// +build acceptance common
|
||||||
|
|
||||||
package v2
|
package v2
|
||||||
|
|
||||||
|
74
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/keypairs_test.go
generated
vendored
Normal file
74
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/keypairs_test.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
// +build acceptance
|
||||||
|
|
||||||
|
package v2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud/acceptance/tools"
|
||||||
|
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs"
|
||||||
|
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
|
||||||
|
"code.google.com/p/go.crypto/ssh"
|
||||||
|
)
|
||||||
|
|
||||||
|
const keyName = "gophercloud_test_key_pair"
|
||||||
|
|
||||||
|
func TestCreateServerWithKeyPair(t *testing.T) {
|
||||||
|
client, err := newClient()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("Skipping test that requires server creation in short mode.")
|
||||||
|
}
|
||||||
|
|
||||||
|
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||||
|
publicKey := privateKey.PublicKey
|
||||||
|
pub, err := ssh.NewPublicKey(&publicKey)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
pubBytes := ssh.MarshalAuthorizedKey(pub)
|
||||||
|
pk := string(pubBytes)
|
||||||
|
|
||||||
|
kp, err := keypairs.Create(client, keypairs.CreateOpts{
|
||||||
|
Name: keyName,
|
||||||
|
PublicKey: pk,
|
||||||
|
}).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Created key pair: %s\n", kp)
|
||||||
|
|
||||||
|
choices, err := ComputeChoicesFromEnv()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
name := tools.RandomString("Gophercloud-", 8)
|
||||||
|
t.Logf("Creating server [%s] with key pair.", name)
|
||||||
|
|
||||||
|
serverCreateOpts := servers.CreateOpts{
|
||||||
|
Name: name,
|
||||||
|
FlavorRef: choices.FlavorID,
|
||||||
|
ImageRef: choices.ImageID,
|
||||||
|
}
|
||||||
|
|
||||||
|
server, err := servers.Create(client, keypairs.CreateOptsExt{
|
||||||
|
serverCreateOpts,
|
||||||
|
keyName,
|
||||||
|
}).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
defer servers.Delete(client, server.ID)
|
||||||
|
if err = waitForStatus(client, server, "ACTIVE"); err != nil {
|
||||||
|
t.Fatalf("Unable to wait for server: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
server, err = servers.Get(client, server.ID).Extract()
|
||||||
|
t.Logf("Created server: %+v\n", server)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
th.AssertEquals(t, server.KeyName, keyName)
|
||||||
|
|
||||||
|
t.Logf("Deleting key pair [%s]...", kp.Name)
|
||||||
|
err = keypairs.Delete(client, keyName).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Deleting server [%s]...", name)
|
||||||
|
}
|
72
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/secdefrules_test.go
generated
vendored
Normal file
72
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/secdefrules_test.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
// +build acceptance compute defsecrules
|
||||||
|
|
||||||
|
package v2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/acceptance/tools"
|
||||||
|
dsr "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/defsecrules"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSecDefRules(t *testing.T) {
|
||||||
|
client, err := newClient()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
id := createDefRule(t, client)
|
||||||
|
|
||||||
|
listDefRules(t, client)
|
||||||
|
|
||||||
|
getDefRule(t, client, id)
|
||||||
|
|
||||||
|
deleteDefRule(t, client, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createDefRule(t *testing.T, client *gophercloud.ServiceClient) string {
|
||||||
|
opts := dsr.CreateOpts{
|
||||||
|
FromPort: tools.RandomInt(80, 89),
|
||||||
|
ToPort: tools.RandomInt(90, 99),
|
||||||
|
IPProtocol: "TCP",
|
||||||
|
CIDR: "0.0.0.0/0",
|
||||||
|
}
|
||||||
|
|
||||||
|
rule, err := dsr.Create(client, opts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Created default rule %s", rule.ID)
|
||||||
|
|
||||||
|
return rule.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func listDefRules(t *testing.T, client *gophercloud.ServiceClient) {
|
||||||
|
err := dsr.List(client).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
drList, err := dsr.ExtractDefaultRules(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, dr := range drList {
|
||||||
|
t.Logf("Listing default rule %s: Name [%s] From Port [%s] To Port [%s] Protocol [%s]",
|
||||||
|
dr.ID, dr.FromPort, dr.ToPort, dr.IPProtocol)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDefRule(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
||||||
|
rule, err := dsr.Get(client, id).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Getting rule %s: %#v", id, rule)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteDefRule(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
||||||
|
err := dsr.Delete(client, id).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Deleted rule %s", id)
|
||||||
|
}
|
177
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/secgroup_test.go
generated
vendored
Normal file
177
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/secgroup_test.go
generated
vendored
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
// +build acceptance compute secgroups
|
||||||
|
|
||||||
|
package v2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/acceptance/tools"
|
||||||
|
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups"
|
||||||
|
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSecGroups(t *testing.T) {
|
||||||
|
client, err := newClient()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
serverID, needsDeletion := findServer(t, client)
|
||||||
|
|
||||||
|
groupID := createSecGroup(t, client)
|
||||||
|
|
||||||
|
listSecGroups(t, client)
|
||||||
|
|
||||||
|
newName := tools.RandomString("secgroup_", 5)
|
||||||
|
updateSecGroup(t, client, groupID, newName)
|
||||||
|
|
||||||
|
getSecGroup(t, client, groupID)
|
||||||
|
|
||||||
|
addRemoveRules(t, client, groupID)
|
||||||
|
|
||||||
|
addServerToSecGroup(t, client, serverID, newName)
|
||||||
|
|
||||||
|
removeServerFromSecGroup(t, client, serverID, newName)
|
||||||
|
|
||||||
|
if needsDeletion {
|
||||||
|
servers.Delete(client, serverID)
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteSecGroup(t, client, groupID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSecGroup(t *testing.T, client *gophercloud.ServiceClient) string {
|
||||||
|
opts := secgroups.CreateOpts{
|
||||||
|
Name: tools.RandomString("secgroup_", 5),
|
||||||
|
Description: "something",
|
||||||
|
}
|
||||||
|
|
||||||
|
group, err := secgroups.Create(client, opts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Created secgroup %s %s", group.ID, group.Name)
|
||||||
|
|
||||||
|
return group.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func listSecGroups(t *testing.T, client *gophercloud.ServiceClient) {
|
||||||
|
err := secgroups.List(client).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
secGrpList, err := secgroups.ExtractSecurityGroups(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, sg := range secGrpList {
|
||||||
|
t.Logf("Listing secgroup %s: Name [%s] Desc [%s] TenantID [%s]", sg.ID,
|
||||||
|
sg.Name, sg.Description, sg.TenantID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateSecGroup(t *testing.T, client *gophercloud.ServiceClient, id, newName string) {
|
||||||
|
opts := secgroups.UpdateOpts{
|
||||||
|
Name: newName,
|
||||||
|
Description: tools.RandomString("dec_", 10),
|
||||||
|
}
|
||||||
|
group, err := secgroups.Update(client, id, opts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Updated %s's name to %s", group.ID, group.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSecGroup(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
||||||
|
group, err := secgroups.Get(client, id).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Getting %s: %#v", id, group)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addRemoveRules(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
||||||
|
opts := secgroups.CreateRuleOpts{
|
||||||
|
ParentGroupID: id,
|
||||||
|
FromPort: 22,
|
||||||
|
ToPort: 22,
|
||||||
|
IPProtocol: "TCP",
|
||||||
|
CIDR: "0.0.0.0/0",
|
||||||
|
}
|
||||||
|
|
||||||
|
rule, err := secgroups.CreateRule(client, opts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Adding rule %s to group %s", rule.ID, id)
|
||||||
|
|
||||||
|
err = secgroups.DeleteRule(client, rule.ID).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Deleted rule %s from group %s", rule.ID, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func findServer(t *testing.T, client *gophercloud.ServiceClient) (string, bool) {
|
||||||
|
var serverID string
|
||||||
|
var needsDeletion bool
|
||||||
|
|
||||||
|
err := servers.List(client, nil).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
sList, err := servers.ExtractServers(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, s := range sList {
|
||||||
|
serverID = s.ID
|
||||||
|
needsDeletion = false
|
||||||
|
|
||||||
|
t.Logf("Found an existing server: ID [%s]", serverID)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
if serverID == "" {
|
||||||
|
t.Log("No server found, creating one")
|
||||||
|
|
||||||
|
choices, err := ComputeChoicesFromEnv()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
opts := &servers.CreateOpts{
|
||||||
|
Name: tools.RandomString("secgroup_test_", 5),
|
||||||
|
ImageRef: choices.ImageID,
|
||||||
|
FlavorRef: choices.FlavorID,
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := servers.Create(client, opts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
serverID = s.ID
|
||||||
|
|
||||||
|
t.Logf("Created server %s, waiting for it to build", s.ID)
|
||||||
|
err = servers.WaitForStatus(client, serverID, "ACTIVE", 300)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
needsDeletion = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return serverID, needsDeletion
|
||||||
|
}
|
||||||
|
|
||||||
|
func addServerToSecGroup(t *testing.T, client *gophercloud.ServiceClient, serverID, groupName string) {
|
||||||
|
err := secgroups.AddServerToGroup(client, serverID, groupName).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Adding group %s to server %s", groupName, serverID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeServerFromSecGroup(t *testing.T, client *gophercloud.ServiceClient, serverID, groupName string) {
|
||||||
|
err := secgroups.RemoveServerFromGroup(client, serverID, groupName).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Removing group %s from server %s", groupName, serverID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteSecGroup(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
||||||
|
err := secgroups.Delete(client, id).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Deleted group %s", id)
|
||||||
|
}
|
@@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
||||||
"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
|
"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestListServers(t *testing.T) {
|
func TestListServers(t *testing.T) {
|
||||||
@@ -94,6 +95,8 @@ func createServer(t *testing.T, client *gophercloud.ServiceClient, choices *Comp
|
|||||||
name := tools.RandomString("ACPTTEST", 16)
|
name := tools.RandomString("ACPTTEST", 16)
|
||||||
t.Logf("Attempting to create server: %s\n", name)
|
t.Logf("Attempting to create server: %s\n", name)
|
||||||
|
|
||||||
|
pwd := tools.MakeNewPassword("")
|
||||||
|
|
||||||
server, err := servers.Create(client, servers.CreateOpts{
|
server, err := servers.Create(client, servers.CreateOpts{
|
||||||
Name: name,
|
Name: name,
|
||||||
FlavorRef: choices.FlavorID,
|
FlavorRef: choices.FlavorID,
|
||||||
@@ -101,11 +104,14 @@ func createServer(t *testing.T, client *gophercloud.ServiceClient, choices *Comp
|
|||||||
Networks: []servers.Network{
|
Networks: []servers.Network{
|
||||||
servers.Network{UUID: network.ID},
|
servers.Network{UUID: network.ID},
|
||||||
},
|
},
|
||||||
|
AdminPass: pwd,
|
||||||
}).Extract()
|
}).Extract()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unable to create server: %v", err)
|
t.Fatalf("Unable to create server: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
th.AssertEquals(t, pwd, server.AdminPass)
|
||||||
|
|
||||||
return server, err
|
return server, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,3 +397,54 @@ func TestActionResizeRevert(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServerMetadata(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
choices, err := ComputeChoicesFromEnv()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
client, err := newClient()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unable to create a compute client: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
server, err := createServer(t, client, choices)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer servers.Delete(client, server.ID)
|
||||||
|
if err = waitForStatus(client, server, "ACTIVE"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata, err := servers.UpdateMetadata(client, server.ID, servers.MetadataOpts{
|
||||||
|
"foo": "bar",
|
||||||
|
"this": "that",
|
||||||
|
}).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("UpdateMetadata result: %+v\n", metadata)
|
||||||
|
|
||||||
|
err = servers.DeleteMetadatum(client, server.ID, "foo").ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
metadata, err = servers.CreateMetadatum(client, server.ID, servers.MetadatumOpts{
|
||||||
|
"foo": "baz",
|
||||||
|
}).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("CreateMetadatum result: %+v\n", metadata)
|
||||||
|
|
||||||
|
metadata, err = servers.Metadatum(client, server.ID, "foo").Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Metadatum result: %+v\n", metadata)
|
||||||
|
th.AssertEquals(t, "baz", metadata["foo"])
|
||||||
|
|
||||||
|
metadata, err = servers.Metadata(client, server.ID).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Metadata result: %+v\n", metadata)
|
||||||
|
|
||||||
|
metadata, err = servers.ResetMetadata(client, server.ID, servers.MetadataOpts{}).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("ResetMetadata result: %+v\n", metadata)
|
||||||
|
th.AssertDeepEquals(t, map[string]string{}, metadata)
|
||||||
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
// +build acceptance
|
// +build acceptance identity
|
||||||
|
|
||||||
package v2
|
package v2
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
// +build acceptance
|
// +build acceptance identity
|
||||||
|
|
||||||
package v2
|
package v2
|
||||||
|
|
||||||
|
58
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/openstack/identity/v2/role_test.go
generated
vendored
Normal file
58
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/openstack/identity/v2/role_test.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// +build acceptance identity roles
|
||||||
|
|
||||||
|
package v2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/openstack/identity/v2/extensions/admin/roles"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRoles(t *testing.T) {
|
||||||
|
client := authenticatedClient(t)
|
||||||
|
|
||||||
|
tenantID := findTenant(t, client)
|
||||||
|
userID := createUser(t, client, tenantID)
|
||||||
|
roleID := listRoles(t, client)
|
||||||
|
|
||||||
|
addUserRole(t, client, tenantID, userID, roleID)
|
||||||
|
|
||||||
|
deleteUserRole(t, client, tenantID, userID, roleID)
|
||||||
|
|
||||||
|
deleteUser(t, client, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listRoles(t *testing.T, client *gophercloud.ServiceClient) string {
|
||||||
|
var roleID string
|
||||||
|
|
||||||
|
err := roles.List(client).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
roleList, err := roles.ExtractRoles(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, role := range roleList {
|
||||||
|
t.Logf("Listing role: ID [%s] Name [%s]", role.ID, role.Name)
|
||||||
|
roleID = role.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
return roleID
|
||||||
|
}
|
||||||
|
|
||||||
|
func addUserRole(t *testing.T, client *gophercloud.ServiceClient, tenantID, userID, roleID string) {
|
||||||
|
err := roles.AddUserRole(client, tenantID, userID, roleID).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Added role %s to user %s", roleID, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteUserRole(t *testing.T, client *gophercloud.ServiceClient, tenantID, userID, roleID string) {
|
||||||
|
err := roles.DeleteUserRole(client, tenantID, userID, roleID).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Removed role %s from user %s", roleID, userID)
|
||||||
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
// +build acceptance
|
// +build acceptance identity
|
||||||
|
|
||||||
package v2
|
package v2
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
// +build acceptance
|
// +build acceptance identity
|
||||||
|
|
||||||
package v2
|
package v2
|
||||||
|
|
||||||
|
127
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/openstack/identity/v2/user_test.go
generated
vendored
Normal file
127
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/openstack/identity/v2/user_test.go
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
// +build acceptance identity
|
||||||
|
|
||||||
|
package v2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/acceptance/tools"
|
||||||
|
"github.com/rackspace/gophercloud/openstack/identity/v2/tenants"
|
||||||
|
"github.com/rackspace/gophercloud/openstack/identity/v2/users"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUsers(t *testing.T) {
|
||||||
|
client := authenticatedClient(t)
|
||||||
|
|
||||||
|
tenantID := findTenant(t, client)
|
||||||
|
|
||||||
|
userID := createUser(t, client, tenantID)
|
||||||
|
|
||||||
|
listUsers(t, client)
|
||||||
|
|
||||||
|
getUser(t, client, userID)
|
||||||
|
|
||||||
|
updateUser(t, client, userID)
|
||||||
|
|
||||||
|
listUserRoles(t, client, tenantID, userID)
|
||||||
|
|
||||||
|
deleteUser(t, client, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func findTenant(t *testing.T, client *gophercloud.ServiceClient) string {
|
||||||
|
var tenantID string
|
||||||
|
err := tenants.List(client, nil).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
tenantList, err := tenants.ExtractTenants(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, t := range tenantList {
|
||||||
|
tenantID = t.ID
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
return tenantID
|
||||||
|
}
|
||||||
|
|
||||||
|
func createUser(t *testing.T, client *gophercloud.ServiceClient, tenantID string) string {
|
||||||
|
t.Log("Creating user")
|
||||||
|
|
||||||
|
opts := users.CreateOpts{
|
||||||
|
Name: tools.RandomString("user_", 5),
|
||||||
|
Enabled: users.Disabled,
|
||||||
|
TenantID: tenantID,
|
||||||
|
Email: "new_user@foo.com",
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := users.Create(client, opts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Created user %s on tenant %s", user.ID, tenantID)
|
||||||
|
|
||||||
|
return user.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func listUsers(t *testing.T, client *gophercloud.ServiceClient) {
|
||||||
|
err := users.List(client).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
userList, err := users.ExtractUsers(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, user := range userList {
|
||||||
|
t.Logf("Listing user: ID [%s] Name [%s] Email [%s] Enabled? [%s]",
|
||||||
|
user.ID, user.Name, user.Email, strconv.FormatBool(user.Enabled))
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUser(t *testing.T, client *gophercloud.ServiceClient, userID string) {
|
||||||
|
_, err := users.Get(client, userID).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Getting user %s", userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateUser(t *testing.T, client *gophercloud.ServiceClient, userID string) {
|
||||||
|
opts := users.UpdateOpts{Name: tools.RandomString("new_name", 5), Email: "new@foo.com"}
|
||||||
|
user, err := users.Update(client, userID, opts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Updated user %s: Name [%s] Email [%s]", userID, user.Name, user.Email)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listUserRoles(t *testing.T, client *gophercloud.ServiceClient, tenantID, userID string) {
|
||||||
|
count := 0
|
||||||
|
err := users.ListRoles(client, tenantID, userID).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
count++
|
||||||
|
|
||||||
|
roleList, err := users.ExtractRoles(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Listing roles for user %s", userID)
|
||||||
|
|
||||||
|
for _, r := range roleList {
|
||||||
|
t.Logf("- %s (%s)", r.Name, r.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if count == 0 {
|
||||||
|
t.Logf("No roles for user %s", userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteUser(t *testing.T, client *gophercloud.ServiceClient, userID string) {
|
||||||
|
res := users.Delete(client, userID)
|
||||||
|
th.AssertNoErr(t, res.Err)
|
||||||
|
t.Logf("Deleted user %s", userID)
|
||||||
|
}
|
@@ -82,7 +82,7 @@ func listPorts(t *testing.T) {
|
|||||||
th.AssertNoErr(t, err)
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
for _, p := range portList {
|
for _, p := range portList {
|
||||||
t.Logf("Port: ID [%s] Name [%s] Status [%d] MAC addr [%s] Fixed IPs [%#v] Security groups [%#v]",
|
t.Logf("Port: ID [%s] Name [%s] Status [%s] MAC addr [%s] Fixed IPs [%#v] Security groups [%#v]",
|
||||||
p.ID, p.Name, p.Status, p.MACAddress, p.FixedIPs, p.SecurityGroups)
|
p.ID, p.Name, p.Status, p.MACAddress, p.FixedIPs, p.SecurityGroups)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -17,7 +17,10 @@ func TestAccounts(t *testing.T) {
|
|||||||
|
|
||||||
// Update an account's metadata.
|
// Update an account's metadata.
|
||||||
updateres := accounts.Update(client, accounts.UpdateOpts{Metadata: metadata})
|
updateres := accounts.Update(client, accounts.UpdateOpts{Metadata: metadata})
|
||||||
th.AssertNoErr(t, updateres.Err)
|
t.Logf("Update Account Response: %+v\n", updateres)
|
||||||
|
updateHeaders, err := updateres.Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Update Account Response Headers: %+v\n", updateHeaders)
|
||||||
|
|
||||||
// Defer the deletion of the metadata set above.
|
// Defer the deletion of the metadata set above.
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -29,11 +32,14 @@ func TestAccounts(t *testing.T) {
|
|||||||
th.AssertNoErr(t, updateres.Err)
|
th.AssertNoErr(t, updateres.Err)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Retrieve account metadata.
|
|
||||||
getres := accounts.Get(client, nil)
|
|
||||||
th.AssertNoErr(t, getres.Err)
|
|
||||||
// Extract the custom metadata from the 'Get' response.
|
// Extract the custom metadata from the 'Get' response.
|
||||||
am, err := getres.ExtractMetadata()
|
res := accounts.Get(client, nil)
|
||||||
|
|
||||||
|
h, err := res.Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Get Account Response Headers: %+v\n", h)
|
||||||
|
|
||||||
|
am, err := res.ExtractMetadata()
|
||||||
th.AssertNoErr(t, err)
|
th.AssertNoErr(t, err)
|
||||||
for k := range metadata {
|
for k := range metadata {
|
||||||
if am[k] != metadata[strings.Title(k)] {
|
if am[k] != metadata[strings.Title(k)] {
|
||||||
|
32
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/cdn/v1/base_test.go
generated
vendored
Normal file
32
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/cdn/v1/base_test.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// +build acceptance
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/cdn/v1/base"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBaseOps(t *testing.T) {
|
||||||
|
client := newClient(t)
|
||||||
|
t.Log("Retrieving Home Document")
|
||||||
|
testHomeDocumentGet(t, client)
|
||||||
|
|
||||||
|
t.Log("Pinging root URL")
|
||||||
|
testPing(t, client)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testHomeDocumentGet(t *testing.T, client *gophercloud.ServiceClient) {
|
||||||
|
hd, err := base.Get(client).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Retrieved home document: %+v", *hd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testPing(t *testing.T, client *gophercloud.ServiceClient) {
|
||||||
|
err := base.Ping(client).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Successfully pinged root URL")
|
||||||
|
}
|
23
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/cdn/v1/common.go
generated
vendored
Normal file
23
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/cdn/v1/common.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// +build acceptance
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newClient(t *testing.T) *gophercloud.ServiceClient {
|
||||||
|
ao, err := rackspace.AuthOptionsFromEnv()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
client, err := rackspace.AuthenticatedClient(ao)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
c, err := rackspace.NewCDNV1(client, gophercloud.EndpointOpts{})
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
return c
|
||||||
|
}
|
47
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/cdn/v1/flavor_test.go
generated
vendored
Normal file
47
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/cdn/v1/flavor_test.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// +build acceptance
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
os "github.com/rackspace/gophercloud/openstack/cdn/v1/flavors"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/cdn/v1/flavors"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFlavor(t *testing.T) {
|
||||||
|
client := newClient(t)
|
||||||
|
|
||||||
|
t.Log("Listing Flavors")
|
||||||
|
id := testFlavorsList(t, client)
|
||||||
|
|
||||||
|
t.Log("Retrieving Flavor")
|
||||||
|
testFlavorGet(t, client, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testFlavorsList(t *testing.T, client *gophercloud.ServiceClient) string {
|
||||||
|
var id string
|
||||||
|
err := flavors.List(client).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
flavorList, err := os.ExtractFlavors(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, flavor := range flavorList {
|
||||||
|
t.Logf("Listing flavor: ID [%s] Providers [%+v]", flavor.ID, flavor.Providers)
|
||||||
|
id = flavor.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
func testFlavorGet(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
||||||
|
flavor, err := flavors.Get(client, id).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Retrieved Flavor: %+v", *flavor)
|
||||||
|
}
|
93
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/cdn/v1/service_test.go
generated
vendored
Normal file
93
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/cdn/v1/service_test.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
// +build acceptance
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
os "github.com/rackspace/gophercloud/openstack/cdn/v1/services"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/cdn/v1/services"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestService(t *testing.T) {
|
||||||
|
client := newClient(t)
|
||||||
|
|
||||||
|
t.Log("Creating Service")
|
||||||
|
loc := testServiceCreate(t, client, "test-site-1")
|
||||||
|
t.Logf("Created service at location: %s", loc)
|
||||||
|
|
||||||
|
defer testServiceDelete(t, client, loc)
|
||||||
|
|
||||||
|
t.Log("Updating Service")
|
||||||
|
testServiceUpdate(t, client, loc)
|
||||||
|
|
||||||
|
t.Log("Retrieving Service")
|
||||||
|
testServiceGet(t, client, loc)
|
||||||
|
|
||||||
|
t.Log("Listing Services")
|
||||||
|
testServiceList(t, client)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testServiceCreate(t *testing.T, client *gophercloud.ServiceClient, name string) string {
|
||||||
|
createOpts := os.CreateOpts{
|
||||||
|
Name: name,
|
||||||
|
Domains: []os.Domain{
|
||||||
|
os.Domain{
|
||||||
|
Domain: "www." + name + ".com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Origins: []os.Origin{
|
||||||
|
os.Origin{
|
||||||
|
Origin: name + ".com",
|
||||||
|
Port: 80,
|
||||||
|
SSL: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
FlavorID: "cdn",
|
||||||
|
}
|
||||||
|
l, err := services.Create(client, createOpts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
func testServiceGet(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
||||||
|
s, err := services.Get(client, id).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Retrieved service: %+v", *s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testServiceUpdate(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
||||||
|
opts := os.UpdateOpts{
|
||||||
|
os.Append{
|
||||||
|
Value: os.Domain{Domain: "newDomain.com", Protocol: "http"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
loc, err := services.Update(client, id, opts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Successfully updated service at location: %s", loc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testServiceList(t *testing.T, client *gophercloud.ServiceClient) {
|
||||||
|
err := services.List(client, nil).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
serviceList, err := os.ExtractServices(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, service := range serviceList {
|
||||||
|
t.Logf("Listing service: %+v", service)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testServiceDelete(t *testing.T, client *gophercloud.ServiceClient, id string) {
|
||||||
|
err := services.Delete(client, id).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Successfully deleted service (%s)", id)
|
||||||
|
}
|
32
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/cdn/v1/serviceasset_test.go
generated
vendored
Normal file
32
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/cdn/v1/serviceasset_test.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// +build acceptance
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
osServiceAssets "github.com/rackspace/gophercloud/openstack/cdn/v1/serviceassets"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/cdn/v1/serviceassets"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestServiceAsset(t *testing.T) {
|
||||||
|
client := newClient(t)
|
||||||
|
|
||||||
|
t.Log("Creating Service")
|
||||||
|
loc := testServiceCreate(t, client, "test-site-2")
|
||||||
|
t.Logf("Created service at location: %s", loc)
|
||||||
|
|
||||||
|
t.Log("Deleting Service Assets")
|
||||||
|
testServiceAssetDelete(t, client, loc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testServiceAssetDelete(t *testing.T, client *gophercloud.ServiceClient, url string) {
|
||||||
|
deleteOpts := osServiceAssets.DeleteOpts{
|
||||||
|
All: true,
|
||||||
|
}
|
||||||
|
err := serviceassets.Delete(client, url, deleteOpts).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Log("Successfully deleted all Service Assets")
|
||||||
|
}
|
@@ -5,11 +5,11 @@ package v2
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud/acceptance/tools"
|
||||||
osBFV "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume"
|
osBFV "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume"
|
||||||
"github.com/rackspace/gophercloud/rackspace/compute/v2/bootfromvolume"
|
"github.com/rackspace/gophercloud/rackspace/compute/v2/bootfromvolume"
|
||||||
"github.com/rackspace/gophercloud/rackspace/compute/v2/servers"
|
"github.com/rackspace/gophercloud/rackspace/compute/v2/servers"
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
"github.com/smashwilson/gophercloud/acceptance/tools"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBootFromVolume(t *testing.T) {
|
func TestBootFromVolume(t *testing.T) {
|
||||||
@@ -41,6 +41,9 @@ func TestBootFromVolume(t *testing.T) {
|
|||||||
}).Extract()
|
}).Extract()
|
||||||
th.AssertNoErr(t, err)
|
th.AssertNoErr(t, err)
|
||||||
t.Logf("Created server: %+v\n", server)
|
t.Logf("Created server: %+v\n", server)
|
||||||
//defer deleteServer(t, client, server)
|
defer deleteServer(t, client, server)
|
||||||
t.Logf("Deleting server [%s]...", name)
|
|
||||||
|
getServer(t, client, server)
|
||||||
|
|
||||||
|
listServers(t, client)
|
||||||
}
|
}
|
||||||
|
@@ -39,11 +39,14 @@ func createServer(t *testing.T, client *gophercloud.ServiceClient, keyName strin
|
|||||||
|
|
||||||
name := tools.RandomString("Gophercloud-", 8)
|
name := tools.RandomString("Gophercloud-", 8)
|
||||||
|
|
||||||
|
pwd := tools.MakeNewPassword("")
|
||||||
|
|
||||||
opts := &servers.CreateOpts{
|
opts := &servers.CreateOpts{
|
||||||
Name: name,
|
Name: name,
|
||||||
ImageRef: options.imageID,
|
ImageRef: options.imageID,
|
||||||
FlavorRef: options.flavorID,
|
FlavorRef: options.flavorID,
|
||||||
DiskConfig: diskconfig.Manual,
|
DiskConfig: diskconfig.Manual,
|
||||||
|
AdminPass: pwd,
|
||||||
}
|
}
|
||||||
|
|
||||||
if keyName != "" {
|
if keyName != "" {
|
||||||
@@ -59,6 +62,8 @@ func createServer(t *testing.T, client *gophercloud.ServiceClient, keyName strin
|
|||||||
th.AssertNoErr(t, err)
|
th.AssertNoErr(t, err)
|
||||||
t.Logf("Server created successfully.")
|
t.Logf("Server created successfully.")
|
||||||
|
|
||||||
|
th.CheckEquals(t, pwd, s.AdminPass)
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,6 +100,18 @@ func getServer(t *testing.T, client *gophercloud.ServiceClient, server *os.Serve
|
|||||||
logServer(t, details, -1)
|
logServer(t, details, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateServer(t *testing.T, client *gophercloud.ServiceClient, server *os.Server) {
|
||||||
|
t.Logf("> servers.Get")
|
||||||
|
|
||||||
|
opts := os.UpdateOpts{
|
||||||
|
Name: "updated-server",
|
||||||
|
}
|
||||||
|
updatedServer, err := servers.Update(client, server.ID, opts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
th.AssertEquals(t, "updated-server", updatedServer.Name)
|
||||||
|
logServer(t, updatedServer, -1)
|
||||||
|
}
|
||||||
|
|
||||||
func listServers(t *testing.T, client *gophercloud.ServiceClient) {
|
func listServers(t *testing.T, client *gophercloud.ServiceClient) {
|
||||||
t.Logf("> servers.List")
|
t.Logf("> servers.List")
|
||||||
|
|
||||||
@@ -120,7 +137,7 @@ func changeAdminPassword(t *testing.T, client *gophercloud.ServiceClient, server
|
|||||||
original := server.AdminPass
|
original := server.AdminPass
|
||||||
|
|
||||||
t.Logf("Changing server password.")
|
t.Logf("Changing server password.")
|
||||||
err := servers.ChangeAdminPassword(client, server.ID, tools.MakeNewPassword(original)).Extract()
|
err := servers.ChangeAdminPassword(client, server.ID, tools.MakeNewPassword(original)).ExtractErr()
|
||||||
th.AssertNoErr(t, err)
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
err = servers.WaitForStatus(client, server.ID, "ACTIVE", 300)
|
err = servers.WaitForStatus(client, server.ID, "ACTIVE", 300)
|
||||||
@@ -131,7 +148,7 @@ func changeAdminPassword(t *testing.T, client *gophercloud.ServiceClient, server
|
|||||||
func rebootServer(t *testing.T, client *gophercloud.ServiceClient, server *os.Server) {
|
func rebootServer(t *testing.T, client *gophercloud.ServiceClient, server *os.Server) {
|
||||||
t.Logf("> servers.Reboot")
|
t.Logf("> servers.Reboot")
|
||||||
|
|
||||||
err := servers.Reboot(client, server.ID, os.HardReboot).Extract()
|
err := servers.Reboot(client, server.ID, os.HardReboot).ExtractErr()
|
||||||
th.AssertNoErr(t, err)
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
err = servers.WaitForStatus(client, server.ID, "ACTIVE", 300)
|
err = servers.WaitForStatus(client, server.ID, "ACTIVE", 300)
|
||||||
@@ -192,6 +209,7 @@ func TestServerOperations(t *testing.T) {
|
|||||||
defer deleteServer(t, client, server)
|
defer deleteServer(t, client, server)
|
||||||
|
|
||||||
getServer(t, client, server)
|
getServer(t, client, server)
|
||||||
|
updateServer(t, client, server)
|
||||||
listServers(t, client)
|
listServers(t, client)
|
||||||
changeAdminPassword(t, client, server)
|
changeAdminPassword(t, client, server)
|
||||||
rebootServer(t, client, server)
|
rebootServer(t, client, server)
|
||||||
|
1
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/identity/v2/pkg.go
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/identity/v2/pkg.go
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package v2
|
59
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/identity/v2/role_test.go
generated
vendored
Normal file
59
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/identity/v2/role_test.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// +build acceptance identity roles
|
||||||
|
|
||||||
|
package v2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
os "github.com/rackspace/gophercloud/openstack/identity/v2/extensions/admin/roles"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/identity/v2/roles"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRoles(t *testing.T) {
|
||||||
|
client := authenticatedClient(t)
|
||||||
|
|
||||||
|
userID := createUser(t, client)
|
||||||
|
roleID := listRoles(t, client)
|
||||||
|
|
||||||
|
addUserRole(t, client, userID, roleID)
|
||||||
|
|
||||||
|
deleteUserRole(t, client, userID, roleID)
|
||||||
|
|
||||||
|
deleteUser(t, client, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listRoles(t *testing.T, client *gophercloud.ServiceClient) string {
|
||||||
|
var roleID string
|
||||||
|
|
||||||
|
err := roles.List(client).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
roleList, err := os.ExtractRoles(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, role := range roleList {
|
||||||
|
t.Logf("Listing role: ID [%s] Name [%s]", role.ID, role.Name)
|
||||||
|
roleID = role.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
return roleID
|
||||||
|
}
|
||||||
|
|
||||||
|
func addUserRole(t *testing.T, client *gophercloud.ServiceClient, userID, roleID string) {
|
||||||
|
err := roles.AddUserRole(client, userID, roleID).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Added role %s to user %s", roleID, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteUserRole(t *testing.T, client *gophercloud.ServiceClient, userID, roleID string) {
|
||||||
|
err := roles.DeleteUserRole(client, userID, roleID).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Removed role %s from user %s", roleID, userID)
|
||||||
|
}
|
93
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/identity/v2/user_test.go
generated
vendored
Normal file
93
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/identity/v2/user_test.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
// +build acceptance identity
|
||||||
|
|
||||||
|
package v2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/acceptance/tools"
|
||||||
|
os "github.com/rackspace/gophercloud/openstack/identity/v2/users"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/identity/v2/users"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUsers(t *testing.T) {
|
||||||
|
client := authenticatedClient(t)
|
||||||
|
|
||||||
|
userID := createUser(t, client)
|
||||||
|
|
||||||
|
listUsers(t, client)
|
||||||
|
|
||||||
|
getUser(t, client, userID)
|
||||||
|
|
||||||
|
updateUser(t, client, userID)
|
||||||
|
|
||||||
|
resetApiKey(t, client, userID)
|
||||||
|
|
||||||
|
deleteUser(t, client, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createUser(t *testing.T, client *gophercloud.ServiceClient) string {
|
||||||
|
t.Log("Creating user")
|
||||||
|
|
||||||
|
opts := users.CreateOpts{
|
||||||
|
Username: tools.RandomString("user_", 5),
|
||||||
|
Enabled: os.Disabled,
|
||||||
|
Email: "new_user@foo.com",
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := users.Create(client, opts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Created user %s", user.ID)
|
||||||
|
|
||||||
|
return user.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func listUsers(t *testing.T, client *gophercloud.ServiceClient) {
|
||||||
|
err := users.List(client).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
userList, err := os.ExtractUsers(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, user := range userList {
|
||||||
|
t.Logf("Listing user: ID [%s] Username [%s] Email [%s] Enabled? [%s]",
|
||||||
|
user.ID, user.Username, user.Email, strconv.FormatBool(user.Enabled))
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUser(t *testing.T, client *gophercloud.ServiceClient, userID string) {
|
||||||
|
_, err := users.Get(client, userID).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Getting user %s", userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateUser(t *testing.T, client *gophercloud.ServiceClient, userID string) {
|
||||||
|
opts := users.UpdateOpts{Username: tools.RandomString("new_name", 5), Email: "new@foo.com"}
|
||||||
|
user, err := users.Update(client, userID, opts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Updated user %s: Username [%s] Email [%s]", userID, user.Username, user.Email)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteUser(t *testing.T, client *gophercloud.ServiceClient, userID string) {
|
||||||
|
res := users.Delete(client, userID)
|
||||||
|
th.AssertNoErr(t, res.Err)
|
||||||
|
t.Logf("Deleted user %s", userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resetApiKey(t *testing.T, client *gophercloud.ServiceClient, userID string) {
|
||||||
|
key, err := users.ResetAPIKey(client, userID).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
if key.APIKey == "" {
|
||||||
|
t.Fatal("failed to reset API key for user")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Reset API key for user %s to %s", key.Username, key.APIKey)
|
||||||
|
}
|
94
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/lb/v1/acl_test.go
generated
vendored
Normal file
94
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/lb/v1/acl_test.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
// +build acceptance lbs
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/lb/v1/acl"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/lb/v1/lbs"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestACL(t *testing.T) {
|
||||||
|
client := setup(t)
|
||||||
|
|
||||||
|
ids := createLB(t, client, 1)
|
||||||
|
lbID := ids[0]
|
||||||
|
|
||||||
|
createACL(t, client, lbID)
|
||||||
|
|
||||||
|
waitForLB(client, lbID, lbs.ACTIVE)
|
||||||
|
|
||||||
|
networkIDs := showACL(t, client, lbID)
|
||||||
|
|
||||||
|
deleteNetworkItem(t, client, lbID, networkIDs[0])
|
||||||
|
waitForLB(client, lbID, lbs.ACTIVE)
|
||||||
|
|
||||||
|
bulkDeleteACL(t, client, lbID, networkIDs[1:2])
|
||||||
|
waitForLB(client, lbID, lbs.ACTIVE)
|
||||||
|
|
||||||
|
deleteACL(t, client, lbID)
|
||||||
|
waitForLB(client, lbID, lbs.ACTIVE)
|
||||||
|
|
||||||
|
deleteLB(t, client, lbID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createACL(t *testing.T, client *gophercloud.ServiceClient, lbID int) {
|
||||||
|
opts := acl.CreateOpts{
|
||||||
|
acl.CreateOpt{Address: "206.160.163.21", Type: acl.DENY},
|
||||||
|
acl.CreateOpt{Address: "206.160.165.11", Type: acl.DENY},
|
||||||
|
acl.CreateOpt{Address: "206.160.165.12", Type: acl.DENY},
|
||||||
|
acl.CreateOpt{Address: "206.160.165.13", Type: acl.ALLOW},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := acl.Create(client, lbID, opts).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Created ACL items for LB %d", lbID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func showACL(t *testing.T, client *gophercloud.ServiceClient, lbID int) []int {
|
||||||
|
ids := []int{}
|
||||||
|
|
||||||
|
err := acl.List(client, lbID).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
accessList, err := acl.ExtractAccessList(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, i := range accessList {
|
||||||
|
t.Logf("Listing network item: ID [%s] Address [%s] Type [%s]", i.ID, i.Address, i.Type)
|
||||||
|
ids = append(ids, i.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
return ids
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteNetworkItem(t *testing.T, client *gophercloud.ServiceClient, lbID, itemID int) {
|
||||||
|
err := acl.Delete(client, lbID, itemID).ExtractErr()
|
||||||
|
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Deleted network item %d", itemID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func bulkDeleteACL(t *testing.T, client *gophercloud.ServiceClient, lbID int, items []int) {
|
||||||
|
err := acl.BulkDelete(client, lbID, items).ExtractErr()
|
||||||
|
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Deleted network items %s", intsToStr(items))
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteACL(t *testing.T, client *gophercloud.ServiceClient, lbID int) {
|
||||||
|
err := acl.DeleteAll(client, lbID).ExtractErr()
|
||||||
|
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Deleted ACL from LB %d", lbID)
|
||||||
|
}
|
62
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/lb/v1/common.go
generated
vendored
Normal file
62
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/lb/v1/common.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// +build acceptance lbs
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/acceptance/tools"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newProvider() (*gophercloud.ProviderClient, error) {
|
||||||
|
opts, err := rackspace.AuthOptionsFromEnv()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
opts = tools.OnlyRS(opts)
|
||||||
|
|
||||||
|
return rackspace.AuthenticatedClient(opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newClient() (*gophercloud.ServiceClient, error) {
|
||||||
|
provider, err := newProvider()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rackspace.NewLBV1(provider, gophercloud.EndpointOpts{
|
||||||
|
Region: os.Getenv("RS_REGION"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func newComputeClient() (*gophercloud.ServiceClient, error) {
|
||||||
|
provider, err := newProvider()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rackspace.NewComputeV2(provider, gophercloud.EndpointOpts{
|
||||||
|
Region: os.Getenv("RS_REGION"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func setup(t *testing.T) *gophercloud.ServiceClient {
|
||||||
|
client, err := newClient()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
func intsToStr(ids []int) string {
|
||||||
|
strIDs := []string{}
|
||||||
|
for _, id := range ids {
|
||||||
|
strIDs = append(strIDs, strconv.Itoa(id))
|
||||||
|
}
|
||||||
|
return strings.Join(strIDs, ", ")
|
||||||
|
}
|
214
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/lb/v1/lb_test.go
generated
vendored
Normal file
214
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/lb/v1/lb_test.go
generated
vendored
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
// +build acceptance lbs
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/acceptance/tools"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/lb/v1/lbs"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/lb/v1/vips"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLBs(t *testing.T) {
|
||||||
|
client := setup(t)
|
||||||
|
|
||||||
|
ids := createLB(t, client, 3)
|
||||||
|
id := ids[0]
|
||||||
|
|
||||||
|
listLBProtocols(t, client)
|
||||||
|
|
||||||
|
listLBAlgorithms(t, client)
|
||||||
|
|
||||||
|
listLBs(t, client)
|
||||||
|
|
||||||
|
getLB(t, client, id)
|
||||||
|
|
||||||
|
checkLBLogging(t, client, id)
|
||||||
|
|
||||||
|
checkErrorPage(t, client, id)
|
||||||
|
|
||||||
|
getStats(t, client, id)
|
||||||
|
|
||||||
|
updateLB(t, client, id)
|
||||||
|
|
||||||
|
deleteLB(t, client, id)
|
||||||
|
|
||||||
|
batchDeleteLBs(t, client, ids[1:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func createLB(t *testing.T, client *gophercloud.ServiceClient, count int) []int {
|
||||||
|
ids := []int{}
|
||||||
|
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
opts := lbs.CreateOpts{
|
||||||
|
Name: tools.RandomString("test_", 5),
|
||||||
|
Port: 80,
|
||||||
|
Protocol: "HTTP",
|
||||||
|
VIPs: []vips.VIP{
|
||||||
|
vips.VIP{Type: vips.PUBLIC},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
lb, err := lbs.Create(client, opts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Created LB %d - waiting for it to build...", lb.ID)
|
||||||
|
waitForLB(client, lb.ID, lbs.ACTIVE)
|
||||||
|
t.Logf("LB %d has reached ACTIVE state", lb.ID)
|
||||||
|
|
||||||
|
ids = append(ids, lb.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForLB(client *gophercloud.ServiceClient, id int, state lbs.Status) {
|
||||||
|
gophercloud.WaitFor(60, func() (bool, error) {
|
||||||
|
lb, err := lbs.Get(client, id).Extract()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if lb.Status != state {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func listLBProtocols(t *testing.T, client *gophercloud.ServiceClient) {
|
||||||
|
err := lbs.ListProtocols(client).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
pList, err := lbs.ExtractProtocols(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, p := range pList {
|
||||||
|
t.Logf("Listing protocol: Name [%s]", p.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listLBAlgorithms(t *testing.T, client *gophercloud.ServiceClient) {
|
||||||
|
err := lbs.ListAlgorithms(client).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
aList, err := lbs.ExtractAlgorithms(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, a := range aList {
|
||||||
|
t.Logf("Listing algorithm: Name [%s]", a.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listLBs(t *testing.T, client *gophercloud.ServiceClient) {
|
||||||
|
err := lbs.List(client, lbs.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
lbList, err := lbs.ExtractLBs(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, lb := range lbList {
|
||||||
|
t.Logf("Listing LB: ID [%d] Name [%s] Protocol [%s] Status [%s] Node count [%d] Port [%d]",
|
||||||
|
lb.ID, lb.Name, lb.Protocol, lb.Status, lb.NodeCount, lb.Port)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLB(t *testing.T, client *gophercloud.ServiceClient, id int) {
|
||||||
|
lb, err := lbs.Get(client, id).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Getting LB %d: Created [%s] VIPs [%#v] Logging [%#v] Persistence [%#v] SourceAddrs [%#v]",
|
||||||
|
lb.ID, lb.Created, lb.VIPs, lb.ConnectionLogging, lb.SessionPersistence, lb.SourceAddrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateLB(t *testing.T, client *gophercloud.ServiceClient, id int) {
|
||||||
|
opts := lbs.UpdateOpts{
|
||||||
|
Name: tools.RandomString("new_", 5),
|
||||||
|
Protocol: "TCP",
|
||||||
|
HalfClosed: gophercloud.Enabled,
|
||||||
|
Algorithm: "RANDOM",
|
||||||
|
Port: 8080,
|
||||||
|
Timeout: 100,
|
||||||
|
HTTPSRedirect: gophercloud.Disabled,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := lbs.Update(client, id, opts).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Updating LB %d - waiting for it to finish", id)
|
||||||
|
waitForLB(client, id, lbs.ACTIVE)
|
||||||
|
t.Logf("LB %d has reached ACTIVE state", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteLB(t *testing.T, client *gophercloud.ServiceClient, id int) {
|
||||||
|
err := lbs.Delete(client, id).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Deleted LB %d", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func batchDeleteLBs(t *testing.T, client *gophercloud.ServiceClient, ids []int) {
|
||||||
|
err := lbs.BulkDelete(client, ids).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Deleted LB %s", intsToStr(ids))
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkLBLogging(t *testing.T, client *gophercloud.ServiceClient, id int) {
|
||||||
|
err := lbs.EnableLogging(client, id).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Enabled logging for LB %d", id)
|
||||||
|
|
||||||
|
res, err := lbs.IsLoggingEnabled(client, id)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("LB %d log enabled? %s", id, strconv.FormatBool(res))
|
||||||
|
|
||||||
|
waitForLB(client, id, lbs.ACTIVE)
|
||||||
|
|
||||||
|
err = lbs.DisableLogging(client, id).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Disabled logging for LB %d", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkErrorPage(t *testing.T, client *gophercloud.ServiceClient, id int) {
|
||||||
|
content, err := lbs.SetErrorPage(client, id, "<html>New content!</html>").Extract()
|
||||||
|
t.Logf("Set error page for LB %d", id)
|
||||||
|
|
||||||
|
content, err = lbs.GetErrorPage(client, id).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Error page for LB %d: %s", id, content)
|
||||||
|
|
||||||
|
err = lbs.DeleteErrorPage(client, id).ExtractErr()
|
||||||
|
t.Logf("Deleted error page for LB %d", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getStats(t *testing.T, client *gophercloud.ServiceClient, id int) {
|
||||||
|
waitForLB(client, id, lbs.ACTIVE)
|
||||||
|
|
||||||
|
stats, err := lbs.GetStats(client, id).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Stats for LB %d: %#v", id, stats)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkCaching(t *testing.T, client *gophercloud.ServiceClient, id int) {
|
||||||
|
err := lbs.EnableCaching(client, id).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Enabled caching for LB %d", id)
|
||||||
|
|
||||||
|
res, err := lbs.IsContentCached(client, id)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Is caching enabled for LB? %s", strconv.FormatBool(res))
|
||||||
|
|
||||||
|
err = lbs.DisableCaching(client, id).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Disabled caching for LB %d", id)
|
||||||
|
}
|
60
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/lb/v1/monitor_test.go
generated
vendored
Normal file
60
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/lb/v1/monitor_test.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
// +build acceptance lbs
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/lb/v1/lbs"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/lb/v1/monitors"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMonitors(t *testing.T) {
|
||||||
|
client := setup(t)
|
||||||
|
|
||||||
|
ids := createLB(t, client, 1)
|
||||||
|
lbID := ids[0]
|
||||||
|
|
||||||
|
getMonitor(t, client, lbID)
|
||||||
|
|
||||||
|
updateMonitor(t, client, lbID)
|
||||||
|
|
||||||
|
deleteMonitor(t, client, lbID)
|
||||||
|
|
||||||
|
deleteLB(t, client, lbID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMonitor(t *testing.T, client *gophercloud.ServiceClient, lbID int) {
|
||||||
|
hm, err := monitors.Get(client, lbID).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Health monitor for LB %d: Type [%s] Delay [%d] Timeout [%d] AttemptLimit [%d]",
|
||||||
|
lbID, hm.Type, hm.Delay, hm.Timeout, hm.AttemptLimit)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateMonitor(t *testing.T, client *gophercloud.ServiceClient, lbID int) {
|
||||||
|
opts := monitors.UpdateHTTPMonitorOpts{
|
||||||
|
AttemptLimit: 3,
|
||||||
|
Delay: 10,
|
||||||
|
Timeout: 10,
|
||||||
|
BodyRegex: "hello is it me you're looking for",
|
||||||
|
Path: "/foo",
|
||||||
|
StatusRegex: "200",
|
||||||
|
Type: monitors.HTTP,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := monitors.Update(client, lbID, opts).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
waitForLB(client, lbID, lbs.ACTIVE)
|
||||||
|
t.Logf("Updated monitor for LB %d", lbID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteMonitor(t *testing.T, client *gophercloud.ServiceClient, lbID int) {
|
||||||
|
err := monitors.Delete(client, lbID).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
waitForLB(client, lbID, lbs.ACTIVE)
|
||||||
|
t.Logf("Deleted monitor for LB %d", lbID)
|
||||||
|
}
|
175
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/lb/v1/node_test.go
generated
vendored
Normal file
175
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/lb/v1/node_test.go
generated
vendored
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
// +build acceptance lbs
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/acceptance/tools"
|
||||||
|
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/diskconfig"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/compute/v2/servers"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/lb/v1/lbs"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/lb/v1/nodes"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNodes(t *testing.T) {
|
||||||
|
client := setup(t)
|
||||||
|
|
||||||
|
serverIP := findServer(t)
|
||||||
|
ids := createLB(t, client, 1)
|
||||||
|
lbID := ids[0]
|
||||||
|
|
||||||
|
nodeID := addNodes(t, client, lbID, serverIP)
|
||||||
|
|
||||||
|
listNodes(t, client, lbID)
|
||||||
|
|
||||||
|
getNode(t, client, lbID, nodeID)
|
||||||
|
|
||||||
|
updateNode(t, client, lbID, nodeID)
|
||||||
|
|
||||||
|
listEvents(t, client, lbID)
|
||||||
|
|
||||||
|
deleteNode(t, client, lbID, nodeID)
|
||||||
|
|
||||||
|
waitForLB(client, lbID, lbs.ACTIVE)
|
||||||
|
deleteLB(t, client, lbID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func findServer(t *testing.T) string {
|
||||||
|
var serverIP string
|
||||||
|
|
||||||
|
client, err := newComputeClient()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
err = servers.List(client, nil).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
sList, err := servers.ExtractServers(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, s := range sList {
|
||||||
|
serverIP = s.AccessIPv4
|
||||||
|
t.Logf("Found an existing server: ID [%s] Public IP [%s]", s.ID, serverIP)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
if serverIP == "" {
|
||||||
|
t.Log("No server found, creating one")
|
||||||
|
|
||||||
|
imageRef := os.Getenv("RS_IMAGE_ID")
|
||||||
|
if imageRef == "" {
|
||||||
|
t.Fatalf("OS var RS_IMAGE_ID undefined")
|
||||||
|
}
|
||||||
|
flavorRef := os.Getenv("RS_FLAVOR_ID")
|
||||||
|
if flavorRef == "" {
|
||||||
|
t.Fatalf("OS var RS_FLAVOR_ID undefined")
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := &servers.CreateOpts{
|
||||||
|
Name: tools.RandomString("lb_test_", 5),
|
||||||
|
ImageRef: imageRef,
|
||||||
|
FlavorRef: flavorRef,
|
||||||
|
DiskConfig: diskconfig.Manual,
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := servers.Create(client, opts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
serverIP = s.AccessIPv4
|
||||||
|
|
||||||
|
t.Logf("Created server %s, waiting for it to build", s.ID)
|
||||||
|
err = servers.WaitForStatus(client, s.ID, "ACTIVE", 300)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Server created successfully.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return serverIP
|
||||||
|
}
|
||||||
|
|
||||||
|
func addNodes(t *testing.T, client *gophercloud.ServiceClient, lbID int, serverIP string) int {
|
||||||
|
opts := nodes.CreateOpts{
|
||||||
|
nodes.CreateOpt{
|
||||||
|
Address: serverIP,
|
||||||
|
Port: 80,
|
||||||
|
Condition: nodes.ENABLED,
|
||||||
|
Type: nodes.PRIMARY,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
page := nodes.Create(client, lbID, opts)
|
||||||
|
|
||||||
|
nodeList, err := page.ExtractNodes()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
var nodeID int
|
||||||
|
for _, n := range nodeList {
|
||||||
|
nodeID = n.ID
|
||||||
|
}
|
||||||
|
if nodeID == 0 {
|
||||||
|
t.Fatalf("nodeID could not be extracted from create response")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Added node %d to LB %d", nodeID, lbID)
|
||||||
|
waitForLB(client, lbID, lbs.ACTIVE)
|
||||||
|
|
||||||
|
return nodeID
|
||||||
|
}
|
||||||
|
|
||||||
|
func listNodes(t *testing.T, client *gophercloud.ServiceClient, lbID int) {
|
||||||
|
err := nodes.List(client, lbID, nil).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
nodeList, err := nodes.ExtractNodes(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, n := range nodeList {
|
||||||
|
t.Logf("Listing node: ID [%d] Address [%s:%d] Status [%s]", n.ID, n.Address, n.Port, n.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNode(t *testing.T, client *gophercloud.ServiceClient, lbID int, nodeID int) {
|
||||||
|
node, err := nodes.Get(client, lbID, nodeID).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Getting node %d: Type [%s] Weight [%d]", nodeID, node.Type, node.Weight)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateNode(t *testing.T, client *gophercloud.ServiceClient, lbID int, nodeID int) {
|
||||||
|
opts := nodes.UpdateOpts{
|
||||||
|
Weight: gophercloud.IntToPointer(10),
|
||||||
|
Condition: nodes.DRAINING,
|
||||||
|
Type: nodes.SECONDARY,
|
||||||
|
}
|
||||||
|
err := nodes.Update(client, lbID, nodeID, opts).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Updated node %d", nodeID)
|
||||||
|
waitForLB(client, lbID, lbs.ACTIVE)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listEvents(t *testing.T, client *gophercloud.ServiceClient, lbID int) {
|
||||||
|
pager := nodes.ListEvents(client, lbID, nodes.ListEventsOpts{})
|
||||||
|
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
eventList, err := nodes.ExtractNodeEvents(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, e := range eventList {
|
||||||
|
t.Logf("Listing events for node %d: Type [%s] Msg [%s] Severity [%s] Date [%s]",
|
||||||
|
e.NodeID, e.Type, e.DetailedMessage, e.Severity, e.Created)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteNode(t *testing.T, client *gophercloud.ServiceClient, lbID int, nodeID int) {
|
||||||
|
err := nodes.Delete(client, lbID, nodeID).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Deleted node %d", nodeID)
|
||||||
|
}
|
47
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/lb/v1/session_test.go
generated
vendored
Normal file
47
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/lb/v1/session_test.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// +build acceptance lbs
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/lb/v1/sessions"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSession(t *testing.T) {
|
||||||
|
client := setup(t)
|
||||||
|
|
||||||
|
ids := createLB(t, client, 1)
|
||||||
|
lbID := ids[0]
|
||||||
|
|
||||||
|
getSession(t, client, lbID)
|
||||||
|
|
||||||
|
enableSession(t, client, lbID)
|
||||||
|
waitForLB(client, lbID, "ACTIVE")
|
||||||
|
|
||||||
|
disableSession(t, client, lbID)
|
||||||
|
waitForLB(client, lbID, "ACTIVE")
|
||||||
|
|
||||||
|
deleteLB(t, client, lbID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSession(t *testing.T, client *gophercloud.ServiceClient, lbID int) {
|
||||||
|
sp, err := sessions.Get(client, lbID).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Session config: Type [%s]", sp.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
func enableSession(t *testing.T, client *gophercloud.ServiceClient, lbID int) {
|
||||||
|
opts := sessions.CreateOpts{Type: sessions.HTTPCOOKIE}
|
||||||
|
err := sessions.Enable(client, lbID, opts).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Enable %s sessions for %d", opts.Type, lbID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func disableSession(t *testing.T, client *gophercloud.ServiceClient, lbID int) {
|
||||||
|
err := sessions.Disable(client, lbID).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Disable sessions for %d", lbID)
|
||||||
|
}
|
53
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/lb/v1/throttle_test.go
generated
vendored
Normal file
53
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/lb/v1/throttle_test.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
// +build acceptance lbs
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/lb/v1/throttle"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestThrottle(t *testing.T) {
|
||||||
|
client := setup(t)
|
||||||
|
|
||||||
|
ids := createLB(t, client, 1)
|
||||||
|
lbID := ids[0]
|
||||||
|
|
||||||
|
getThrottleConfig(t, client, lbID)
|
||||||
|
|
||||||
|
createThrottleConfig(t, client, lbID)
|
||||||
|
waitForLB(client, lbID, "ACTIVE")
|
||||||
|
|
||||||
|
deleteThrottleConfig(t, client, lbID)
|
||||||
|
waitForLB(client, lbID, "ACTIVE")
|
||||||
|
|
||||||
|
deleteLB(t, client, lbID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getThrottleConfig(t *testing.T, client *gophercloud.ServiceClient, lbID int) {
|
||||||
|
sp, err := throttle.Get(client, lbID).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Throttle config: MaxConns [%s]", sp.MaxConnections)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createThrottleConfig(t *testing.T, client *gophercloud.ServiceClient, lbID int) {
|
||||||
|
opts := throttle.CreateOpts{
|
||||||
|
MaxConnections: 200,
|
||||||
|
MaxConnectionRate: 100,
|
||||||
|
MinConnections: 0,
|
||||||
|
RateInterval: 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := throttle.Create(client, lbID, opts).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Enable throttling for %d", lbID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteThrottleConfig(t *testing.T, client *gophercloud.ServiceClient, lbID int) {
|
||||||
|
err := throttle.Delete(client, lbID).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Disable throttling for %d", lbID)
|
||||||
|
}
|
83
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/lb/v1/vip_test.go
generated
vendored
Normal file
83
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/lb/v1/vip_test.go
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
// +build acceptance lbs
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/lb/v1/lbs"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/lb/v1/vips"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVIPs(t *testing.T) {
|
||||||
|
client := setup(t)
|
||||||
|
|
||||||
|
ids := createLB(t, client, 1)
|
||||||
|
lbID := ids[0]
|
||||||
|
|
||||||
|
listVIPs(t, client, lbID)
|
||||||
|
|
||||||
|
vipIDs := addVIPs(t, client, lbID, 3)
|
||||||
|
|
||||||
|
deleteVIP(t, client, lbID, vipIDs[0])
|
||||||
|
|
||||||
|
bulkDeleteVIPs(t, client, lbID, vipIDs[1:])
|
||||||
|
|
||||||
|
waitForLB(client, lbID, lbs.ACTIVE)
|
||||||
|
deleteLB(t, client, lbID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listVIPs(t *testing.T, client *gophercloud.ServiceClient, lbID int) {
|
||||||
|
err := vips.List(client, lbID).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
vipList, err := vips.ExtractVIPs(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, vip := range vipList {
|
||||||
|
t.Logf("Listing VIP: ID [%s] Address [%s] Type [%s] Version [%s]",
|
||||||
|
vip.ID, vip.Address, vip.Type, vip.Version)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addVIPs(t *testing.T, client *gophercloud.ServiceClient, lbID, count int) []int {
|
||||||
|
ids := []int{}
|
||||||
|
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
opts := vips.CreateOpts{
|
||||||
|
Type: vips.PUBLIC,
|
||||||
|
Version: vips.IPV6,
|
||||||
|
}
|
||||||
|
|
||||||
|
vip, err := vips.Create(client, lbID, opts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Created VIP %d", vip.ID)
|
||||||
|
|
||||||
|
waitForLB(client, lbID, lbs.ACTIVE)
|
||||||
|
|
||||||
|
ids = append(ids, vip.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteVIP(t *testing.T, client *gophercloud.ServiceClient, lbID, vipID int) {
|
||||||
|
err := vips.Delete(client, lbID, vipID).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
t.Logf("Deleted VIP %d", vipID)
|
||||||
|
|
||||||
|
waitForLB(client, lbID, lbs.ACTIVE)
|
||||||
|
}
|
||||||
|
|
||||||
|
func bulkDeleteVIPs(t *testing.T, client *gophercloud.ServiceClient, lbID int, ids []int) {
|
||||||
|
err := vips.BulkDelete(client, lbID, ids).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Deleted VIPs %s", intsToStr(ids))
|
||||||
|
}
|
39
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/networking/v2/common.go
generated
vendored
Normal file
39
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/networking/v2/common.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package v2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Client *gophercloud.ServiceClient
|
||||||
|
|
||||||
|
func NewClient() (*gophercloud.ServiceClient, error) {
|
||||||
|
opts, err := rackspace.AuthOptionsFromEnv()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
provider, err := rackspace.AuthenticatedClient(opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rackspace.NewNetworkV2(provider, gophercloud.EndpointOpts{
|
||||||
|
Name: "cloudNetworks",
|
||||||
|
Region: os.Getenv("RS_REGION"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Setup(t *testing.T) {
|
||||||
|
client, err := NewClient()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
Client = client
|
||||||
|
}
|
||||||
|
|
||||||
|
func Teardown() {
|
||||||
|
Client = nil
|
||||||
|
}
|
65
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/networking/v2/network_test.go
generated
vendored
Normal file
65
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/networking/v2/network_test.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
// +build acceptance networking
|
||||||
|
|
||||||
|
package v2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
os "github.com/rackspace/gophercloud/openstack/networking/v2/networks"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/networking/v2/networks"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNetworkCRUDOperations(t *testing.T) {
|
||||||
|
Setup(t)
|
||||||
|
defer Teardown()
|
||||||
|
|
||||||
|
// Create a network
|
||||||
|
n, err := networks.Create(Client, os.CreateOpts{Name: "sample_network", AdminStateUp: os.Up}).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
defer networks.Delete(Client, n.ID)
|
||||||
|
th.AssertEquals(t, "sample_network", n.Name)
|
||||||
|
th.AssertEquals(t, true, n.AdminStateUp)
|
||||||
|
networkID := n.ID
|
||||||
|
|
||||||
|
// List networks
|
||||||
|
pager := networks.List(Client, os.ListOpts{Limit: 2})
|
||||||
|
err = pager.EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
t.Logf("--- Page ---")
|
||||||
|
|
||||||
|
networkList, err := os.ExtractNetworks(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, n := range networkList {
|
||||||
|
t.Logf("Network: ID [%s] Name [%s] Status [%s] Is shared? [%s]",
|
||||||
|
n.ID, n.Name, n.Status, strconv.FormatBool(n.Shared))
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
th.CheckNoErr(t, err)
|
||||||
|
|
||||||
|
// Get a network
|
||||||
|
if networkID == "" {
|
||||||
|
t.Fatalf("In order to retrieve a network, the NetworkID must be set")
|
||||||
|
}
|
||||||
|
n, err = networks.Get(Client, networkID).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
th.AssertEquals(t, "ACTIVE", n.Status)
|
||||||
|
th.AssertDeepEquals(t, []string{}, n.Subnets)
|
||||||
|
th.AssertEquals(t, "sample_network", n.Name)
|
||||||
|
th.AssertEquals(t, true, n.AdminStateUp)
|
||||||
|
th.AssertEquals(t, false, n.Shared)
|
||||||
|
th.AssertEquals(t, networkID, n.ID)
|
||||||
|
|
||||||
|
// Update network
|
||||||
|
n, err = networks.Update(Client, networkID, os.UpdateOpts{Name: "new_network_name"}).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
th.AssertEquals(t, "new_network_name", n.Name)
|
||||||
|
|
||||||
|
// Delete network
|
||||||
|
res := networks.Delete(Client, networkID)
|
||||||
|
th.AssertNoErr(t, res.Err)
|
||||||
|
}
|
116
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/networking/v2/port_test.go
generated
vendored
Normal file
116
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/networking/v2/port_test.go
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
// +build acceptance networking
|
||||||
|
|
||||||
|
package v2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
osNetworks "github.com/rackspace/gophercloud/openstack/networking/v2/networks"
|
||||||
|
osPorts "github.com/rackspace/gophercloud/openstack/networking/v2/ports"
|
||||||
|
osSubnets "github.com/rackspace/gophercloud/openstack/networking/v2/subnets"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/networking/v2/networks"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/networking/v2/ports"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/networking/v2/subnets"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPortCRUD(t *testing.T) {
|
||||||
|
Setup(t)
|
||||||
|
defer Teardown()
|
||||||
|
|
||||||
|
// Setup network
|
||||||
|
t.Log("Setting up network")
|
||||||
|
networkID, err := createNetwork()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
defer networks.Delete(Client, networkID)
|
||||||
|
|
||||||
|
// Setup subnet
|
||||||
|
t.Logf("Setting up subnet on network %s", networkID)
|
||||||
|
subnetID, err := createSubnet(networkID)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
defer subnets.Delete(Client, subnetID)
|
||||||
|
|
||||||
|
// Create port
|
||||||
|
t.Logf("Create port based on subnet %s", subnetID)
|
||||||
|
portID := createPort(t, networkID, subnetID)
|
||||||
|
|
||||||
|
// List ports
|
||||||
|
t.Logf("Listing all ports")
|
||||||
|
listPorts(t)
|
||||||
|
|
||||||
|
// Get port
|
||||||
|
if portID == "" {
|
||||||
|
t.Fatalf("In order to retrieve a port, the portID must be set")
|
||||||
|
}
|
||||||
|
p, err := ports.Get(Client, portID).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
th.AssertEquals(t, portID, p.ID)
|
||||||
|
|
||||||
|
// Update port
|
||||||
|
p, err = ports.Update(Client, portID, osPorts.UpdateOpts{Name: "new_port_name"}).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
th.AssertEquals(t, "new_port_name", p.Name)
|
||||||
|
|
||||||
|
// Delete port
|
||||||
|
res := ports.Delete(Client, portID)
|
||||||
|
th.AssertNoErr(t, res.Err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createPort(t *testing.T, networkID, subnetID string) string {
|
||||||
|
enable := true
|
||||||
|
opts := osPorts.CreateOpts{
|
||||||
|
NetworkID: networkID,
|
||||||
|
Name: "my_port",
|
||||||
|
AdminStateUp: &enable,
|
||||||
|
FixedIPs: []osPorts.IP{osPorts.IP{SubnetID: subnetID}},
|
||||||
|
}
|
||||||
|
p, err := ports.Create(Client, opts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
th.AssertEquals(t, networkID, p.NetworkID)
|
||||||
|
th.AssertEquals(t, "my_port", p.Name)
|
||||||
|
th.AssertEquals(t, true, p.AdminStateUp)
|
||||||
|
|
||||||
|
return p.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func listPorts(t *testing.T) {
|
||||||
|
count := 0
|
||||||
|
pager := ports.List(Client, osPorts.ListOpts{})
|
||||||
|
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
count++
|
||||||
|
t.Logf("--- Page ---")
|
||||||
|
|
||||||
|
portList, err := osPorts.ExtractPorts(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, p := range portList {
|
||||||
|
t.Logf("Port: ID [%s] Name [%s] Status [%s] MAC addr [%s] Fixed IPs [%#v] Security groups [%#v]",
|
||||||
|
p.ID, p.Name, p.Status, p.MACAddress, p.FixedIPs, p.SecurityGroups)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
th.CheckNoErr(t, err)
|
||||||
|
|
||||||
|
if count == 0 {
|
||||||
|
t.Logf("No pages were iterated over when listing ports")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createNetwork() (string, error) {
|
||||||
|
res, err := networks.Create(Client, osNetworks.CreateOpts{Name: "tmp_network", AdminStateUp: osNetworks.Up}).Extract()
|
||||||
|
return res.ID, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSubnet(networkID string) (string, error) {
|
||||||
|
s, err := subnets.Create(Client, osSubnets.CreateOpts{
|
||||||
|
NetworkID: networkID,
|
||||||
|
CIDR: "192.168.199.0/24",
|
||||||
|
IPVersion: osSubnets.IPv4,
|
||||||
|
Name: "my_subnet",
|
||||||
|
EnableDHCP: osSubnets.Down,
|
||||||
|
}).Extract()
|
||||||
|
return s.ID, err
|
||||||
|
}
|
84
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/networking/v2/subnet_test.go
generated
vendored
Normal file
84
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/networking/v2/subnet_test.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
// +build acceptance networking
|
||||||
|
|
||||||
|
package v2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
osNetworks "github.com/rackspace/gophercloud/openstack/networking/v2/networks"
|
||||||
|
osSubnets "github.com/rackspace/gophercloud/openstack/networking/v2/subnets"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/networking/v2/networks"
|
||||||
|
"github.com/rackspace/gophercloud/rackspace/networking/v2/subnets"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestListSubnets(t *testing.T) {
|
||||||
|
Setup(t)
|
||||||
|
defer Teardown()
|
||||||
|
|
||||||
|
pager := subnets.List(Client, osSubnets.ListOpts{Limit: 2})
|
||||||
|
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
t.Logf("--- Page ---")
|
||||||
|
|
||||||
|
subnetList, err := osSubnets.ExtractSubnets(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
for _, s := range subnetList {
|
||||||
|
t.Logf("Subnet: ID [%s] Name [%s] IP Version [%d] CIDR [%s] GatewayIP [%s]",
|
||||||
|
s.ID, s.Name, s.IPVersion, s.CIDR, s.GatewayIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
th.CheckNoErr(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSubnetCRUD(t *testing.T) {
|
||||||
|
Setup(t)
|
||||||
|
defer Teardown()
|
||||||
|
|
||||||
|
// Setup network
|
||||||
|
t.Log("Setting up network")
|
||||||
|
n, err := networks.Create(Client, osNetworks.CreateOpts{Name: "tmp_network", AdminStateUp: osNetworks.Up}).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
networkID := n.ID
|
||||||
|
defer networks.Delete(Client, networkID)
|
||||||
|
|
||||||
|
// Create subnet
|
||||||
|
t.Log("Create subnet")
|
||||||
|
enable := false
|
||||||
|
opts := osSubnets.CreateOpts{
|
||||||
|
NetworkID: networkID,
|
||||||
|
CIDR: "192.168.199.0/24",
|
||||||
|
IPVersion: osSubnets.IPv4,
|
||||||
|
Name: "my_subnet",
|
||||||
|
EnableDHCP: &enable,
|
||||||
|
}
|
||||||
|
s, err := subnets.Create(Client, opts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
th.AssertEquals(t, networkID, s.NetworkID)
|
||||||
|
th.AssertEquals(t, "192.168.199.0/24", s.CIDR)
|
||||||
|
th.AssertEquals(t, 4, s.IPVersion)
|
||||||
|
th.AssertEquals(t, "my_subnet", s.Name)
|
||||||
|
th.AssertEquals(t, false, s.EnableDHCP)
|
||||||
|
subnetID := s.ID
|
||||||
|
|
||||||
|
// Get subnet
|
||||||
|
t.Log("Getting subnet")
|
||||||
|
s, err = subnets.Get(Client, subnetID).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
th.AssertEquals(t, subnetID, s.ID)
|
||||||
|
|
||||||
|
// Update subnet
|
||||||
|
t.Log("Update subnet")
|
||||||
|
s, err = subnets.Update(Client, subnetID, osSubnets.UpdateOpts{Name: "new_subnet_name"}).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
th.AssertEquals(t, "new_subnet_name", s.Name)
|
||||||
|
|
||||||
|
// Delete subnet
|
||||||
|
t.Log("Delete subnet")
|
||||||
|
res := subnets.Delete(Client, subnetID)
|
||||||
|
th.AssertNoErr(t, res.Err)
|
||||||
|
}
|
@@ -13,11 +13,11 @@ func TestAccounts(t *testing.T) {
|
|||||||
c, err := createClient(t, false)
|
c, err := createClient(t, false)
|
||||||
th.AssertNoErr(t, err)
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
updateres := raxAccounts.Update(c, raxAccounts.UpdateOpts{Metadata: map[string]string{"white": "mountains"}})
|
updateHeaders, err := raxAccounts.Update(c, raxAccounts.UpdateOpts{Metadata: map[string]string{"white": "mountains"}}).Extract()
|
||||||
th.AssertNoErr(t, updateres.Err)
|
th.AssertNoErr(t, err)
|
||||||
t.Logf("Headers from Update Account request: %+v\n", updateres.Header)
|
t.Logf("Update Account Response Headers: %+v\n", updateHeaders)
|
||||||
defer func() {
|
defer func() {
|
||||||
updateres = raxAccounts.Update(c, raxAccounts.UpdateOpts{Metadata: map[string]string{"white": ""}})
|
updateres := raxAccounts.Update(c, raxAccounts.UpdateOpts{Metadata: map[string]string{"white": ""}})
|
||||||
th.AssertNoErr(t, updateres.Err)
|
th.AssertNoErr(t, updateres.Err)
|
||||||
metadata, err := raxAccounts.Get(c).ExtractMetadata()
|
metadata, err := raxAccounts.Get(c).ExtractMetadata()
|
||||||
th.AssertNoErr(t, err)
|
th.AssertNoErr(t, err)
|
||||||
@@ -25,8 +25,13 @@ func TestAccounts(t *testing.T) {
|
|||||||
th.CheckEquals(t, metadata["White"], "")
|
th.CheckEquals(t, metadata["White"], "")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
metadata, err := raxAccounts.Get(c).ExtractMetadata()
|
getResp := raxAccounts.Get(c)
|
||||||
th.AssertNoErr(t, err)
|
th.AssertNoErr(t, getResp.Err)
|
||||||
|
|
||||||
|
getHeaders, _ := getResp.Extract()
|
||||||
|
t.Logf("Get Account Response Headers: %+v\n", getHeaders)
|
||||||
|
|
||||||
|
metadata, _ := getResp.ExtractMetadata()
|
||||||
t.Logf("Metadata from Get Account request (after update): %+v\n", metadata)
|
t.Logf("Metadata from Get Account request (after update): %+v\n", metadata)
|
||||||
|
|
||||||
th.CheckEquals(t, metadata["White"], "mountains")
|
th.CheckEquals(t, metadata["White"], "mountains")
|
||||||
|
@@ -26,10 +26,11 @@ func TestCDNContainers(t *testing.T) {
|
|||||||
|
|
||||||
raxCDNClient, err := createClient(t, true)
|
raxCDNClient, err := createClient(t, true)
|
||||||
th.AssertNoErr(t, err)
|
th.AssertNoErr(t, err)
|
||||||
|
enableRes := raxCDNContainers.Enable(raxCDNClient, "gophercloud-test", raxCDNContainers.EnableOpts{CDNEnabled: true, TTL: 900})
|
||||||
r := raxCDNContainers.Enable(raxCDNClient, "gophercloud-test", raxCDNContainers.EnableOpts{CDNEnabled: true, TTL: 900})
|
t.Logf("Header map from Enable CDN Container request: %+v\n", enableRes.Header)
|
||||||
th.AssertNoErr(t, r.Err)
|
enableHeader, err := enableRes.Extract()
|
||||||
t.Logf("Headers from Enable CDN Container request: %+v\n", r.Header)
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Headers from Enable CDN Container request: %+v\n", enableHeader)
|
||||||
|
|
||||||
t.Logf("Container Names available to the currently issued token:")
|
t.Logf("Container Names available to the currently issued token:")
|
||||||
count := 0
|
count := 0
|
||||||
@@ -51,11 +52,15 @@ func TestCDNContainers(t *testing.T) {
|
|||||||
t.Errorf("No CDN containers listed for your current token.")
|
t.Errorf("No CDN containers listed for your current token.")
|
||||||
}
|
}
|
||||||
|
|
||||||
updateres := raxCDNContainers.Update(raxCDNClient, "gophercloud-test", raxCDNContainers.UpdateOpts{CDNEnabled: false})
|
updateOpts := raxCDNContainers.UpdateOpts{XCDNEnabled: raxCDNContainers.Disabled, XLogRetention: raxCDNContainers.Enabled}
|
||||||
th.AssertNoErr(t, updateres.Err)
|
updateHeader, err := raxCDNContainers.Update(raxCDNClient, "gophercloud-test", updateOpts).Extract()
|
||||||
t.Logf("Headers from Update CDN Container request: %+v\n", updateres.Header)
|
|
||||||
|
|
||||||
metadata, err := raxCDNContainers.Get(raxCDNClient, "gophercloud-test").ExtractMetadata()
|
|
||||||
th.AssertNoErr(t, err)
|
th.AssertNoErr(t, err)
|
||||||
t.Logf("Headers from Get CDN Container request (after update): %+v\n", metadata)
|
t.Logf("Headers from Update CDN Container request: %+v\n", updateHeader)
|
||||||
|
|
||||||
|
getRes := raxCDNContainers.Get(raxCDNClient, "gophercloud-test")
|
||||||
|
getHeader, err := getRes.Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Headers from Get CDN Container request (after update): %+v\n", getHeader)
|
||||||
|
metadata, err := getRes.ExtractMetadata()
|
||||||
|
t.Logf("Metadata from Get CDN Container request (after update): %+v\n", metadata)
|
||||||
}
|
}
|
||||||
|
@@ -57,29 +57,34 @@ func TestContainers(t *testing.T) {
|
|||||||
t.Errorf("No containers listed for your current token.")
|
t.Errorf("No containers listed for your current token.")
|
||||||
}
|
}
|
||||||
|
|
||||||
createres := raxContainers.Create(c, "gophercloud-test", nil)
|
createHeader, err := raxContainers.Create(c, "gophercloud-test", nil).Extract()
|
||||||
th.AssertNoErr(t, createres.Err)
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Headers from Create Container request: %+v\n", createHeader)
|
||||||
defer func() {
|
defer func() {
|
||||||
res := raxContainers.Delete(c, "gophercloud-test")
|
deleteres := raxContainers.Delete(c, "gophercloud-test")
|
||||||
th.AssertNoErr(t, res.Err)
|
deleteHeader, err := deleteres.Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("Headers from Delete Container request: %+v\n", deleteres.Header)
|
||||||
|
t.Logf("Headers from Delete Container request: %+v\n", deleteHeader)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
updateres := raxContainers.Update(c, "gophercloud-test", raxContainers.UpdateOpts{Metadata: map[string]string{"white": "mountains"}})
|
updateHeader, err := raxContainers.Update(c, "gophercloud-test", raxContainers.UpdateOpts{Metadata: map[string]string{"white": "mountains"}}).Extract()
|
||||||
th.AssertNoErr(t, updateres.Err)
|
th.AssertNoErr(t, err)
|
||||||
t.Logf("Headers from Update Account request: %+v\n", updateres.Header)
|
t.Logf("Headers from Update Container request: %+v\n", updateHeader)
|
||||||
defer func() {
|
defer func() {
|
||||||
res := raxContainers.Update(c, "gophercloud-test", raxContainers.UpdateOpts{Metadata: map[string]string{"white": ""}})
|
res := raxContainers.Update(c, "gophercloud-test", raxContainers.UpdateOpts{Metadata: map[string]string{"white": ""}})
|
||||||
th.AssertNoErr(t, res.Err)
|
th.AssertNoErr(t, res.Err)
|
||||||
metadata, err := raxContainers.Get(c, "gophercloud-test").ExtractMetadata()
|
metadata, err := raxContainers.Get(c, "gophercloud-test").ExtractMetadata()
|
||||||
th.AssertNoErr(t, err)
|
th.AssertNoErr(t, err)
|
||||||
t.Logf("Metadata from Get Account request (after update reverted): %+v\n", metadata)
|
t.Logf("Metadata from Get Container request (after update reverted): %+v\n", metadata)
|
||||||
th.CheckEquals(t, metadata["White"], "")
|
th.CheckEquals(t, metadata["White"], "")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
getres := raxContainers.Get(c, "gophercloud-test")
|
getres := raxContainers.Get(c, "gophercloud-test")
|
||||||
t.Logf("Headers from Get Account request (after update): %+v\n", getres.Header)
|
getHeader, err := getres.Extract()
|
||||||
metadata, err := getres.ExtractMetadata()
|
|
||||||
th.AssertNoErr(t, err)
|
th.AssertNoErr(t, err)
|
||||||
t.Logf("Metadata from Get Account request (after update): %+v\n", metadata)
|
t.Logf("Headers from Get Container request (after update): %+v\n", getHeader)
|
||||||
|
metadata, err := getres.ExtractMetadata()
|
||||||
|
t.Logf("Metadata from Get Container request (after update): %+v\n", metadata)
|
||||||
th.CheckEquals(t, metadata["White"], "mountains")
|
th.CheckEquals(t, metadata["White"], "mountains")
|
||||||
}
|
}
|
||||||
|
@@ -21,6 +21,7 @@ func TestObjects(t *testing.T) {
|
|||||||
th.AssertNoErr(t, res.Err)
|
th.AssertNoErr(t, res.Err)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
t.Logf("Deleting container...")
|
||||||
res := raxContainers.Delete(c, "gophercloud-test")
|
res := raxContainers.Delete(c, "gophercloud-test")
|
||||||
th.AssertNoErr(t, res.Err)
|
th.AssertNoErr(t, res.Err)
|
||||||
}()
|
}()
|
||||||
@@ -29,7 +30,9 @@ func TestObjects(t *testing.T) {
|
|||||||
options := &osObjects.CreateOpts{ContentType: "text/plain"}
|
options := &osObjects.CreateOpts{ContentType: "text/plain"}
|
||||||
createres := raxObjects.Create(c, "gophercloud-test", "o1", content, options)
|
createres := raxObjects.Create(c, "gophercloud-test", "o1", content, options)
|
||||||
th.AssertNoErr(t, createres.Err)
|
th.AssertNoErr(t, createres.Err)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
t.Logf("Deleting object o1...")
|
||||||
res := raxObjects.Delete(c, "gophercloud-test", "o1", nil)
|
res := raxObjects.Delete(c, "gophercloud-test", "o1", nil)
|
||||||
th.AssertNoErr(t, res.Err)
|
th.AssertNoErr(t, res.Err)
|
||||||
}()
|
}()
|
||||||
@@ -80,6 +83,7 @@ func TestObjects(t *testing.T) {
|
|||||||
copyres := raxObjects.Copy(c, "gophercloud-test", "o1", &raxObjects.CopyOpts{Destination: "gophercloud-test/o2"})
|
copyres := raxObjects.Copy(c, "gophercloud-test", "o1", &raxObjects.CopyOpts{Destination: "gophercloud-test/o2"})
|
||||||
th.AssertNoErr(t, copyres.Err)
|
th.AssertNoErr(t, copyres.Err)
|
||||||
defer func() {
|
defer func() {
|
||||||
|
t.Logf("Deleting object o2...")
|
||||||
res := raxObjects.Delete(c, "gophercloud-test", "o2", nil)
|
res := raxObjects.Delete(c, "gophercloud-test", "o2", nil)
|
||||||
th.AssertNoErr(t, res.Err)
|
th.AssertNoErr(t, res.Err)
|
||||||
}()
|
}()
|
||||||
@@ -99,7 +103,7 @@ func TestObjects(t *testing.T) {
|
|||||||
metadata, err := raxObjects.Get(c, "gophercloud-test", "o2", nil).ExtractMetadata()
|
metadata, err := raxObjects.Get(c, "gophercloud-test", "o2", nil).ExtractMetadata()
|
||||||
th.AssertNoErr(t, err)
|
th.AssertNoErr(t, err)
|
||||||
t.Logf("Metadata from Get Account request (after update reverted): %+v\n", metadata)
|
t.Logf("Metadata from Get Account request (after update reverted): %+v\n", metadata)
|
||||||
th.CheckEquals(t, metadata["White"], "")
|
th.CheckEquals(t, "", metadata["White"])
|
||||||
}()
|
}()
|
||||||
|
|
||||||
getres := raxObjects.Get(c, "gophercloud-test", "o2", nil)
|
getres := raxObjects.Get(c, "gophercloud-test", "o2", nil)
|
||||||
@@ -108,5 +112,13 @@ func TestObjects(t *testing.T) {
|
|||||||
metadata, err := getres.ExtractMetadata()
|
metadata, err := getres.ExtractMetadata()
|
||||||
th.AssertNoErr(t, err)
|
th.AssertNoErr(t, err)
|
||||||
t.Logf("Metadata from Get Account request (after update): %+v\n", metadata)
|
t.Logf("Metadata from Get Account request (after update): %+v\n", metadata)
|
||||||
th.CheckEquals(t, metadata["White"], "mountains")
|
th.CheckEquals(t, "mountains", metadata["White"])
|
||||||
|
|
||||||
|
createTempURLOpts := osObjects.CreateTempURLOpts{
|
||||||
|
Method: osObjects.GET,
|
||||||
|
TTL: 600,
|
||||||
|
}
|
||||||
|
tempURL, err := raxObjects.CreateTempURL(c, "gophercloud-test", "o1", createTempURLOpts)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
t.Logf("TempURL for object (%s): %s", "o1", tempURL)
|
||||||
}
|
}
|
||||||
|
9
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/tools/tools.go
generated
vendored
9
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/tools/tools.go
generated
vendored
@@ -1,10 +1,11 @@
|
|||||||
// +build acceptance
|
// +build acceptance common
|
||||||
|
|
||||||
package tools
|
package tools
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"errors"
|
"errors"
|
||||||
|
mrand "math/rand"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -72,6 +73,12 @@ func RandomString(prefix string, n int) string {
|
|||||||
return prefix + string(bytes)
|
return prefix + string(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RandomInt will return a random integer between a specified range.
|
||||||
|
func RandomInt(min, max int) int {
|
||||||
|
mrand.Seed(time.Now().Unix())
|
||||||
|
return mrand.Intn(max-min) + min
|
||||||
|
}
|
||||||
|
|
||||||
// Elide returns the first bit of its input string with a suffix of "..." if it's longer than
|
// Elide returns the first bit of its input string with a suffix of "..." if it's longer than
|
||||||
// a comfortable 40 characters.
|
// a comfortable 40 characters.
|
||||||
func Elide(value string) string {
|
func Elide(value string) string {
|
||||||
|
26
Godeps/_workspace/src/github.com/rackspace/gophercloud/auth_options.go
generated
vendored
26
Godeps/_workspace/src/github.com/rackspace/gophercloud/auth_options.go
generated
vendored
@@ -1,20 +1,28 @@
|
|||||||
package gophercloud
|
package gophercloud
|
||||||
|
|
||||||
// AuthOptions allows anyone calling Authenticate to supply the required access
|
/*
|
||||||
// credentials. Its fields are the union of those recognized by each identity
|
AuthOptions stores information needed to authenticate to an OpenStack cluster.
|
||||||
// implementation and provider.
|
You can populate one manually, or use a provider's AuthOptionsFromEnv() function
|
||||||
|
to read relevant information from the standard environment variables. Pass one
|
||||||
|
to a provider's AuthenticatedClient function to authenticate and obtain a
|
||||||
|
ProviderClient representing an active session on that provider.
|
||||||
|
|
||||||
|
Its fields are the union of those recognized by each identity implementation and
|
||||||
|
provider.
|
||||||
|
*/
|
||||||
type AuthOptions struct {
|
type AuthOptions struct {
|
||||||
// IdentityEndpoint specifies the HTTP endpoint that is required to work with
|
// IdentityEndpoint specifies the HTTP endpoint that is required to work with
|
||||||
// the Identity API of the appropriate version. Required by the identity
|
// the Identity API of the appropriate version. While it's ultimately needed by
|
||||||
// services, but often populated by a provider Client.
|
// all of the identity services, it will often be populated by a provider-level
|
||||||
|
// function.
|
||||||
IdentityEndpoint string
|
IdentityEndpoint string
|
||||||
|
|
||||||
// Username is required if using Identity V2 API. Consult with your provider's
|
// Username is required if using Identity V2 API. Consult with your provider's
|
||||||
// control panel to discover your account's username. In Identity V3, either
|
// control panel to discover your account's username. In Identity V3, either
|
||||||
// UserID or a combination of Username and DomainID or DomainName.
|
// UserID or a combination of Username and DomainID or DomainName are needed.
|
||||||
Username, UserID string
|
Username, UserID string
|
||||||
|
|
||||||
// Exactly one of Password or ApiKey is required for the Identity V2 and V3
|
// Exactly one of Password or APIKey is required for the Identity V2 and V3
|
||||||
// APIs. Consult with your provider's control panel to discover your account's
|
// APIs. Consult with your provider's control panel to discover your account's
|
||||||
// preferred method of authentication.
|
// preferred method of authentication.
|
||||||
Password, APIKey string
|
Password, APIKey string
|
||||||
@@ -25,7 +33,7 @@ type AuthOptions struct {
|
|||||||
|
|
||||||
// The TenantID and TenantName fields are optional for the Identity V2 API.
|
// The TenantID and TenantName fields are optional for the Identity V2 API.
|
||||||
// Some providers allow you to specify a TenantName instead of the TenantId.
|
// Some providers allow you to specify a TenantName instead of the TenantId.
|
||||||
// Some require both. Your provider's authentication policies will determine
|
// Some require both. Your provider's authentication policies will determine
|
||||||
// how these fields influence authentication.
|
// how these fields influence authentication.
|
||||||
TenantID, TenantName string
|
TenantID, TenantName string
|
||||||
|
|
||||||
@@ -34,5 +42,7 @@ type AuthOptions struct {
|
|||||||
// re-authenticate automatically if/when your token expires. If you set it to
|
// re-authenticate automatically if/when your token expires. If you set it to
|
||||||
// false, it will not cache these settings, but re-authentication will not be
|
// false, it will not cache these settings, but re-authentication will not be
|
||||||
// possible. This setting defaults to false.
|
// possible. This setting defaults to false.
|
||||||
|
//
|
||||||
|
// This setting is speculative and is currently not respected!
|
||||||
AllowReauth bool
|
AllowReauth bool
|
||||||
}
|
}
|
||||||
|
7
Godeps/_workspace/src/github.com/rackspace/gophercloud/auth_results.go
generated
vendored
7
Godeps/_workspace/src/github.com/rackspace/gophercloud/auth_results.go
generated
vendored
@@ -2,10 +2,9 @@ package gophercloud
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
// AuthResults encapsulates the raw results from an authentication request. As OpenStack allows
|
// AuthResults [deprecated] is a leftover type from the v0.x days. It was
|
||||||
// extensions to influence the structure returned in ways that Gophercloud cannot predict at
|
// intended to describe common functionality among identity service results, but
|
||||||
// compile-time, you should use type-safe accessors to work with the data represented by this type,
|
// is not actually used anywhere.
|
||||||
// such as ServiceCatalog and TokenID.
|
|
||||||
type AuthResults interface {
|
type AuthResults interface {
|
||||||
// TokenID returns the token's ID value from the authentication response.
|
// TokenID returns the token's ID value from the authentication response.
|
||||||
TokenID() (string, error)
|
TokenID() (string, error)
|
||||||
|
67
Godeps/_workspace/src/github.com/rackspace/gophercloud/doc.go
generated
vendored
Normal file
67
Godeps/_workspace/src/github.com/rackspace/gophercloud/doc.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
Package gophercloud provides a multi-vendor interface to OpenStack-compatible
|
||||||
|
clouds. The library has a three-level hierarchy: providers, services, and
|
||||||
|
resources.
|
||||||
|
|
||||||
|
Provider structs represent the service providers that offer and manage a
|
||||||
|
collection of services. Examples of providers include: OpenStack, Rackspace,
|
||||||
|
HP. These are defined like so:
|
||||||
|
|
||||||
|
opts := gophercloud.AuthOptions{
|
||||||
|
IdentityEndpoint: "https://my-openstack.com:5000/v2.0",
|
||||||
|
Username: "{username}",
|
||||||
|
Password: "{password}",
|
||||||
|
TenantID: "{tenant_id}",
|
||||||
|
}
|
||||||
|
|
||||||
|
provider, err := openstack.AuthenticatedClient(opts)
|
||||||
|
|
||||||
|
Service structs are specific to a provider and handle all of the logic and
|
||||||
|
operations for a particular OpenStack service. Examples of services include:
|
||||||
|
Compute, Object Storage, Block Storage. In order to define one, you need to
|
||||||
|
pass in the parent provider, like so:
|
||||||
|
|
||||||
|
opts := gophercloud.EndpointOpts{Region: "RegionOne"}
|
||||||
|
|
||||||
|
client := openstack.NewComputeV2(provider, opts)
|
||||||
|
|
||||||
|
Resource structs are the domain models that services make use of in order
|
||||||
|
to work with and represent the state of API resources:
|
||||||
|
|
||||||
|
server, err := servers.Get(client, "{serverId}").Extract()
|
||||||
|
|
||||||
|
Intermediate Result structs are returned for API operations, which allow
|
||||||
|
generic access to the HTTP headers, response body, and any errors associated
|
||||||
|
with the network transaction. To turn a result into a usable resource struct,
|
||||||
|
you must call the Extract method which is chained to the response, or an
|
||||||
|
Extract function from an applicable extension:
|
||||||
|
|
||||||
|
result := servers.Get(client, "{serverId}")
|
||||||
|
|
||||||
|
// Attempt to extract the disk configuration from the OS-DCF disk config
|
||||||
|
// extension:
|
||||||
|
config, err := diskconfig.ExtractGet(result)
|
||||||
|
|
||||||
|
All requests that enumerate a collection return a Pager struct that is used to
|
||||||
|
iterate through the results one page at a time. Use the EachPage method on that
|
||||||
|
Pager to handle each successive Page in a closure, then use the appropriate
|
||||||
|
extraction method from that request's package to interpret that Page as a slice
|
||||||
|
of results:
|
||||||
|
|
||||||
|
err := servers.List(client, nil).EachPage(func (page pagination.Page) (bool, error) {
|
||||||
|
s, err := servers.ExtractServers(page)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the []servers.Server slice.
|
||||||
|
|
||||||
|
// Return "false" or an error to prematurely stop fetching new pages.
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
This top-level package contains utility functions and data types that are used
|
||||||
|
throughout the provider and service packages. Of particular note for end users
|
||||||
|
are the AuthOptions and EndpointOpts structs.
|
||||||
|
*/
|
||||||
|
package gophercloud
|
77
Godeps/_workspace/src/github.com/rackspace/gophercloud/endpoint_search.go
generated
vendored
77
Godeps/_workspace/src/github.com/rackspace/gophercloud/endpoint_search.go
generated
vendored
@@ -3,58 +3,85 @@ package gophercloud
|
|||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrServiceNotFound is returned when no service matches the EndpointOpts.
|
// ErrServiceNotFound is returned when no service in a service catalog matches
|
||||||
|
// the provided EndpointOpts. This is generally returned by provider service
|
||||||
|
// factory methods like "NewComputeV2()" and can mean that a service is not
|
||||||
|
// enabled for your account.
|
||||||
ErrServiceNotFound = errors.New("No suitable service could be found in the service catalog.")
|
ErrServiceNotFound = errors.New("No suitable service could be found in the service catalog.")
|
||||||
|
|
||||||
// ErrEndpointNotFound is returned when no available endpoints match the provided EndpointOpts.
|
// ErrEndpointNotFound is returned when no available endpoints match the
|
||||||
|
// provided EndpointOpts. This is also generally returned by provider service
|
||||||
|
// factory methods, and usually indicates that a region was specified
|
||||||
|
// incorrectly.
|
||||||
ErrEndpointNotFound = errors.New("No suitable endpoint could be found in the service catalog.")
|
ErrEndpointNotFound = errors.New("No suitable endpoint could be found in the service catalog.")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Availability indicates whether a specific service endpoint is accessible.
|
// Availability indicates to whom a specific service endpoint is accessible:
|
||||||
// Identity v2 lists these as different kinds of URLs ("adminURL",
|
// the internet at large, internal networks only, or only to administrators.
|
||||||
// "internalURL", and "publicURL"), while v3 lists them as "Interfaces".
|
// Different identity services use different terminology for these. Identity v2
|
||||||
|
// lists them as different kinds of URLs within the service catalog ("adminURL",
|
||||||
|
// "internalURL", and "publicURL"), while v3 lists them as "Interfaces" in an
|
||||||
|
// endpoint's response.
|
||||||
type Availability string
|
type Availability string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// AvailabilityAdmin makes an endpoint only available to administrators.
|
// AvailabilityAdmin indicates that an endpoint is only available to
|
||||||
|
// administrators.
|
||||||
AvailabilityAdmin Availability = "admin"
|
AvailabilityAdmin Availability = "admin"
|
||||||
|
|
||||||
// AvailabilityPublic makes an endpoint available to everyone.
|
// AvailabilityPublic indicates that an endpoint is available to everyone on
|
||||||
|
// the internet.
|
||||||
AvailabilityPublic Availability = "public"
|
AvailabilityPublic Availability = "public"
|
||||||
|
|
||||||
// AvailabilityInternal makes an endpoint only available within the cluster.
|
// AvailabilityInternal indicates that an endpoint is only available within
|
||||||
|
// the cluster's internal network.
|
||||||
AvailabilityInternal Availability = "internal"
|
AvailabilityInternal Availability = "internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EndpointOpts contains options for finding an endpoint for an Openstack client.
|
// EndpointOpts specifies search criteria used by queries against an
|
||||||
|
// OpenStack service catalog. The options must contain enough information to
|
||||||
|
// unambiguously identify one, and only one, endpoint within the catalog.
|
||||||
|
//
|
||||||
|
// Usually, these are passed to service client factory functions in a provider
|
||||||
|
// package, like "rackspace.NewComputeV2()".
|
||||||
type EndpointOpts struct {
|
type EndpointOpts struct {
|
||||||
// Type is the service type for the client (e.g., "compute", "object-store").
|
// Type [required] is the service type for the client (e.g., "compute",
|
||||||
// Required.
|
// "object-store"). Generally, this will be supplied by the service client
|
||||||
|
// function, but a user-given value will be honored if provided.
|
||||||
Type string
|
Type string
|
||||||
|
|
||||||
// Name is the service name for the client (e.g., "nova") as it appears in
|
// Name [optional] is the service name for the client (e.g., "nova") as it
|
||||||
// the service catalog. Services can have the same Type but a different Name,
|
// appears in the service catalog. Services can have the same Type but a
|
||||||
// which is why both Type and Name are sometimes needed. Optional.
|
// different Name, which is why both Type and Name are sometimes needed.
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
// Region is the geographic region in which the service resides. Required only
|
// Region [required] is the geographic region in which the endpoint resides,
|
||||||
// for services that span multiple regions.
|
// generally specifying which datacenter should house your resources.
|
||||||
|
// Required only for services that span multiple regions.
|
||||||
Region string
|
Region string
|
||||||
|
|
||||||
// Availability is the visibility of the endpoint to be returned. Valid types
|
// Availability [optional] is the visibility of the endpoint to be returned.
|
||||||
// are: AvailabilityPublic, AvailabilityInternal, or AvailabilityAdmin.
|
// Valid types include the constants AvailabilityPublic, AvailabilityInternal,
|
||||||
// Availability is not required, and defaults to AvailabilityPublic.
|
// or AvailabilityAdmin from this package.
|
||||||
// Not all providers or services offer all Availability options.
|
//
|
||||||
|
// Availability is not required, and defaults to AvailabilityPublic. Not all
|
||||||
|
// providers or services offer all Availability options.
|
||||||
Availability Availability
|
Availability Availability
|
||||||
}
|
}
|
||||||
|
|
||||||
// EndpointLocator is a function that describes how to locate a single endpoint
|
/*
|
||||||
// from a service catalog for a specific ProviderClient. It should be set
|
EndpointLocator is an internal function to be used by provider implementations.
|
||||||
// during ProviderClient authentication and used to discover related ServiceClients.
|
|
||||||
|
It provides an implementation that locates a single endpoint from a service
|
||||||
|
catalog for a specific ProviderClient based on user-provided EndpointOpts. The
|
||||||
|
provider then uses it to discover related ServiceClients.
|
||||||
|
*/
|
||||||
type EndpointLocator func(EndpointOpts) (string, error)
|
type EndpointLocator func(EndpointOpts) (string, error)
|
||||||
|
|
||||||
// ApplyDefaults sets EndpointOpts fields if not already set. Currently,
|
// ApplyDefaults is an internal method to be used by provider implementations.
|
||||||
// EndpointOpts.Availability defaults to the public endpoint.
|
//
|
||||||
|
// It sets EndpointOpts fields if not already set, including a default type.
|
||||||
|
// Currently, EndpointOpts.Availability defaults to the public endpoint.
|
||||||
func (eo *EndpointOpts) ApplyDefaults(t string) {
|
func (eo *EndpointOpts) ApplyDefaults(t string) {
|
||||||
if eo.Type == "" {
|
if eo.Type == "" {
|
||||||
eo.Type = t
|
eo.Type = t
|
||||||
|
@@ -1,38 +0,0 @@
|
|||||||
package snapshots
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
"github.com/rackspace/gophercloud/testhelper/client"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestWaitForStatus(t *testing.T) {
|
|
||||||
th.SetupHTTP()
|
|
||||||
defer th.TeardownHTTP()
|
|
||||||
|
|
||||||
th.Mux.HandleFunc("/snapshots/1234", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
w.Header().Add("Content-Type", "application/json")
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
fmt.Fprintf(w, `
|
|
||||||
{
|
|
||||||
"snapshot": {
|
|
||||||
"display_name": "snapshot-001",
|
|
||||||
"id": "1234",
|
|
||||||
"status":"available"
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
err := WaitForStatus(client.ServiceClient(), "1234", "available", 0)
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("Expected error: 'Time Out in WaitFor'")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = WaitForStatus(client.ServiceClient(), "1234", "available", 3)
|
|
||||||
th.CheckNoErr(t, err)
|
|
||||||
}
|
|
@@ -28,7 +28,7 @@ type Volume struct {
|
|||||||
CreatedAt string `mapstructure:"created_at"`
|
CreatedAt string `mapstructure:"created_at"`
|
||||||
|
|
||||||
// Human-readable description for the volume.
|
// Human-readable description for the volume.
|
||||||
Description string `mapstructure:"display_discription"`
|
Description string `mapstructure:"display_description"`
|
||||||
|
|
||||||
// The type of volume to create, either SATA or SSD.
|
// The type of volume to create, either SATA or SSD.
|
||||||
VolumeType string `mapstructure:"volume_type"`
|
VolumeType string `mapstructure:"volume_type"`
|
||||||
|
@@ -1,38 +0,0 @@
|
|||||||
package volumes
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
th "github.com/rackspace/gophercloud/testhelper"
|
|
||||||
"github.com/rackspace/gophercloud/testhelper/client"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestWaitForStatus(t *testing.T) {
|
|
||||||
th.SetupHTTP()
|
|
||||||
defer th.TeardownHTTP()
|
|
||||||
|
|
||||||
th.Mux.HandleFunc("/volumes/1234", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
time.Sleep(3 * time.Second)
|
|
||||||
w.Header().Add("Content-Type", "application/json")
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
fmt.Fprintf(w, `
|
|
||||||
{
|
|
||||||
"volume": {
|
|
||||||
"display_name": "vol-001",
|
|
||||||
"id": "1234",
|
|
||||||
"status":"available"
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
err := WaitForStatus(client.ServiceClient(), "1234", "available", 0)
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("Expected error: 'Time Out in WaitFor'")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = WaitForStatus(client.ServiceClient(), "1234", "available", 6)
|
|
||||||
th.CheckNoErr(t, err)
|
|
||||||
}
|
|
4
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/base/doc.go
generated
vendored
Normal file
4
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/base/doc.go
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
// Package base provides information and interaction with the base API
|
||||||
|
// resource in the OpenStack CDN service. This API resource allows for
|
||||||
|
// retrieving the Home Document and pinging the root URL.
|
||||||
|
package base
|
53
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/base/fixtures.go
generated
vendored
Normal file
53
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/base/fixtures.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package base
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
fake "github.com/rackspace/gophercloud/testhelper/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandleGetSuccessfully creates an HTTP handler at `/` on the test handler mux
|
||||||
|
// that responds with a `Get` response.
|
||||||
|
func HandleGetSuccessfully(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "GET")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
th.TestHeader(t, r, "Accept", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
fmt.Fprintf(w, `
|
||||||
|
{
|
||||||
|
"resources": {
|
||||||
|
"rel/cdn": {
|
||||||
|
"href-template": "services{?marker,limit}",
|
||||||
|
"href-vars": {
|
||||||
|
"marker": "param/marker",
|
||||||
|
"limit": "param/limit"
|
||||||
|
},
|
||||||
|
"hints": {
|
||||||
|
"allow": [
|
||||||
|
"GET"
|
||||||
|
],
|
||||||
|
"formats": {
|
||||||
|
"application/json": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandlePingSuccessfully creates an HTTP handler at `/ping` on the test handler
|
||||||
|
// mux that responds with a `Ping` response.
|
||||||
|
func HandlePingSuccessfully(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "GET")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
})
|
||||||
|
}
|
30
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/base/requests.go
generated
vendored
Normal file
30
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/base/requests.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package base
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
|
||||||
|
"github.com/racker/perigee"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Get retrieves the home document, allowing the user to discover the
|
||||||
|
// entire API.
|
||||||
|
func Get(c *gophercloud.ServiceClient) GetResult {
|
||||||
|
var res GetResult
|
||||||
|
_, res.Err = perigee.Request("GET", getURL(c), perigee.Options{
|
||||||
|
MoreHeaders: c.AuthenticatedHeaders(),
|
||||||
|
Results: &res.Body,
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ping retrieves a ping to the server.
|
||||||
|
func Ping(c *gophercloud.ServiceClient) PingResult {
|
||||||
|
var res PingResult
|
||||||
|
_, res.Err = perigee.Request("GET", pingURL(c), perigee.Options{
|
||||||
|
MoreHeaders: c.AuthenticatedHeaders(),
|
||||||
|
OkCodes: []int{204},
|
||||||
|
OmitAccept: true,
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
43
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/base/requests_test.go
generated
vendored
Normal file
43
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/base/requests_test.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package base
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
fake "github.com/rackspace/gophercloud/testhelper/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetHomeDocument(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
HandleGetSuccessfully(t)
|
||||||
|
|
||||||
|
actual, err := Get(fake.ServiceClient()).Extract()
|
||||||
|
th.CheckNoErr(t, err)
|
||||||
|
|
||||||
|
expected := HomeDocument{
|
||||||
|
"rel/cdn": map[string]interface{}{
|
||||||
|
"href-template": "services{?marker,limit}",
|
||||||
|
"href-vars": map[string]interface{}{
|
||||||
|
"marker": "param/marker",
|
||||||
|
"limit": "param/limit",
|
||||||
|
},
|
||||||
|
"hints": map[string]interface{}{
|
||||||
|
"allow": []string{"GET"},
|
||||||
|
"formats": map[string]interface{}{
|
||||||
|
"application/json": map[string]interface{}{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
th.CheckDeepEquals(t, expected, *actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPing(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
HandlePingSuccessfully(t)
|
||||||
|
|
||||||
|
err := Ping(fake.ServiceClient()).ExtractErr()
|
||||||
|
th.CheckNoErr(t, err)
|
||||||
|
}
|
35
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/base/results.go
generated
vendored
Normal file
35
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/base/results.go
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package base
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HomeDocument is a resource that contains all the resources for the CDN API.
|
||||||
|
type HomeDocument map[string]interface{}
|
||||||
|
|
||||||
|
// GetResult represents the result of a Get operation.
|
||||||
|
type GetResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract is a function that accepts a result and extracts a home document resource.
|
||||||
|
func (r GetResult) Extract() (*HomeDocument, error) {
|
||||||
|
if r.Err != nil {
|
||||||
|
return nil, r.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
submap, ok := r.Body.(map[string]interface{})["resources"]
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("Unexpected HomeDocument structure")
|
||||||
|
}
|
||||||
|
casted := HomeDocument(submap.(map[string]interface{}))
|
||||||
|
|
||||||
|
return &casted, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PingResult represents the result of a Ping operation.
|
||||||
|
type PingResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
11
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/base/urls.go
generated
vendored
Normal file
11
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/base/urls.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package base
|
||||||
|
|
||||||
|
import "github.com/rackspace/gophercloud"
|
||||||
|
|
||||||
|
func getURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL()
|
||||||
|
}
|
||||||
|
|
||||||
|
func pingURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL("ping")
|
||||||
|
}
|
6
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/flavors/doc.go
generated
vendored
Normal file
6
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/flavors/doc.go
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// Package flavors provides information and interaction with the flavors API
|
||||||
|
// resource in the OpenStack CDN service. This API resource allows for
|
||||||
|
// listing flavors and retrieving a specific flavor.
|
||||||
|
//
|
||||||
|
// A flavor is a mapping configuration to a CDN provider.
|
||||||
|
package flavors
|
82
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/flavors/fixtures.go
generated
vendored
Normal file
82
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/flavors/fixtures.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package flavors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
fake "github.com/rackspace/gophercloud/testhelper/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandleListCDNFlavorsSuccessfully creates an HTTP handler at `/flavors` on the test handler mux
|
||||||
|
// that responds with a `List` response.
|
||||||
|
func HandleListCDNFlavorsSuccessfully(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc("/flavors", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "GET")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
fmt.Fprintf(w, `
|
||||||
|
{
|
||||||
|
"flavors": [
|
||||||
|
{
|
||||||
|
"id": "europe",
|
||||||
|
"providers": [
|
||||||
|
{
|
||||||
|
"provider": "Fastly",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "http://www.fastly.com",
|
||||||
|
"rel": "provider_url"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "https://www.poppycdn.io/v1.0/flavors/europe",
|
||||||
|
"rel": "self"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleGetCDNFlavorSuccessfully creates an HTTP handler at `/flavors/{id}` on the test handler mux
|
||||||
|
// that responds with a `Get` response.
|
||||||
|
func HandleGetCDNFlavorSuccessfully(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc("/flavors/asia", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "GET")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
fmt.Fprintf(w, `
|
||||||
|
{
|
||||||
|
"id" : "asia",
|
||||||
|
"providers" : [
|
||||||
|
{
|
||||||
|
"provider" : "ChinaCache",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "http://www.chinacache.com",
|
||||||
|
"rel": "provider_url"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "https://www.poppycdn.io/v1.0/flavors/asia",
|
||||||
|
"rel": "self"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
}
|
27
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/flavors/requests.go
generated
vendored
Normal file
27
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/flavors/requests.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package flavors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/racker/perigee"
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// List returns a single page of CDN flavors.
|
||||||
|
func List(c *gophercloud.ServiceClient) pagination.Pager {
|
||||||
|
url := listURL(c)
|
||||||
|
createPage := func(r pagination.PageResult) pagination.Page {
|
||||||
|
return FlavorPage{pagination.SinglePageBase(r)}
|
||||||
|
}
|
||||||
|
return pagination.NewPager(c, url, createPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves a specific flavor based on its unique ID.
|
||||||
|
func Get(c *gophercloud.ServiceClient, id string) GetResult {
|
||||||
|
var res GetResult
|
||||||
|
_, res.Err = perigee.Request("GET", getURL(c, id), perigee.Options{
|
||||||
|
MoreHeaders: c.AuthenticatedHeaders(),
|
||||||
|
Results: &res.Body,
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
90
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/flavors/requests_test.go
generated
vendored
Normal file
90
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/flavors/requests_test.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
package flavors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
fake "github.com/rackspace/gophercloud/testhelper/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestList(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
HandleListCDNFlavorsSuccessfully(t)
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
|
||||||
|
err := List(fake.ServiceClient()).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
count++
|
||||||
|
actual, err := ExtractFlavors(page)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed to extract flavors: %v", err)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := []Flavor{
|
||||||
|
Flavor{
|
||||||
|
ID: "europe",
|
||||||
|
Providers: []Provider{
|
||||||
|
Provider{
|
||||||
|
Provider: "Fastly",
|
||||||
|
Links: []gophercloud.Link{
|
||||||
|
gophercloud.Link{
|
||||||
|
Href: "http://www.fastly.com",
|
||||||
|
Rel: "provider_url",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Links: []gophercloud.Link{
|
||||||
|
gophercloud.Link{
|
||||||
|
Href: "https://www.poppycdn.io/v1.0/flavors/europe",
|
||||||
|
Rel: "self",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
th.CheckDeepEquals(t, expected, actual)
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
th.CheckEquals(t, 1, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGet(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
HandleGetCDNFlavorSuccessfully(t)
|
||||||
|
|
||||||
|
expected := &Flavor{
|
||||||
|
ID: "asia",
|
||||||
|
Providers: []Provider{
|
||||||
|
Provider{
|
||||||
|
Provider: "ChinaCache",
|
||||||
|
Links: []gophercloud.Link{
|
||||||
|
gophercloud.Link{
|
||||||
|
Href: "http://www.chinacache.com",
|
||||||
|
Rel: "provider_url",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Links: []gophercloud.Link{
|
||||||
|
gophercloud.Link{
|
||||||
|
Href: "https://www.poppycdn.io/v1.0/flavors/asia",
|
||||||
|
Rel: "self",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
actual, err := Get(fake.ServiceClient(), "asia").Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
th.AssertDeepEquals(t, expected, actual)
|
||||||
|
}
|
71
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/flavors/results.go
generated
vendored
Normal file
71
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/flavors/results.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package flavors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Provider represents a provider for a particular flavor.
|
||||||
|
type Provider struct {
|
||||||
|
// Specifies the name of the provider. The name must not exceed 64 bytes in
|
||||||
|
// length and is limited to unicode, digits, underscores, and hyphens.
|
||||||
|
Provider string `mapstructure:"provider"`
|
||||||
|
// Specifies a list with an href where rel is provider_url.
|
||||||
|
Links []gophercloud.Link `mapstructure:"links"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flavor represents a mapping configuration to a CDN provider.
|
||||||
|
type Flavor struct {
|
||||||
|
// Specifies the name of the flavor. The name must not exceed 64 bytes in
|
||||||
|
// length and is limited to unicode, digits, underscores, and hyphens.
|
||||||
|
ID string `mapstructure:"id"`
|
||||||
|
// Specifies the list of providers mapped to this flavor.
|
||||||
|
Providers []Provider `mapstructure:"providers"`
|
||||||
|
// Specifies the self-navigating JSON document paths.
|
||||||
|
Links []gophercloud.Link `mapstructure:"links"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// FlavorPage is the page returned by a pager when traversing over a
|
||||||
|
// collection of CDN flavors.
|
||||||
|
type FlavorPage struct {
|
||||||
|
pagination.SinglePageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty returns true if a FlavorPage contains no Flavors.
|
||||||
|
func (r FlavorPage) IsEmpty() (bool, error) {
|
||||||
|
flavors, err := ExtractFlavors(r)
|
||||||
|
if err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
return len(flavors) == 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractFlavors extracts and returns Flavors. It is used while iterating over
|
||||||
|
// a flavors.List call.
|
||||||
|
func ExtractFlavors(page pagination.Page) ([]Flavor, error) {
|
||||||
|
var response struct {
|
||||||
|
Flavors []Flavor `json:"flavors"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := mapstructure.Decode(page.(FlavorPage).Body, &response)
|
||||||
|
return response.Flavors, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult represents the result of a get operation.
|
||||||
|
type GetResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract is a function that extracts a flavor from a GetResult.
|
||||||
|
func (r GetResult) Extract() (*Flavor, error) {
|
||||||
|
if r.Err != nil {
|
||||||
|
return nil, r.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
var res Flavor
|
||||||
|
|
||||||
|
err := mapstructure.Decode(r.Body, &res)
|
||||||
|
|
||||||
|
return &res, err
|
||||||
|
}
|
11
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/flavors/urls.go
generated
vendored
Normal file
11
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/flavors/urls.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package flavors
|
||||||
|
|
||||||
|
import "github.com/rackspace/gophercloud"
|
||||||
|
|
||||||
|
func listURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL("flavors")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL("flavors", id)
|
||||||
|
}
|
7
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/serviceassets/doc.go
generated
vendored
Normal file
7
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/serviceassets/doc.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
// Package serviceassets provides information and interaction with the
|
||||||
|
// serviceassets API resource in the OpenStack CDN service. This API resource
|
||||||
|
// allows for deleting cached assets.
|
||||||
|
//
|
||||||
|
// A service distributes assets across the network. Service assets let you
|
||||||
|
// interrogate properties about these assets and perform certain actions on them.
|
||||||
|
package serviceassets
|
19
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/serviceassets/fixtures.go
generated
vendored
Normal file
19
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/serviceassets/fixtures.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package serviceassets
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
fake "github.com/rackspace/gophercloud/testhelper/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandleDeleteCDNAssetSuccessfully creates an HTTP handler at `/services/{id}/assets` on the test handler mux
|
||||||
|
// that responds with a `Delete` response.
|
||||||
|
func HandleDeleteCDNAssetSuccessfully(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc("/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0/assets", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "DELETE")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
w.WriteHeader(http.StatusAccepted)
|
||||||
|
})
|
||||||
|
}
|
52
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/serviceassets/requests.go
generated
vendored
Normal file
52
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/serviceassets/requests.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package serviceassets
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/racker/perigee"
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeleteOptsBuilder allows extensions to add additional parameters to the Delete
|
||||||
|
// request.
|
||||||
|
type DeleteOptsBuilder interface {
|
||||||
|
ToCDNAssetDeleteParams() (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteOpts is a structure that holds options for deleting CDN service assets.
|
||||||
|
type DeleteOpts struct {
|
||||||
|
// If all is set to true, specifies that the delete occurs against all of the
|
||||||
|
// assets for the service.
|
||||||
|
All bool `q:"all"`
|
||||||
|
// Specifies the relative URL of the asset to be deleted.
|
||||||
|
URL string `q:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToCDNAssetDeleteParams formats a DeleteOpts into a query string.
|
||||||
|
func (opts DeleteOpts) ToCDNAssetDeleteParams() (string, error) {
|
||||||
|
q, err := gophercloud.BuildQueryString(opts)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return q.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete accepts a unique service ID or URL and deletes the CDN service asset associated with
|
||||||
|
// it. For example, both "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0" and
|
||||||
|
// "https://global.cdn.api.rackspacecloud.com/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0"
|
||||||
|
// are valid options for idOrURL.
|
||||||
|
func Delete(c *gophercloud.ServiceClient, idOrURL string, opts DeleteOptsBuilder) DeleteResult {
|
||||||
|
var url string
|
||||||
|
if strings.Contains(idOrURL, "/") {
|
||||||
|
url = idOrURL
|
||||||
|
} else {
|
||||||
|
url = deleteURL(c, idOrURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
var res DeleteResult
|
||||||
|
_, res.Err = perigee.Request("DELETE", url, perigee.Options{
|
||||||
|
MoreHeaders: c.AuthenticatedHeaders(),
|
||||||
|
OkCodes: []int{202},
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
18
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/serviceassets/requests_test.go
generated
vendored
Normal file
18
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/serviceassets/requests_test.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package serviceassets
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
fake "github.com/rackspace/gophercloud/testhelper/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDelete(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
HandleDeleteCDNAssetSuccessfully(t)
|
||||||
|
|
||||||
|
err := Delete(fake.ServiceClient(), "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0", nil).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
8
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/serviceassets/results.go
generated
vendored
Normal file
8
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/serviceassets/results.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package serviceassets
|
||||||
|
|
||||||
|
import "github.com/rackspace/gophercloud"
|
||||||
|
|
||||||
|
// DeleteResult represents the result of a Delete operation.
|
||||||
|
type DeleteResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
7
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/serviceassets/urls.go
generated
vendored
Normal file
7
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/serviceassets/urls.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package serviceassets
|
||||||
|
|
||||||
|
import "github.com/rackspace/gophercloud"
|
||||||
|
|
||||||
|
func deleteURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL("services", id, "assets")
|
||||||
|
}
|
7
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/services/doc.go
generated
vendored
Normal file
7
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/services/doc.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
// Package services provides information and interaction with the services API
|
||||||
|
// resource in the OpenStack CDN service. This API resource allows for
|
||||||
|
// listing, creating, updating, retrieving, and deleting services.
|
||||||
|
//
|
||||||
|
// A service represents an application that has its content cached to the edge
|
||||||
|
// nodes.
|
||||||
|
package services
|
7
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/services/errors.go
generated
vendored
Normal file
7
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/services/errors.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func no(str string) error {
|
||||||
|
return fmt.Errorf("Required parameter %s not provided", str)
|
||||||
|
}
|
372
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/services/fixtures.go
generated
vendored
Normal file
372
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/services/fixtures.go
generated
vendored
Normal file
@@ -0,0 +1,372 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
fake "github.com/rackspace/gophercloud/testhelper/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HandleListCDNServiceSuccessfully creates an HTTP handler at `/services` on the test handler mux
|
||||||
|
// that responds with a `List` response.
|
||||||
|
func HandleListCDNServiceSuccessfully(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc("/services", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "GET")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
r.ParseForm()
|
||||||
|
marker := r.Form.Get("marker")
|
||||||
|
switch marker {
|
||||||
|
case "":
|
||||||
|
fmt.Fprintf(w, `
|
||||||
|
{
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"rel": "next",
|
||||||
|
"href": "https://www.poppycdn.io/v1.0/services?marker=96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0&limit=20"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"id": "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0",
|
||||||
|
"name": "mywebsite.com",
|
||||||
|
"domains": [
|
||||||
|
{
|
||||||
|
"domain": "www.mywebsite.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"origins": [
|
||||||
|
{
|
||||||
|
"origin": "mywebsite.com",
|
||||||
|
"port": 80,
|
||||||
|
"ssl": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"caching": [
|
||||||
|
{
|
||||||
|
"name": "default",
|
||||||
|
"ttl": 3600
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "home",
|
||||||
|
"ttl": 17200,
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"name": "index",
|
||||||
|
"request_url": "/index.htm"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "images",
|
||||||
|
"ttl": 12800,
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"name": "images",
|
||||||
|
"request_url": "*.png"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"restrictions": [
|
||||||
|
{
|
||||||
|
"name": "website only",
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"name": "mywebsite.com",
|
||||||
|
"referrer": "www.mywebsite.com"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"flavor_id": "asia",
|
||||||
|
"status": "deployed",
|
||||||
|
"errors" : [],
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "https://www.poppycdn.io/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0",
|
||||||
|
"rel": "self"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "mywebsite.com.cdn123.poppycdn.net",
|
||||||
|
"rel": "access_url"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "https://www.poppycdn.io/v1.0/flavors/asia",
|
||||||
|
"rel": "flavor"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f1",
|
||||||
|
"name": "myothersite.com",
|
||||||
|
"domains": [
|
||||||
|
{
|
||||||
|
"domain": "www.myothersite.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"origins": [
|
||||||
|
{
|
||||||
|
"origin": "44.33.22.11",
|
||||||
|
"port": 80,
|
||||||
|
"ssl": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"origin": "77.66.55.44",
|
||||||
|
"port": 80,
|
||||||
|
"ssl": false,
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"name": "videos",
|
||||||
|
"request_url": "^/videos/*.m3u"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"caching": [
|
||||||
|
{
|
||||||
|
"name": "default",
|
||||||
|
"ttl": 3600
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"restrictions": [
|
||||||
|
{}
|
||||||
|
],
|
||||||
|
"flavor_id": "europe",
|
||||||
|
"status": "deployed",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "https://www.poppycdn.io/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f1",
|
||||||
|
"rel": "self"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "myothersite.com.poppycdn.net",
|
||||||
|
"rel": "access_url"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "https://www.poppycdn.io/v1.0/flavors/europe",
|
||||||
|
"rel": "flavor"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
case "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f1":
|
||||||
|
fmt.Fprintf(w, `{
|
||||||
|
"services": []
|
||||||
|
}`)
|
||||||
|
default:
|
||||||
|
t.Fatalf("Unexpected marker: [%s]", marker)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleCreateCDNServiceSuccessfully creates an HTTP handler at `/services` on the test handler mux
|
||||||
|
// that responds with a `Create` response.
|
||||||
|
func HandleCreateCDNServiceSuccessfully(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc("/services", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "POST")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
th.TestJSONRequest(t, r, `
|
||||||
|
{
|
||||||
|
"name": "mywebsite.com",
|
||||||
|
"domains": [
|
||||||
|
{
|
||||||
|
"domain": "www.mywebsite.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"domain": "blog.mywebsite.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"origins": [
|
||||||
|
{
|
||||||
|
"origin": "mywebsite.com",
|
||||||
|
"port": 80,
|
||||||
|
"ssl": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"restrictions": [
|
||||||
|
{
|
||||||
|
"name": "website only",
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"name": "mywebsite.com",
|
||||||
|
"referrer": "www.mywebsite.com"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"caching": [
|
||||||
|
{
|
||||||
|
"name": "default",
|
||||||
|
"ttl": 3600
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
"flavor_id": "cdn"
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
w.Header().Add("Location", "https://global.cdn.api.rackspacecloud.com/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0")
|
||||||
|
w.WriteHeader(http.StatusAccepted)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleGetCDNServiceSuccessfully creates an HTTP handler at `/services/{id}` on the test handler mux
|
||||||
|
// that responds with a `Get` response.
|
||||||
|
func HandleGetCDNServiceSuccessfully(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc("/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "GET")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
fmt.Fprintf(w, `
|
||||||
|
{
|
||||||
|
"id": "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0",
|
||||||
|
"name": "mywebsite.com",
|
||||||
|
"domains": [
|
||||||
|
{
|
||||||
|
"domain": "www.mywebsite.com",
|
||||||
|
"protocol": "http"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"origins": [
|
||||||
|
{
|
||||||
|
"origin": "mywebsite.com",
|
||||||
|
"port": 80,
|
||||||
|
"ssl": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"caching": [
|
||||||
|
{
|
||||||
|
"name": "default",
|
||||||
|
"ttl": 3600
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "home",
|
||||||
|
"ttl": 17200,
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"name": "index",
|
||||||
|
"request_url": "/index.htm"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "images",
|
||||||
|
"ttl": 12800,
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"name": "images",
|
||||||
|
"request_url": "*.png"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"restrictions": [
|
||||||
|
{
|
||||||
|
"name": "website only",
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"name": "mywebsite.com",
|
||||||
|
"referrer": "www.mywebsite.com"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"flavor_id": "cdn",
|
||||||
|
"status": "deployed",
|
||||||
|
"errors" : [],
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "https://global.cdn.api.rackspacecloud.com/v1.0/110011/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0",
|
||||||
|
"rel": "self"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "blog.mywebsite.com.cdn1.raxcdn.com",
|
||||||
|
"rel": "access_url"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "https://global.cdn.api.rackspacecloud.com/v1.0/110011/flavors/cdn",
|
||||||
|
"rel": "flavor"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleUpdateCDNServiceSuccessfully creates an HTTP handler at `/services/{id}` on the test handler mux
|
||||||
|
// that responds with a `Update` response.
|
||||||
|
func HandleUpdateCDNServiceSuccessfully(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc("/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "PATCH")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
th.TestJSONRequest(t, r, `
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"op": "add",
|
||||||
|
"path": "/domains/-",
|
||||||
|
"value": {"domain": "appended.mocksite4.com"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "add",
|
||||||
|
"path": "/domains/4",
|
||||||
|
"value": {"domain": "inserted.mocksite4.com"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "add",
|
||||||
|
"path": "/domains",
|
||||||
|
"value": [
|
||||||
|
{"domain": "bulkadded1.mocksite4.com"},
|
||||||
|
{"domain": "bulkadded2.mocksite4.com"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "replace",
|
||||||
|
"path": "/origins/2",
|
||||||
|
"value": {"origin": "44.33.22.11", "port": 80, "ssl": false}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "replace",
|
||||||
|
"path": "/origins",
|
||||||
|
"value": [
|
||||||
|
{"origin": "44.33.22.11", "port": 80, "ssl": false},
|
||||||
|
{"origin": "55.44.33.22", "port": 443, "ssl": true}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "remove",
|
||||||
|
"path": "/caching/8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "remove",
|
||||||
|
"path": "/caching"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"op": "replace",
|
||||||
|
"path": "/name",
|
||||||
|
"value": "differentServiceName"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
`)
|
||||||
|
w.Header().Add("Location", "https://www.poppycdn.io/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0")
|
||||||
|
w.WriteHeader(http.StatusAccepted)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleDeleteCDNServiceSuccessfully creates an HTTP handler at `/services/{id}` on the test handler mux
|
||||||
|
// that responds with a `Delete` response.
|
||||||
|
func HandleDeleteCDNServiceSuccessfully(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc("/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "DELETE")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
w.WriteHeader(http.StatusAccepted)
|
||||||
|
})
|
||||||
|
}
|
391
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/services/requests.go
generated
vendored
Normal file
391
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/services/requests.go
generated
vendored
Normal file
@@ -0,0 +1,391 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/racker/perigee"
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ListOptsBuilder allows extensions to add additional parameters to the
|
||||||
|
// List request.
|
||||||
|
type ListOptsBuilder interface {
|
||||||
|
ToCDNServiceListQuery() (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListOpts allows the filtering and sorting of paginated collections through
|
||||||
|
// the API. Marker and Limit are used for pagination.
|
||||||
|
type ListOpts struct {
|
||||||
|
Marker string `q:"marker"`
|
||||||
|
Limit int `q:"limit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToCDNServiceListQuery formats a ListOpts into a query string.
|
||||||
|
func (opts ListOpts) ToCDNServiceListQuery() (string, error) {
|
||||||
|
q, err := gophercloud.BuildQueryString(opts)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return q.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns a Pager which allows you to iterate over a collection of
|
||||||
|
// CDN services. It accepts a ListOpts struct, which allows for pagination via
|
||||||
|
// marker and limit.
|
||||||
|
func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
|
||||||
|
url := listURL(c)
|
||||||
|
if opts != nil {
|
||||||
|
query, err := opts.ToCDNServiceListQuery()
|
||||||
|
if err != nil {
|
||||||
|
return pagination.Pager{Err: err}
|
||||||
|
}
|
||||||
|
url += query
|
||||||
|
}
|
||||||
|
|
||||||
|
createPage := func(r pagination.PageResult) pagination.Page {
|
||||||
|
p := ServicePage{pagination.MarkerPageBase{PageResult: r}}
|
||||||
|
p.MarkerPageBase.Owner = p
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
pager := pagination.NewPager(c, url, createPage)
|
||||||
|
return pager
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOptsBuilder is the interface options structs have to satisfy in order
|
||||||
|
// to be used in the main Create operation in this package. Since many
|
||||||
|
// extensions decorate or modify the common logic, it is useful for them to
|
||||||
|
// satisfy a basic interface in order for them to be used.
|
||||||
|
type CreateOptsBuilder interface {
|
||||||
|
ToCDNServiceCreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOpts is the common options struct used in this package's Create
|
||||||
|
// operation.
|
||||||
|
type CreateOpts struct {
|
||||||
|
// REQUIRED. Specifies the name of the service. The minimum length for name is
|
||||||
|
// 3. The maximum length is 256.
|
||||||
|
Name string
|
||||||
|
// REQUIRED. Specifies a list of domains used by users to access their website.
|
||||||
|
Domains []Domain
|
||||||
|
// REQUIRED. Specifies a list of origin domains or IP addresses where the
|
||||||
|
// original assets are stored.
|
||||||
|
Origins []Origin
|
||||||
|
// REQUIRED. Specifies the CDN provider flavor ID to use. For a list of
|
||||||
|
// flavors, see the operation to list the available flavors. The minimum
|
||||||
|
// length for flavor_id is 1. The maximum length is 256.
|
||||||
|
FlavorID string
|
||||||
|
// OPTIONAL. Specifies the TTL rules for the assets under this service. Supports wildcards for fine-grained control.
|
||||||
|
Caching []CacheRule
|
||||||
|
// OPTIONAL. Specifies the restrictions that define who can access assets (content from the CDN cache).
|
||||||
|
Restrictions []Restriction
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToCDNServiceCreateMap casts a CreateOpts struct to a map.
|
||||||
|
func (opts CreateOpts) ToCDNServiceCreateMap() (map[string]interface{}, error) {
|
||||||
|
s := make(map[string]interface{})
|
||||||
|
|
||||||
|
if opts.Name == "" {
|
||||||
|
return nil, no("Name")
|
||||||
|
}
|
||||||
|
s["name"] = opts.Name
|
||||||
|
|
||||||
|
if opts.Domains == nil {
|
||||||
|
return nil, no("Domains")
|
||||||
|
}
|
||||||
|
for _, domain := range opts.Domains {
|
||||||
|
if domain.Domain == "" {
|
||||||
|
return nil, no("Domains[].Domain")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s["domains"] = opts.Domains
|
||||||
|
|
||||||
|
if opts.Origins == nil {
|
||||||
|
return nil, no("Origins")
|
||||||
|
}
|
||||||
|
for _, origin := range opts.Origins {
|
||||||
|
if origin.Origin == "" {
|
||||||
|
return nil, no("Origins[].Origin")
|
||||||
|
}
|
||||||
|
if origin.Rules == nil && len(opts.Origins) > 1 {
|
||||||
|
return nil, no("Origins[].Rules")
|
||||||
|
}
|
||||||
|
for _, rule := range origin.Rules {
|
||||||
|
if rule.Name == "" {
|
||||||
|
return nil, no("Origins[].Rules[].Name")
|
||||||
|
}
|
||||||
|
if rule.RequestURL == "" {
|
||||||
|
return nil, no("Origins[].Rules[].RequestURL")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s["origins"] = opts.Origins
|
||||||
|
|
||||||
|
if opts.FlavorID == "" {
|
||||||
|
return nil, no("FlavorID")
|
||||||
|
}
|
||||||
|
s["flavor_id"] = opts.FlavorID
|
||||||
|
|
||||||
|
if opts.Caching != nil {
|
||||||
|
for _, cache := range opts.Caching {
|
||||||
|
if cache.Name == "" {
|
||||||
|
return nil, no("Caching[].Name")
|
||||||
|
}
|
||||||
|
if cache.Rules != nil {
|
||||||
|
for _, rule := range cache.Rules {
|
||||||
|
if rule.Name == "" {
|
||||||
|
return nil, no("Caching[].Rules[].Name")
|
||||||
|
}
|
||||||
|
if rule.RequestURL == "" {
|
||||||
|
return nil, no("Caching[].Rules[].RequestURL")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s["caching"] = opts.Caching
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.Restrictions != nil {
|
||||||
|
for _, restriction := range opts.Restrictions {
|
||||||
|
if restriction.Name == "" {
|
||||||
|
return nil, no("Restrictions[].Name")
|
||||||
|
}
|
||||||
|
if restriction.Rules != nil {
|
||||||
|
for _, rule := range restriction.Rules {
|
||||||
|
if rule.Name == "" {
|
||||||
|
return nil, no("Restrictions[].Rules[].Name")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s["restrictions"] = opts.Restrictions
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create accepts a CreateOpts struct and creates a new CDN service using the
|
||||||
|
// values provided.
|
||||||
|
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
|
||||||
|
var res CreateResult
|
||||||
|
|
||||||
|
reqBody, err := opts.ToCDNServiceCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
res.Err = err
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send request to API
|
||||||
|
resp, err := perigee.Request("POST", createURL(c), perigee.Options{
|
||||||
|
MoreHeaders: c.AuthenticatedHeaders(),
|
||||||
|
ReqBody: &reqBody,
|
||||||
|
OkCodes: []int{202},
|
||||||
|
})
|
||||||
|
res.Header = resp.HttpResponse.Header
|
||||||
|
res.Err = err
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves a specific service based on its URL or its unique ID. For
|
||||||
|
// example, both "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0" and
|
||||||
|
// "https://global.cdn.api.rackspacecloud.com/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0"
|
||||||
|
// are valid options for idOrURL.
|
||||||
|
func Get(c *gophercloud.ServiceClient, idOrURL string) GetResult {
|
||||||
|
var url string
|
||||||
|
if strings.Contains(idOrURL, "/") {
|
||||||
|
url = idOrURL
|
||||||
|
} else {
|
||||||
|
url = getURL(c, idOrURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
var res GetResult
|
||||||
|
_, res.Err = perigee.Request("GET", url, perigee.Options{
|
||||||
|
MoreHeaders: c.AuthenticatedHeaders(),
|
||||||
|
Results: &res.Body,
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// Path is a JSON pointer location that indicates which service parameter is being added, replaced,
|
||||||
|
// or removed.
|
||||||
|
type Path struct {
|
||||||
|
baseElement string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Path) renderRoot() string {
|
||||||
|
return "/" + p.baseElement
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Path) renderDash() string {
|
||||||
|
return fmt.Sprintf("/%s/-", p.baseElement)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Path) renderIndex(index int64) string {
|
||||||
|
return fmt.Sprintf("/%s/%d", p.baseElement, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// PathDomains indicates that an update operation is to be performed on a Domain.
|
||||||
|
PathDomains = Path{baseElement: "domains"}
|
||||||
|
|
||||||
|
// PathOrigins indicates that an update operation is to be performed on an Origin.
|
||||||
|
PathOrigins = Path{baseElement: "origins"}
|
||||||
|
|
||||||
|
// PathCaching indicates that an update operation is to be performed on a CacheRule.
|
||||||
|
PathCaching = Path{baseElement: "caching"}
|
||||||
|
)
|
||||||
|
|
||||||
|
type value interface {
|
||||||
|
toPatchValue() interface{}
|
||||||
|
appropriatePath() Path
|
||||||
|
renderRootOr(func(p Path) string) string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patch represents a single update to an existing Service. Multiple updates to a service can be
|
||||||
|
// submitted at the same time.
|
||||||
|
type Patch interface {
|
||||||
|
ToCDNServiceUpdateMap() map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insertion is a Patch that requests the addition of a value (Domain, Origin, or CacheRule) to
|
||||||
|
// a Service at a fixed index. Use an Append instead to append the new value to the end of its
|
||||||
|
// collection. Pass it to the Update function as part of the Patch slice.
|
||||||
|
type Insertion struct {
|
||||||
|
Index int64
|
||||||
|
Value value
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToCDNServiceUpdateMap converts an Insertion into a request body fragment suitable for the
|
||||||
|
// Update call.
|
||||||
|
func (i Insertion) ToCDNServiceUpdateMap() map[string]interface{} {
|
||||||
|
return map[string]interface{}{
|
||||||
|
"op": "add",
|
||||||
|
"path": i.Value.renderRootOr(func(p Path) string { return p.renderIndex(i.Index) }),
|
||||||
|
"value": i.Value.toPatchValue(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append is a Patch that requests the addition of a value (Domain, Origin, or CacheRule) to a
|
||||||
|
// Service at the end of its respective collection. Use an Insertion instead to insert the value
|
||||||
|
// at a fixed index within the collection. Pass this to the Update function as part of its
|
||||||
|
// Patch slice.
|
||||||
|
type Append struct {
|
||||||
|
Value value
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToCDNServiceUpdateMap converts an Append into a request body fragment suitable for the
|
||||||
|
// Update call.
|
||||||
|
func (a Append) ToCDNServiceUpdateMap() map[string]interface{} {
|
||||||
|
return map[string]interface{}{
|
||||||
|
"op": "add",
|
||||||
|
"path": a.Value.renderRootOr(func(p Path) string { return p.renderDash() }),
|
||||||
|
"value": a.Value.toPatchValue(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replacement is a Patch that alters a specific service parameter (Domain, Origin, or CacheRule)
|
||||||
|
// in-place by index. Pass it to the Update function as part of the Patch slice.
|
||||||
|
type Replacement struct {
|
||||||
|
Value value
|
||||||
|
Index int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToCDNServiceUpdateMap converts a Replacement into a request body fragment suitable for the
|
||||||
|
// Update call.
|
||||||
|
func (r Replacement) ToCDNServiceUpdateMap() map[string]interface{} {
|
||||||
|
return map[string]interface{}{
|
||||||
|
"op": "replace",
|
||||||
|
"path": r.Value.renderRootOr(func(p Path) string { return p.renderIndex(r.Index) }),
|
||||||
|
"value": r.Value.toPatchValue(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NameReplacement specifically updates the Service name. Pass it to the Update function as part
|
||||||
|
// of the Patch slice.
|
||||||
|
type NameReplacement struct {
|
||||||
|
NewName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToCDNServiceUpdateMap converts a NameReplacement into a request body fragment suitable for the
|
||||||
|
// Update call.
|
||||||
|
func (r NameReplacement) ToCDNServiceUpdateMap() map[string]interface{} {
|
||||||
|
return map[string]interface{}{
|
||||||
|
"op": "replace",
|
||||||
|
"path": "/name",
|
||||||
|
"value": r.NewName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removal is a Patch that requests the removal of a service parameter (Domain, Origin, or
|
||||||
|
// CacheRule) by index. Pass it to the Update function as part of the Patch slice.
|
||||||
|
type Removal struct {
|
||||||
|
Path Path
|
||||||
|
Index int64
|
||||||
|
All bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToCDNServiceUpdateMap converts a Removal into a request body fragment suitable for the
|
||||||
|
// Update call.
|
||||||
|
func (r Removal) ToCDNServiceUpdateMap() map[string]interface{} {
|
||||||
|
result := map[string]interface{}{"op": "remove"}
|
||||||
|
if r.All {
|
||||||
|
result["path"] = r.Path.renderRoot()
|
||||||
|
} else {
|
||||||
|
result["path"] = r.Path.renderIndex(r.Index)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
type UpdateOpts []Patch
|
||||||
|
|
||||||
|
// Update accepts a slice of Patch operations (Insertion, Append, Replacement or Removal) and
|
||||||
|
// updates an existing CDN service using the values provided. idOrURL can be either the service's
|
||||||
|
// URL or its ID. For example, both "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0" and
|
||||||
|
// "https://global.cdn.api.rackspacecloud.com/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0"
|
||||||
|
// are valid options for idOrURL.
|
||||||
|
func Update(c *gophercloud.ServiceClient, idOrURL string, opts UpdateOpts) UpdateResult {
|
||||||
|
var url string
|
||||||
|
if strings.Contains(idOrURL, "/") {
|
||||||
|
url = idOrURL
|
||||||
|
} else {
|
||||||
|
url = updateURL(c, idOrURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
reqBody := make([]map[string]interface{}, len(opts))
|
||||||
|
for i, patch := range opts {
|
||||||
|
reqBody[i] = patch.ToCDNServiceUpdateMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := perigee.Request("PATCH", url, perigee.Options{
|
||||||
|
MoreHeaders: c.AuthenticatedHeaders(),
|
||||||
|
ReqBody: &reqBody,
|
||||||
|
OkCodes: []int{202},
|
||||||
|
})
|
||||||
|
var result UpdateResult
|
||||||
|
result.Header = resp.HttpResponse.Header
|
||||||
|
result.Err = err
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete accepts a service's ID or its URL and deletes the CDN service
|
||||||
|
// associated with it. For example, both "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0" and
|
||||||
|
// "https://global.cdn.api.rackspacecloud.com/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0"
|
||||||
|
// are valid options for idOrURL.
|
||||||
|
func Delete(c *gophercloud.ServiceClient, idOrURL string) DeleteResult {
|
||||||
|
var url string
|
||||||
|
if strings.Contains(idOrURL, "/") {
|
||||||
|
url = idOrURL
|
||||||
|
} else {
|
||||||
|
url = deleteURL(c, idOrURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
var res DeleteResult
|
||||||
|
_, res.Err = perigee.Request("DELETE", url, perigee.Options{
|
||||||
|
MoreHeaders: c.AuthenticatedHeaders(),
|
||||||
|
OkCodes: []int{202},
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
358
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/services/requests_test.go
generated
vendored
Normal file
358
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/services/requests_test.go
generated
vendored
Normal file
@@ -0,0 +1,358 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
fake "github.com/rackspace/gophercloud/testhelper/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestList(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
HandleListCDNServiceSuccessfully(t)
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
|
||||||
|
err := List(fake.ServiceClient(), &ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
count++
|
||||||
|
actual, err := ExtractServices(page)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed to extract services: %v", err)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := []Service{
|
||||||
|
Service{
|
||||||
|
ID: "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0",
|
||||||
|
Name: "mywebsite.com",
|
||||||
|
Domains: []Domain{
|
||||||
|
Domain{
|
||||||
|
Domain: "www.mywebsite.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Origins: []Origin{
|
||||||
|
Origin{
|
||||||
|
Origin: "mywebsite.com",
|
||||||
|
Port: 80,
|
||||||
|
SSL: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Caching: []CacheRule{
|
||||||
|
CacheRule{
|
||||||
|
Name: "default",
|
||||||
|
TTL: 3600,
|
||||||
|
},
|
||||||
|
CacheRule{
|
||||||
|
Name: "home",
|
||||||
|
TTL: 17200,
|
||||||
|
Rules: []TTLRule{
|
||||||
|
TTLRule{
|
||||||
|
Name: "index",
|
||||||
|
RequestURL: "/index.htm",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CacheRule{
|
||||||
|
Name: "images",
|
||||||
|
TTL: 12800,
|
||||||
|
Rules: []TTLRule{
|
||||||
|
TTLRule{
|
||||||
|
Name: "images",
|
||||||
|
RequestURL: "*.png",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Restrictions: []Restriction{
|
||||||
|
Restriction{
|
||||||
|
Name: "website only",
|
||||||
|
Rules: []RestrictionRule{
|
||||||
|
RestrictionRule{
|
||||||
|
Name: "mywebsite.com",
|
||||||
|
Referrer: "www.mywebsite.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
FlavorID: "asia",
|
||||||
|
Status: "deployed",
|
||||||
|
Errors: []Error{},
|
||||||
|
Links: []gophercloud.Link{
|
||||||
|
gophercloud.Link{
|
||||||
|
Href: "https://www.poppycdn.io/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0",
|
||||||
|
Rel: "self",
|
||||||
|
},
|
||||||
|
gophercloud.Link{
|
||||||
|
Href: "mywebsite.com.cdn123.poppycdn.net",
|
||||||
|
Rel: "access_url",
|
||||||
|
},
|
||||||
|
gophercloud.Link{
|
||||||
|
Href: "https://www.poppycdn.io/v1.0/flavors/asia",
|
||||||
|
Rel: "flavor",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Service{
|
||||||
|
ID: "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f1",
|
||||||
|
Name: "myothersite.com",
|
||||||
|
Domains: []Domain{
|
||||||
|
Domain{
|
||||||
|
Domain: "www.myothersite.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Origins: []Origin{
|
||||||
|
Origin{
|
||||||
|
Origin: "44.33.22.11",
|
||||||
|
Port: 80,
|
||||||
|
SSL: false,
|
||||||
|
},
|
||||||
|
Origin{
|
||||||
|
Origin: "77.66.55.44",
|
||||||
|
Port: 80,
|
||||||
|
SSL: false,
|
||||||
|
Rules: []OriginRule{
|
||||||
|
OriginRule{
|
||||||
|
Name: "videos",
|
||||||
|
RequestURL: "^/videos/*.m3u",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Caching: []CacheRule{
|
||||||
|
CacheRule{
|
||||||
|
Name: "default",
|
||||||
|
TTL: 3600,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Restrictions: []Restriction{},
|
||||||
|
FlavorID: "europe",
|
||||||
|
Status: "deployed",
|
||||||
|
Links: []gophercloud.Link{
|
||||||
|
gophercloud.Link{
|
||||||
|
Href: "https://www.poppycdn.io/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f1",
|
||||||
|
Rel: "self",
|
||||||
|
},
|
||||||
|
gophercloud.Link{
|
||||||
|
Href: "myothersite.com.poppycdn.net",
|
||||||
|
Rel: "access_url",
|
||||||
|
},
|
||||||
|
gophercloud.Link{
|
||||||
|
Href: "https://www.poppycdn.io/v1.0/flavors/europe",
|
||||||
|
Rel: "flavor",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
th.CheckDeepEquals(t, expected, actual)
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
if count != 1 {
|
||||||
|
t.Errorf("Expected 1 page, got %d", count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreate(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
HandleCreateCDNServiceSuccessfully(t)
|
||||||
|
|
||||||
|
createOpts := CreateOpts{
|
||||||
|
Name: "mywebsite.com",
|
||||||
|
Domains: []Domain{
|
||||||
|
Domain{
|
||||||
|
Domain: "www.mywebsite.com",
|
||||||
|
},
|
||||||
|
Domain{
|
||||||
|
Domain: "blog.mywebsite.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Origins: []Origin{
|
||||||
|
Origin{
|
||||||
|
Origin: "mywebsite.com",
|
||||||
|
Port: 80,
|
||||||
|
SSL: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Restrictions: []Restriction{
|
||||||
|
Restriction{
|
||||||
|
Name: "website only",
|
||||||
|
Rules: []RestrictionRule{
|
||||||
|
RestrictionRule{
|
||||||
|
Name: "mywebsite.com",
|
||||||
|
Referrer: "www.mywebsite.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Caching: []CacheRule{
|
||||||
|
CacheRule{
|
||||||
|
Name: "default",
|
||||||
|
TTL: 3600,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
FlavorID: "cdn",
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := "https://global.cdn.api.rackspacecloud.com/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0"
|
||||||
|
actual, err := Create(fake.ServiceClient(), createOpts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
th.AssertEquals(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGet(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
HandleGetCDNServiceSuccessfully(t)
|
||||||
|
|
||||||
|
expected := &Service{
|
||||||
|
ID: "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0",
|
||||||
|
Name: "mywebsite.com",
|
||||||
|
Domains: []Domain{
|
||||||
|
Domain{
|
||||||
|
Domain: "www.mywebsite.com",
|
||||||
|
Protocol: "http",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Origins: []Origin{
|
||||||
|
Origin{
|
||||||
|
Origin: "mywebsite.com",
|
||||||
|
Port: 80,
|
||||||
|
SSL: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Caching: []CacheRule{
|
||||||
|
CacheRule{
|
||||||
|
Name: "default",
|
||||||
|
TTL: 3600,
|
||||||
|
},
|
||||||
|
CacheRule{
|
||||||
|
Name: "home",
|
||||||
|
TTL: 17200,
|
||||||
|
Rules: []TTLRule{
|
||||||
|
TTLRule{
|
||||||
|
Name: "index",
|
||||||
|
RequestURL: "/index.htm",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
CacheRule{
|
||||||
|
Name: "images",
|
||||||
|
TTL: 12800,
|
||||||
|
Rules: []TTLRule{
|
||||||
|
TTLRule{
|
||||||
|
Name: "images",
|
||||||
|
RequestURL: "*.png",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Restrictions: []Restriction{
|
||||||
|
Restriction{
|
||||||
|
Name: "website only",
|
||||||
|
Rules: []RestrictionRule{
|
||||||
|
RestrictionRule{
|
||||||
|
Name: "mywebsite.com",
|
||||||
|
Referrer: "www.mywebsite.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
FlavorID: "cdn",
|
||||||
|
Status: "deployed",
|
||||||
|
Errors: []Error{},
|
||||||
|
Links: []gophercloud.Link{
|
||||||
|
gophercloud.Link{
|
||||||
|
Href: "https://global.cdn.api.rackspacecloud.com/v1.0/110011/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0",
|
||||||
|
Rel: "self",
|
||||||
|
},
|
||||||
|
gophercloud.Link{
|
||||||
|
Href: "blog.mywebsite.com.cdn1.raxcdn.com",
|
||||||
|
Rel: "access_url",
|
||||||
|
},
|
||||||
|
gophercloud.Link{
|
||||||
|
Href: "https://global.cdn.api.rackspacecloud.com/v1.0/110011/flavors/cdn",
|
||||||
|
Rel: "flavor",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
actual, err := Get(fake.ServiceClient(), "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0").Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
th.AssertDeepEquals(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSuccessfulUpdate(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
HandleUpdateCDNServiceSuccessfully(t)
|
||||||
|
|
||||||
|
expected := "https://www.poppycdn.io/v1.0/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0"
|
||||||
|
ops := UpdateOpts{
|
||||||
|
// Append a single Domain
|
||||||
|
Append{Value: Domain{Domain: "appended.mocksite4.com"}},
|
||||||
|
// Insert a single Domain
|
||||||
|
Insertion{
|
||||||
|
Index: 4,
|
||||||
|
Value: Domain{Domain: "inserted.mocksite4.com"},
|
||||||
|
},
|
||||||
|
// Bulk addition
|
||||||
|
Append{
|
||||||
|
Value: DomainList{
|
||||||
|
Domain{Domain: "bulkadded1.mocksite4.com"},
|
||||||
|
Domain{Domain: "bulkadded2.mocksite4.com"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Replace a single Origin
|
||||||
|
Replacement{
|
||||||
|
Index: 2,
|
||||||
|
Value: Origin{Origin: "44.33.22.11", Port: 80, SSL: false},
|
||||||
|
},
|
||||||
|
// Bulk replace Origins
|
||||||
|
Replacement{
|
||||||
|
Index: 0, // Ignored
|
||||||
|
Value: OriginList{
|
||||||
|
Origin{Origin: "44.33.22.11", Port: 80, SSL: false},
|
||||||
|
Origin{Origin: "55.44.33.22", Port: 443, SSL: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Remove a single CacheRule
|
||||||
|
Removal{
|
||||||
|
Index: 8,
|
||||||
|
Path: PathCaching,
|
||||||
|
},
|
||||||
|
// Bulk removal
|
||||||
|
Removal{
|
||||||
|
All: true,
|
||||||
|
Path: PathCaching,
|
||||||
|
},
|
||||||
|
// Service name replacement
|
||||||
|
NameReplacement{
|
||||||
|
NewName: "differentServiceName",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
actual, err := Update(fake.ServiceClient(), "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0", ops).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
th.AssertEquals(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDelete(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
HandleDeleteCDNServiceSuccessfully(t)
|
||||||
|
|
||||||
|
err := Delete(fake.ServiceClient(), "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0").ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
316
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/services/results.go
generated
vendored
Normal file
316
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/services/results.go
generated
vendored
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Domain represents a domain used by users to access their website.
|
||||||
|
type Domain struct {
|
||||||
|
// Specifies the domain used to access the assets on their website, for which
|
||||||
|
// a CNAME is given to the CDN provider.
|
||||||
|
Domain string `mapstructure:"domain" json:"domain"`
|
||||||
|
// Specifies the protocol used to access the assets on this domain. Only "http"
|
||||||
|
// or "https" are currently allowed. The default is "http".
|
||||||
|
Protocol string `mapstructure:"protocol" json:"protocol,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d Domain) toPatchValue() interface{} {
|
||||||
|
r := make(map[string]interface{})
|
||||||
|
r["domain"] = d.Domain
|
||||||
|
if d.Protocol != "" {
|
||||||
|
r["protocol"] = d.Protocol
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d Domain) appropriatePath() Path {
|
||||||
|
return PathDomains
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d Domain) renderRootOr(render func(p Path) string) string {
|
||||||
|
return render(d.appropriatePath())
|
||||||
|
}
|
||||||
|
|
||||||
|
// DomainList provides a useful way to perform bulk operations in a single Patch.
|
||||||
|
type DomainList []Domain
|
||||||
|
|
||||||
|
func (list DomainList) toPatchValue() interface{} {
|
||||||
|
r := make([]interface{}, len(list))
|
||||||
|
for i, domain := range list {
|
||||||
|
r[i] = domain.toPatchValue()
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (list DomainList) appropriatePath() Path {
|
||||||
|
return PathDomains
|
||||||
|
}
|
||||||
|
|
||||||
|
func (list DomainList) renderRootOr(_ func(p Path) string) string {
|
||||||
|
return list.appropriatePath().renderRoot()
|
||||||
|
}
|
||||||
|
|
||||||
|
// OriginRule represents a rule that defines when an origin should be accessed.
|
||||||
|
type OriginRule struct {
|
||||||
|
// Specifies the name of this rule.
|
||||||
|
Name string `mapstructure:"name" json:"name"`
|
||||||
|
// Specifies the request URL this rule should match for this origin to be used. Regex is supported.
|
||||||
|
RequestURL string `mapstructure:"request_url" json:"request_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Origin specifies a list of origin domains or IP addresses where the original assets are stored.
|
||||||
|
type Origin struct {
|
||||||
|
// Specifies the URL or IP address to pull origin content from.
|
||||||
|
Origin string `mapstructure:"origin" json:"origin"`
|
||||||
|
// Specifies the port used to access the origin. The default is port 80.
|
||||||
|
Port int `mapstructure:"port" json:"port,omitempty"`
|
||||||
|
// Specifies whether or not to use HTTPS to access the origin. The default
|
||||||
|
// is false.
|
||||||
|
SSL bool `mapstructure:"ssl" json:"ssl"`
|
||||||
|
// Specifies a collection of rules that define the conditions when this origin
|
||||||
|
// should be accessed. If there is more than one origin, the rules parameter is required.
|
||||||
|
Rules []OriginRule `mapstructure:"rules" json:"rules,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o Origin) toPatchValue() interface{} {
|
||||||
|
r := make(map[string]interface{})
|
||||||
|
r["origin"] = o.Origin
|
||||||
|
r["port"] = o.Port
|
||||||
|
r["ssl"] = o.SSL
|
||||||
|
if len(o.Rules) > 0 {
|
||||||
|
r["rules"] = make([]map[string]interface{}, len(o.Rules))
|
||||||
|
for index, rule := range o.Rules {
|
||||||
|
submap := r["rules"].([]map[string]interface{})[index]
|
||||||
|
submap["name"] = rule.Name
|
||||||
|
submap["request_url"] = rule.RequestURL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o Origin) appropriatePath() Path {
|
||||||
|
return PathOrigins
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o Origin) renderRootOr(render func(p Path) string) string {
|
||||||
|
return render(o.appropriatePath())
|
||||||
|
}
|
||||||
|
|
||||||
|
// OriginList provides a useful way to perform bulk operations in a single Patch.
|
||||||
|
type OriginList []Origin
|
||||||
|
|
||||||
|
func (list OriginList) toPatchValue() interface{} {
|
||||||
|
r := make([]interface{}, len(list))
|
||||||
|
for i, origin := range list {
|
||||||
|
r[i] = origin.toPatchValue()
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (list OriginList) appropriatePath() Path {
|
||||||
|
return PathOrigins
|
||||||
|
}
|
||||||
|
|
||||||
|
func (list OriginList) renderRootOr(_ func(p Path) string) string {
|
||||||
|
return list.appropriatePath().renderRoot()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TTLRule specifies a rule that determines if a TTL should be applied to an asset.
|
||||||
|
type TTLRule struct {
|
||||||
|
// Specifies the name of this rule.
|
||||||
|
Name string `mapstructure:"name" json:"name"`
|
||||||
|
// Specifies the request URL this rule should match for this TTL to be used. Regex is supported.
|
||||||
|
RequestURL string `mapstructure:"request_url" json:"request_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CacheRule specifies the TTL rules for the assets under this service.
|
||||||
|
type CacheRule struct {
|
||||||
|
// Specifies the name of this caching rule. Note: 'default' is a reserved name used for the default TTL setting.
|
||||||
|
Name string `mapstructure:"name" json:"name"`
|
||||||
|
// Specifies the TTL to apply.
|
||||||
|
TTL int `mapstructure:"ttl" json:"ttl"`
|
||||||
|
// Specifies a collection of rules that determine if this TTL should be applied to an asset.
|
||||||
|
Rules []TTLRule `mapstructure:"rules" json:"rules,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c CacheRule) toPatchValue() interface{} {
|
||||||
|
r := make(map[string]interface{})
|
||||||
|
r["name"] = c.Name
|
||||||
|
r["ttl"] = c.TTL
|
||||||
|
r["rules"] = make([]map[string]interface{}, len(c.Rules))
|
||||||
|
for index, rule := range c.Rules {
|
||||||
|
submap := r["rules"].([]map[string]interface{})[index]
|
||||||
|
submap["name"] = rule.Name
|
||||||
|
submap["request_url"] = rule.RequestURL
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c CacheRule) appropriatePath() Path {
|
||||||
|
return PathCaching
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c CacheRule) renderRootOr(render func(p Path) string) string {
|
||||||
|
return render(c.appropriatePath())
|
||||||
|
}
|
||||||
|
|
||||||
|
// CacheRuleList provides a useful way to perform bulk operations in a single Patch.
|
||||||
|
type CacheRuleList []CacheRule
|
||||||
|
|
||||||
|
func (list CacheRuleList) toPatchValue() interface{} {
|
||||||
|
r := make([]interface{}, len(list))
|
||||||
|
for i, rule := range list {
|
||||||
|
r[i] = rule.toPatchValue()
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (list CacheRuleList) appropriatePath() Path {
|
||||||
|
return PathCaching
|
||||||
|
}
|
||||||
|
|
||||||
|
func (list CacheRuleList) renderRootOr(_ func(p Path) string) string {
|
||||||
|
return list.appropriatePath().renderRoot()
|
||||||
|
}
|
||||||
|
|
||||||
|
// RestrictionRule specifies a rule that determines if this restriction should be applied to an asset.
|
||||||
|
type RestrictionRule struct {
|
||||||
|
// Specifies the name of this rule.
|
||||||
|
Name string `mapstructure:"name" json:"name"`
|
||||||
|
// Specifies the http host that requests must come from.
|
||||||
|
Referrer string `mapstructure:"referrer" json:"referrer,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restriction specifies a restriction that defines who can access assets (content from the CDN cache).
|
||||||
|
type Restriction struct {
|
||||||
|
// Specifies the name of this restriction.
|
||||||
|
Name string `mapstructure:"name" json:"name"`
|
||||||
|
// Specifies a collection of rules that determine if this TTL should be applied to an asset.
|
||||||
|
Rules []RestrictionRule `mapstructure:"rules" json:"rules"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error specifies an error that occurred during the previous service action.
|
||||||
|
type Error struct {
|
||||||
|
// Specifies an error message detailing why there is an error.
|
||||||
|
Message string `mapstructure:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Service represents a CDN service resource.
|
||||||
|
type Service struct {
|
||||||
|
// Specifies the service ID that represents distributed content. The value is
|
||||||
|
// a UUID, such as 96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0, that is generated by the server.
|
||||||
|
ID string `mapstructure:"id"`
|
||||||
|
// Specifies the name of the service.
|
||||||
|
Name string `mapstructure:"name"`
|
||||||
|
// Specifies a list of domains used by users to access their website.
|
||||||
|
Domains []Domain `mapstructure:"domains"`
|
||||||
|
// Specifies a list of origin domains or IP addresses where the original assets are stored.
|
||||||
|
Origins []Origin `mapstructure:"origins"`
|
||||||
|
// Specifies the TTL rules for the assets under this service. Supports wildcards for fine grained control.
|
||||||
|
Caching []CacheRule `mapstructure:"caching"`
|
||||||
|
// Specifies the restrictions that define who can access assets (content from the CDN cache).
|
||||||
|
Restrictions []Restriction `mapstructure:"restrictions" json:"restrictions,omitempty"`
|
||||||
|
// Specifies the CDN provider flavor ID to use. For a list of flavors, see the operation to list the available flavors.
|
||||||
|
FlavorID string `mapstructure:"flavor_id"`
|
||||||
|
// Specifies the current status of the service.
|
||||||
|
Status string `mapstructure:"status"`
|
||||||
|
// Specifies the list of errors that occurred during the previous service action.
|
||||||
|
Errors []Error `mapstructure:"errors"`
|
||||||
|
// Specifies the self-navigating JSON document paths.
|
||||||
|
Links []gophercloud.Link `mapstructure:"links"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServicePage is the page returned by a pager when traversing over a
|
||||||
|
// collection of CDN services.
|
||||||
|
type ServicePage struct {
|
||||||
|
pagination.MarkerPageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty returns true if a ListResult contains no services.
|
||||||
|
func (r ServicePage) IsEmpty() (bool, error) {
|
||||||
|
services, err := ExtractServices(r)
|
||||||
|
if err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
return len(services) == 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LastMarker returns the last service in a ListResult.
|
||||||
|
func (r ServicePage) LastMarker() (string, error) {
|
||||||
|
services, err := ExtractServices(r)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if len(services) == 0 {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
return (services[len(services)-1]).ID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractServices is a function that takes a ListResult and returns the services' information.
|
||||||
|
func ExtractServices(page pagination.Page) ([]Service, error) {
|
||||||
|
var response struct {
|
||||||
|
Services []Service `mapstructure:"services"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := mapstructure.Decode(page.(ServicePage).Body, &response)
|
||||||
|
return response.Services, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateResult represents the result of a Create operation.
|
||||||
|
type CreateResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract is a method that extracts the location of a newly created service.
|
||||||
|
func (r CreateResult) Extract() (string, error) {
|
||||||
|
if r.Err != nil {
|
||||||
|
return "", r.Err
|
||||||
|
}
|
||||||
|
if l, ok := r.Header["Location"]; ok && len(l) > 0 {
|
||||||
|
return l[0], nil
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult represents the result of a get operation.
|
||||||
|
type GetResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract is a function that extracts a service from a GetResult.
|
||||||
|
func (r GetResult) Extract() (*Service, error) {
|
||||||
|
if r.Err != nil {
|
||||||
|
return nil, r.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
var res Service
|
||||||
|
|
||||||
|
err := mapstructure.Decode(r.Body, &res)
|
||||||
|
|
||||||
|
return &res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateResult represents the result of a Update operation.
|
||||||
|
type UpdateResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract is a method that extracts the location of an updated service.
|
||||||
|
func (r UpdateResult) Extract() (string, error) {
|
||||||
|
if r.Err != nil {
|
||||||
|
return "", r.Err
|
||||||
|
}
|
||||||
|
if l, ok := r.Header["Location"]; ok && len(l) > 0 {
|
||||||
|
return l[0], nil
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteResult represents the result of a Delete operation.
|
||||||
|
type DeleteResult struct {
|
||||||
|
gophercloud.ErrResult
|
||||||
|
}
|
23
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/services/urls.go
generated
vendored
Normal file
23
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/cdn/v1/services/urls.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import "github.com/rackspace/gophercloud"
|
||||||
|
|
||||||
|
func listURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL("services")
|
||||||
|
}
|
||||||
|
|
||||||
|
func createURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return listURL(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL("services", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return getURL(c, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return getURL(c, id)
|
||||||
|
}
|
11
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/client.go
generated
vendored
11
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/client.go
generated
vendored
@@ -203,3 +203,14 @@ func NewBlockStorageV1(client *gophercloud.ProviderClient, eo gophercloud.Endpoi
|
|||||||
}
|
}
|
||||||
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
|
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewCDNV1 creates a ServiceClient that may be used to access the OpenStack v1
|
||||||
|
// CDN service.
|
||||||
|
func NewCDNV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
|
||||||
|
eo.ApplyDefaults("cdn")
|
||||||
|
url, err := client.EndpointLocator(eo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
|
||||||
|
}
|
||||||
|
1
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/defsecrules/doc.go
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/defsecrules/doc.go
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package defsecrules
|
108
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/defsecrules/fixtures.go
generated
vendored
Normal file
108
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/defsecrules/fixtures.go
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
package defsecrules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
fake "github.com/rackspace/gophercloud/testhelper/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
const rootPath = "/os-security-group-default-rules"
|
||||||
|
|
||||||
|
func mockListRulesResponse(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc(rootPath, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "GET")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
fmt.Fprintf(w, `
|
||||||
|
{
|
||||||
|
"security_group_default_rules": [
|
||||||
|
{
|
||||||
|
"from_port": 80,
|
||||||
|
"id": "{ruleID}",
|
||||||
|
"ip_protocol": "TCP",
|
||||||
|
"ip_range": {
|
||||||
|
"cidr": "10.10.10.0/24"
|
||||||
|
},
|
||||||
|
"to_port": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockCreateRuleResponse(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc(rootPath, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "POST")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
|
||||||
|
th.TestJSONRequest(t, r, `
|
||||||
|
{
|
||||||
|
"security_group_default_rule": {
|
||||||
|
"ip_protocol": "TCP",
|
||||||
|
"from_port": 80,
|
||||||
|
"to_port": 80,
|
||||||
|
"cidr": "10.10.12.0/24"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
fmt.Fprintf(w, `
|
||||||
|
{
|
||||||
|
"security_group_default_rule": {
|
||||||
|
"from_port": 80,
|
||||||
|
"id": "{ruleID}",
|
||||||
|
"ip_protocol": "TCP",
|
||||||
|
"ip_range": {
|
||||||
|
"cidr": "10.10.12.0/24"
|
||||||
|
},
|
||||||
|
"to_port": 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockGetRuleResponse(t *testing.T, ruleID string) {
|
||||||
|
url := rootPath + "/" + ruleID
|
||||||
|
th.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "GET")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
fmt.Fprintf(w, `
|
||||||
|
{
|
||||||
|
"security_group_default_rule": {
|
||||||
|
"id": "{ruleID}",
|
||||||
|
"from_port": 80,
|
||||||
|
"to_port": 80,
|
||||||
|
"ip_protocol": "TCP",
|
||||||
|
"ip_range": {
|
||||||
|
"cidr": "10.10.12.0/24"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockDeleteRuleResponse(t *testing.T, ruleID string) {
|
||||||
|
url := rootPath + "/" + ruleID
|
||||||
|
th.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "DELETE")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
})
|
||||||
|
}
|
111
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/defsecrules/requests.go
generated
vendored
Normal file
111
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/defsecrules/requests.go
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
package defsecrules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/racker/perigee"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// List will return a collection of default rules.
|
||||||
|
func List(client *gophercloud.ServiceClient) pagination.Pager {
|
||||||
|
createPage := func(r pagination.PageResult) pagination.Page {
|
||||||
|
return DefaultRulePage{pagination.SinglePageBase(r)}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pagination.NewPager(client, rootURL(client), createPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOpts represents the configuration for adding a new default rule.
|
||||||
|
type CreateOpts struct {
|
||||||
|
// Required - the lower bound of the port range that will be opened.
|
||||||
|
FromPort int `json:"from_port"`
|
||||||
|
|
||||||
|
// Required - the upper bound of the port range that will be opened.
|
||||||
|
ToPort int `json:"to_port"`
|
||||||
|
|
||||||
|
// Required - the protocol type that will be allowed, e.g. TCP.
|
||||||
|
IPProtocol string `json:"ip_protocol"`
|
||||||
|
|
||||||
|
// ONLY required if FromGroupID is blank. This represents the IP range that
|
||||||
|
// will be the source of network traffic to your security group. Use
|
||||||
|
// 0.0.0.0/0 to allow all IP addresses.
|
||||||
|
CIDR string `json:"cidr,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOptsBuilder builds the create rule options into a serializable format.
|
||||||
|
type CreateOptsBuilder interface {
|
||||||
|
ToRuleCreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToRuleCreateMap builds the create rule options into a serializable format.
|
||||||
|
func (opts CreateOpts) ToRuleCreateMap() (map[string]interface{}, error) {
|
||||||
|
rule := make(map[string]interface{})
|
||||||
|
|
||||||
|
if opts.FromPort == 0 {
|
||||||
|
return rule, errors.New("A FromPort must be set")
|
||||||
|
}
|
||||||
|
if opts.ToPort == 0 {
|
||||||
|
return rule, errors.New("A ToPort must be set")
|
||||||
|
}
|
||||||
|
if opts.IPProtocol == "" {
|
||||||
|
return rule, errors.New("A IPProtocol must be set")
|
||||||
|
}
|
||||||
|
if opts.CIDR == "" {
|
||||||
|
return rule, errors.New("A CIDR must be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
rule["from_port"] = opts.FromPort
|
||||||
|
rule["to_port"] = opts.ToPort
|
||||||
|
rule["ip_protocol"] = opts.IPProtocol
|
||||||
|
rule["cidr"] = opts.CIDR
|
||||||
|
|
||||||
|
return map[string]interface{}{"security_group_default_rule": rule}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create is the operation responsible for creating a new default rule.
|
||||||
|
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
|
||||||
|
var result CreateResult
|
||||||
|
|
||||||
|
reqBody, err := opts.ToRuleCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
result.Err = err
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
_, result.Err = perigee.Request("POST", rootURL(client), perigee.Options{
|
||||||
|
Results: &result.Body,
|
||||||
|
ReqBody: &reqBody,
|
||||||
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get will return details for a particular default rule.
|
||||||
|
func Get(client *gophercloud.ServiceClient, id string) GetResult {
|
||||||
|
var result GetResult
|
||||||
|
|
||||||
|
_, result.Err = perigee.Request("GET", resourceURL(client, id), perigee.Options{
|
||||||
|
Results: &result.Body,
|
||||||
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete will permanently delete a default rule from the project.
|
||||||
|
func Delete(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
|
||||||
|
var result gophercloud.ErrResult
|
||||||
|
|
||||||
|
_, result.Err = perigee.Request("DELETE", resourceURL(client, id), perigee.Options{
|
||||||
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
OkCodes: []int{204},
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
100
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/defsecrules/requests_test.go
generated
vendored
Normal file
100
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/defsecrules/requests_test.go
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
package defsecrules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
"github.com/rackspace/gophercloud/testhelper/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ruleID = "{ruleID}"
|
||||||
|
|
||||||
|
func TestList(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
mockListRulesResponse(t)
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
|
||||||
|
err := List(client.ServiceClient()).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
count++
|
||||||
|
actual, err := ExtractDefaultRules(page)
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
expected := []DefaultRule{
|
||||||
|
DefaultRule{
|
||||||
|
FromPort: 80,
|
||||||
|
ID: ruleID,
|
||||||
|
IPProtocol: "TCP",
|
||||||
|
IPRange: secgroups.IPRange{CIDR: "10.10.10.0/24"},
|
||||||
|
ToPort: 80,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
th.CheckDeepEquals(t, expected, actual)
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
th.AssertEquals(t, 1, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreate(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
mockCreateRuleResponse(t)
|
||||||
|
|
||||||
|
opts := CreateOpts{
|
||||||
|
IPProtocol: "TCP",
|
||||||
|
FromPort: 80,
|
||||||
|
ToPort: 80,
|
||||||
|
CIDR: "10.10.12.0/24",
|
||||||
|
}
|
||||||
|
|
||||||
|
group, err := Create(client.ServiceClient(), opts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
expected := &DefaultRule{
|
||||||
|
ID: ruleID,
|
||||||
|
FromPort: 80,
|
||||||
|
ToPort: 80,
|
||||||
|
IPProtocol: "TCP",
|
||||||
|
IPRange: secgroups.IPRange{CIDR: "10.10.12.0/24"},
|
||||||
|
}
|
||||||
|
th.AssertDeepEquals(t, expected, group)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGet(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
mockGetRuleResponse(t, ruleID)
|
||||||
|
|
||||||
|
group, err := Get(client.ServiceClient(), ruleID).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
expected := &DefaultRule{
|
||||||
|
ID: ruleID,
|
||||||
|
FromPort: 80,
|
||||||
|
ToPort: 80,
|
||||||
|
IPProtocol: "TCP",
|
||||||
|
IPRange: secgroups.IPRange{CIDR: "10.10.12.0/24"},
|
||||||
|
}
|
||||||
|
|
||||||
|
th.AssertDeepEquals(t, expected, group)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDelete(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
mockDeleteRuleResponse(t, ruleID)
|
||||||
|
|
||||||
|
err := Delete(client.ServiceClient(), ruleID).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
69
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/defsecrules/results.go
generated
vendored
Normal file
69
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/defsecrules/results.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
package defsecrules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultRule represents a default rule - which is identical to a
|
||||||
|
// normal security rule.
|
||||||
|
type DefaultRule secgroups.Rule
|
||||||
|
|
||||||
|
// DefaultRulePage is a single page of a DefaultRule collection.
|
||||||
|
type DefaultRulePage struct {
|
||||||
|
pagination.SinglePageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty determines whether or not a page of default rules contains any results.
|
||||||
|
func (page DefaultRulePage) IsEmpty() (bool, error) {
|
||||||
|
users, err := ExtractDefaultRules(page)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return len(users) == 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractDefaultRules returns a slice of DefaultRules contained in a single
|
||||||
|
// page of results.
|
||||||
|
func ExtractDefaultRules(page pagination.Page) ([]DefaultRule, error) {
|
||||||
|
casted := page.(DefaultRulePage).Body
|
||||||
|
var response struct {
|
||||||
|
Rules []DefaultRule `mapstructure:"security_group_default_rules"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := mapstructure.WeakDecode(casted, &response)
|
||||||
|
|
||||||
|
return response.Rules, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type commonResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateResult represents the result of a create operation.
|
||||||
|
type CreateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult represents the result of a get operation.
|
||||||
|
type GetResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract will extract a DefaultRule struct from most responses.
|
||||||
|
func (r commonResult) Extract() (*DefaultRule, error) {
|
||||||
|
if r.Err != nil {
|
||||||
|
return nil, r.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
var response struct {
|
||||||
|
Rule DefaultRule `mapstructure:"security_group_default_rule"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := mapstructure.WeakDecode(r.Body, &response)
|
||||||
|
|
||||||
|
return &response.Rule, err
|
||||||
|
}
|
13
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/defsecrules/urls.go
generated
vendored
Normal file
13
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/defsecrules/urls.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package defsecrules
|
||||||
|
|
||||||
|
import "github.com/rackspace/gophercloud"
|
||||||
|
|
||||||
|
const rulepath = "os-security-group-default-rules"
|
||||||
|
|
||||||
|
func resourceURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL(rulepath, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func rootURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL(rulepath)
|
||||||
|
}
|
@@ -5,9 +5,34 @@ import (
|
|||||||
|
|
||||||
"github.com/racker/perigee"
|
"github.com/racker/perigee"
|
||||||
"github.com/rackspace/gophercloud"
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
||||||
"github.com/rackspace/gophercloud/pagination"
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// CreateOptsExt adds a KeyPair option to the base CreateOpts.
|
||||||
|
type CreateOptsExt struct {
|
||||||
|
servers.CreateOptsBuilder
|
||||||
|
KeyName string `json:"key_name,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToServerCreateMap adds the key_name and, optionally, key_data options to
|
||||||
|
// the base server creation options.
|
||||||
|
func (opts CreateOptsExt) ToServerCreateMap() (map[string]interface{}, error) {
|
||||||
|
base, err := opts.CreateOptsBuilder.ToServerCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.KeyName == "" {
|
||||||
|
return base, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
serverMap := base["server"].(map[string]interface{})
|
||||||
|
serverMap["key_name"] = opts.KeyName
|
||||||
|
|
||||||
|
return base, nil
|
||||||
|
}
|
||||||
|
|
||||||
// List returns a Pager that allows you to iterate over a collection of KeyPairs.
|
// List returns a Pager that allows you to iterate over a collection of KeyPairs.
|
||||||
func List(client *gophercloud.ServiceClient) pagination.Pager {
|
func List(client *gophercloud.ServiceClient) pagination.Pager {
|
||||||
return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
|
return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
|
||||||
@@ -21,7 +46,7 @@ type CreateOptsBuilder interface {
|
|||||||
ToKeyPairCreateMap() (map[string]interface{}, error)
|
ToKeyPairCreateMap() (map[string]interface{}, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateOpts species keypair creation or import parameters.
|
// CreateOpts specifies keypair creation or import parameters.
|
||||||
type CreateOpts struct {
|
type CreateOpts struct {
|
||||||
// Name [required] is a friendly name to refer to this KeyPair in other services.
|
// Name [required] is a friendly name to refer to this KeyPair in other services.
|
||||||
Name string
|
Name string
|
||||||
|
1
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups/doc.go
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups/doc.go
generated
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package secgroups
|
265
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups/fixtures.go
generated
vendored
Normal file
265
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups/fixtures.go
generated
vendored
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
package secgroups
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
fake "github.com/rackspace/gophercloud/testhelper/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
const rootPath = "/os-security-groups"
|
||||||
|
|
||||||
|
const listGroupsJSON = `
|
||||||
|
{
|
||||||
|
"security_groups": [
|
||||||
|
{
|
||||||
|
"description": "default",
|
||||||
|
"id": "{groupID}",
|
||||||
|
"name": "default",
|
||||||
|
"rules": [],
|
||||||
|
"tenant_id": "openstack"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
func mockListGroupsResponse(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc(rootPath, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "GET")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
fmt.Fprintf(w, listGroupsJSON)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockListGroupsByServerResponse(t *testing.T, serverID string) {
|
||||||
|
url := fmt.Sprintf("%s/servers/%s%s", rootPath, serverID, rootPath)
|
||||||
|
th.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "GET")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
fmt.Fprintf(w, listGroupsJSON)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockCreateGroupResponse(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc(rootPath, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "POST")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
|
||||||
|
th.TestJSONRequest(t, r, `
|
||||||
|
{
|
||||||
|
"security_group": {
|
||||||
|
"name": "test",
|
||||||
|
"description": "something"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
fmt.Fprintf(w, `
|
||||||
|
{
|
||||||
|
"security_group": {
|
||||||
|
"description": "something",
|
||||||
|
"id": "{groupID}",
|
||||||
|
"name": "test",
|
||||||
|
"rules": [],
|
||||||
|
"tenant_id": "openstack"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockUpdateGroupResponse(t *testing.T, groupID string) {
|
||||||
|
url := fmt.Sprintf("%s/%s", rootPath, groupID)
|
||||||
|
th.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "PUT")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
|
||||||
|
th.TestJSONRequest(t, r, `
|
||||||
|
{
|
||||||
|
"security_group": {
|
||||||
|
"name": "new_name",
|
||||||
|
"description": "new_desc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
fmt.Fprintf(w, `
|
||||||
|
{
|
||||||
|
"security_group": {
|
||||||
|
"description": "something",
|
||||||
|
"id": "{groupID}",
|
||||||
|
"name": "new_name",
|
||||||
|
"rules": [],
|
||||||
|
"tenant_id": "openstack"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockGetGroupsResponse(t *testing.T, groupID string) {
|
||||||
|
url := fmt.Sprintf("%s/%s", rootPath, groupID)
|
||||||
|
th.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "GET")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
fmt.Fprintf(w, `
|
||||||
|
{
|
||||||
|
"security_group": {
|
||||||
|
"description": "default",
|
||||||
|
"id": "{groupID}",
|
||||||
|
"name": "default",
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"from_port": 80,
|
||||||
|
"group": {
|
||||||
|
"tenant_id": "openstack",
|
||||||
|
"name": "default"
|
||||||
|
},
|
||||||
|
"ip_protocol": "TCP",
|
||||||
|
"to_port": 85,
|
||||||
|
"parent_group_id": "{groupID}",
|
||||||
|
"ip_range": {
|
||||||
|
"cidr": "0.0.0.0"
|
||||||
|
},
|
||||||
|
"id": "{ruleID}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tenant_id": "openstack"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockGetNumericIDGroupResponse(t *testing.T, groupID int) {
|
||||||
|
url := fmt.Sprintf("%s/%d", rootPath, groupID)
|
||||||
|
th.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "GET")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
fmt.Fprintf(w, `
|
||||||
|
{
|
||||||
|
"security_group": {
|
||||||
|
"id": 12345
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockDeleteGroupResponse(t *testing.T, groupID string) {
|
||||||
|
url := fmt.Sprintf("%s/%s", rootPath, groupID)
|
||||||
|
th.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "DELETE")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusAccepted)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockAddRuleResponse(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc("/os-security-group-rules", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "POST")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
|
||||||
|
th.TestJSONRequest(t, r, `
|
||||||
|
{
|
||||||
|
"security_group_rule": {
|
||||||
|
"from_port": 22,
|
||||||
|
"ip_protocol": "TCP",
|
||||||
|
"to_port": 22,
|
||||||
|
"parent_group_id": "{groupID}",
|
||||||
|
"cidr": "0.0.0.0/0"
|
||||||
|
}
|
||||||
|
} `)
|
||||||
|
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
fmt.Fprintf(w, `
|
||||||
|
{
|
||||||
|
"security_group_rule": {
|
||||||
|
"from_port": 22,
|
||||||
|
"group": {},
|
||||||
|
"ip_protocol": "TCP",
|
||||||
|
"to_port": 22,
|
||||||
|
"parent_group_id": "{groupID}",
|
||||||
|
"ip_range": {
|
||||||
|
"cidr": "0.0.0.0/0"
|
||||||
|
},
|
||||||
|
"id": "{ruleID}"
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockDeleteRuleResponse(t *testing.T, ruleID string) {
|
||||||
|
url := fmt.Sprintf("/os-security-group-rules/%s", ruleID)
|
||||||
|
th.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "DELETE")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusAccepted)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockAddServerToGroupResponse(t *testing.T, serverID string) {
|
||||||
|
url := fmt.Sprintf("/servers/%s/action", serverID)
|
||||||
|
th.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "POST")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
|
||||||
|
th.TestJSONRequest(t, r, `
|
||||||
|
{
|
||||||
|
"addSecurityGroup": {
|
||||||
|
"name": "test"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusAccepted)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockRemoveServerFromGroupResponse(t *testing.T, serverID string) {
|
||||||
|
url := fmt.Sprintf("/servers/%s/action", serverID)
|
||||||
|
th.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "POST")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||||
|
|
||||||
|
th.TestJSONRequest(t, r, `
|
||||||
|
{
|
||||||
|
"removeSecurityGroup": {
|
||||||
|
"name": "test"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusAccepted)
|
||||||
|
})
|
||||||
|
}
|
298
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups/requests.go
generated
vendored
Normal file
298
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups/requests.go
generated
vendored
Normal file
@@ -0,0 +1,298 @@
|
|||||||
|
package secgroups
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/racker/perigee"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
func commonList(client *gophercloud.ServiceClient, url string) pagination.Pager {
|
||||||
|
createPage := func(r pagination.PageResult) pagination.Page {
|
||||||
|
return SecurityGroupPage{pagination.SinglePageBase(r)}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pagination.NewPager(client, url, createPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List will return a collection of all the security groups for a particular
|
||||||
|
// tenant.
|
||||||
|
func List(client *gophercloud.ServiceClient) pagination.Pager {
|
||||||
|
return commonList(client, rootURL(client))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListByServer will return a collection of all the security groups which are
|
||||||
|
// associated with a particular server.
|
||||||
|
func ListByServer(client *gophercloud.ServiceClient, serverID string) pagination.Pager {
|
||||||
|
return commonList(client, listByServerURL(client, serverID))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupOpts is the underlying struct responsible for creating or updating
|
||||||
|
// security groups. It therefore represents the mutable attributes of a
|
||||||
|
// security group.
|
||||||
|
type GroupOpts struct {
|
||||||
|
// Required - the name of your security group.
|
||||||
|
Name string `json:"name"`
|
||||||
|
|
||||||
|
// Required - the description of your security group.
|
||||||
|
Description string `json:"description"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateOpts is the struct responsible for creating a security group.
|
||||||
|
type CreateOpts GroupOpts
|
||||||
|
|
||||||
|
// CreateOptsBuilder builds the create options into a serializable format.
|
||||||
|
type CreateOptsBuilder interface {
|
||||||
|
ToSecGroupCreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errName = errors.New("Name is a required field")
|
||||||
|
errDesc = errors.New("Description is a required field")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ToSecGroupCreateMap builds the create options into a serializable format.
|
||||||
|
func (opts CreateOpts) ToSecGroupCreateMap() (map[string]interface{}, error) {
|
||||||
|
sg := make(map[string]interface{})
|
||||||
|
|
||||||
|
if opts.Name == "" {
|
||||||
|
return sg, errName
|
||||||
|
}
|
||||||
|
if opts.Description == "" {
|
||||||
|
return sg, errDesc
|
||||||
|
}
|
||||||
|
|
||||||
|
sg["name"] = opts.Name
|
||||||
|
sg["description"] = opts.Description
|
||||||
|
|
||||||
|
return map[string]interface{}{"security_group": sg}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create will create a new security group.
|
||||||
|
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
|
||||||
|
var result CreateResult
|
||||||
|
|
||||||
|
reqBody, err := opts.ToSecGroupCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
result.Err = err
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
_, result.Err = perigee.Request("POST", rootURL(client), perigee.Options{
|
||||||
|
Results: &result.Body,
|
||||||
|
ReqBody: &reqBody,
|
||||||
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateOpts is the struct responsible for updating an existing security group.
|
||||||
|
type UpdateOpts GroupOpts
|
||||||
|
|
||||||
|
// UpdateOptsBuilder builds the update options into a serializable format.
|
||||||
|
type UpdateOptsBuilder interface {
|
||||||
|
ToSecGroupUpdateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToSecGroupUpdateMap builds the update options into a serializable format.
|
||||||
|
func (opts UpdateOpts) ToSecGroupUpdateMap() (map[string]interface{}, error) {
|
||||||
|
sg := make(map[string]interface{})
|
||||||
|
|
||||||
|
if opts.Name == "" {
|
||||||
|
return sg, errName
|
||||||
|
}
|
||||||
|
if opts.Description == "" {
|
||||||
|
return sg, errDesc
|
||||||
|
}
|
||||||
|
|
||||||
|
sg["name"] = opts.Name
|
||||||
|
sg["description"] = opts.Description
|
||||||
|
|
||||||
|
return map[string]interface{}{"security_group": sg}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update will modify the mutable properties of a security group, notably its
|
||||||
|
// name and description.
|
||||||
|
func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
|
||||||
|
var result UpdateResult
|
||||||
|
|
||||||
|
reqBody, err := opts.ToSecGroupUpdateMap()
|
||||||
|
if err != nil {
|
||||||
|
result.Err = err
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
_, result.Err = perigee.Request("PUT", resourceURL(client, id), perigee.Options{
|
||||||
|
Results: &result.Body,
|
||||||
|
ReqBody: &reqBody,
|
||||||
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get will return details for a particular security group.
|
||||||
|
func Get(client *gophercloud.ServiceClient, id string) GetResult {
|
||||||
|
var result GetResult
|
||||||
|
|
||||||
|
_, result.Err = perigee.Request("GET", resourceURL(client, id), perigee.Options{
|
||||||
|
Results: &result.Body,
|
||||||
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete will permanently delete a security group from the project.
|
||||||
|
func Delete(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
|
||||||
|
var result gophercloud.ErrResult
|
||||||
|
|
||||||
|
_, result.Err = perigee.Request("DELETE", resourceURL(client, id), perigee.Options{
|
||||||
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
OkCodes: []int{202},
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRuleOpts represents the configuration for adding a new rule to an
|
||||||
|
// existing security group.
|
||||||
|
type CreateRuleOpts struct {
|
||||||
|
// Required - the ID of the group that this rule will be added to.
|
||||||
|
ParentGroupID string `json:"parent_group_id"`
|
||||||
|
|
||||||
|
// Required - the lower bound of the port range that will be opened.
|
||||||
|
FromPort int `json:"from_port"`
|
||||||
|
|
||||||
|
// Required - the upper bound of the port range that will be opened.
|
||||||
|
ToPort int `json:"to_port"`
|
||||||
|
|
||||||
|
// Required - the protocol type that will be allowed, e.g. TCP.
|
||||||
|
IPProtocol string `json:"ip_protocol"`
|
||||||
|
|
||||||
|
// ONLY required if FromGroupID is blank. This represents the IP range that
|
||||||
|
// will be the source of network traffic to your security group. Use
|
||||||
|
// 0.0.0.0/0 to allow all IP addresses.
|
||||||
|
CIDR string `json:"cidr,omitempty"`
|
||||||
|
|
||||||
|
// ONLY required if CIDR is blank. This value represents the ID of a group
|
||||||
|
// that forwards traffic to the parent group. So, instead of accepting
|
||||||
|
// network traffic from an entire IP range, you can instead refine the
|
||||||
|
// inbound source by an existing security group.
|
||||||
|
FromGroupID string `json:"group_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRuleOptsBuilder builds the create rule options into a serializable format.
|
||||||
|
type CreateRuleOptsBuilder interface {
|
||||||
|
ToRuleCreateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToRuleCreateMap builds the create rule options into a serializable format.
|
||||||
|
func (opts CreateRuleOpts) ToRuleCreateMap() (map[string]interface{}, error) {
|
||||||
|
rule := make(map[string]interface{})
|
||||||
|
|
||||||
|
if opts.ParentGroupID == "" {
|
||||||
|
return rule, errors.New("A ParentGroupID must be set")
|
||||||
|
}
|
||||||
|
if opts.FromPort == 0 {
|
||||||
|
return rule, errors.New("A FromPort must be set")
|
||||||
|
}
|
||||||
|
if opts.ToPort == 0 {
|
||||||
|
return rule, errors.New("A ToPort must be set")
|
||||||
|
}
|
||||||
|
if opts.IPProtocol == "" {
|
||||||
|
return rule, errors.New("A IPProtocol must be set")
|
||||||
|
}
|
||||||
|
if opts.CIDR == "" && opts.FromGroupID == "" {
|
||||||
|
return rule, errors.New("A CIDR or FromGroupID must be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
rule["parent_group_id"] = opts.ParentGroupID
|
||||||
|
rule["from_port"] = opts.FromPort
|
||||||
|
rule["to_port"] = opts.ToPort
|
||||||
|
rule["ip_protocol"] = opts.IPProtocol
|
||||||
|
|
||||||
|
if opts.CIDR != "" {
|
||||||
|
rule["cidr"] = opts.CIDR
|
||||||
|
}
|
||||||
|
if opts.FromGroupID != "" {
|
||||||
|
rule["from_group_id"] = opts.FromGroupID
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]interface{}{"security_group_rule": rule}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRule will add a new rule to an existing security group (whose ID is
|
||||||
|
// specified in CreateRuleOpts). You have the option of controlling inbound
|
||||||
|
// traffic from either an IP range (CIDR) or from another security group.
|
||||||
|
func CreateRule(client *gophercloud.ServiceClient, opts CreateRuleOptsBuilder) CreateRuleResult {
|
||||||
|
var result CreateRuleResult
|
||||||
|
|
||||||
|
reqBody, err := opts.ToRuleCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
result.Err = err
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
_, result.Err = perigee.Request("POST", rootRuleURL(client), perigee.Options{
|
||||||
|
Results: &result.Body,
|
||||||
|
ReqBody: &reqBody,
|
||||||
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRule will permanently delete a rule from a security group.
|
||||||
|
func DeleteRule(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
|
||||||
|
var result gophercloud.ErrResult
|
||||||
|
|
||||||
|
_, result.Err = perigee.Request("DELETE", resourceRuleURL(client, id), perigee.Options{
|
||||||
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
OkCodes: []int{202},
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func actionMap(prefix, groupName string) map[string]map[string]string {
|
||||||
|
return map[string]map[string]string{
|
||||||
|
prefix + "SecurityGroup": map[string]string{"name": groupName},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddServerToGroup will associate a server and a security group, enforcing the
|
||||||
|
// rules of the group on the server.
|
||||||
|
func AddServerToGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
|
||||||
|
var result gophercloud.ErrResult
|
||||||
|
|
||||||
|
_, result.Err = perigee.Request("POST", serverActionURL(client, serverID), perigee.Options{
|
||||||
|
Results: &result.Body,
|
||||||
|
ReqBody: actionMap("add", groupName),
|
||||||
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
OkCodes: []int{202},
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveServerFromGroup will disassociate a server from a security group.
|
||||||
|
func RemoveServerFromGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
|
||||||
|
var result gophercloud.ErrResult
|
||||||
|
|
||||||
|
_, result.Err = perigee.Request("POST", serverActionURL(client, serverID), perigee.Options{
|
||||||
|
Results: &result.Body,
|
||||||
|
ReqBody: actionMap("remove", groupName),
|
||||||
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
OkCodes: []int{202},
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
248
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups/requests_test.go
generated
vendored
Normal file
248
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups/requests_test.go
generated
vendored
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
package secgroups
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
"github.com/rackspace/gophercloud/testhelper/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
serverID = "{serverID}"
|
||||||
|
groupID = "{groupID}"
|
||||||
|
ruleID = "{ruleID}"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestList(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
mockListGroupsResponse(t)
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
|
||||||
|
err := List(client.ServiceClient()).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
count++
|
||||||
|
actual, err := ExtractSecurityGroups(page)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed to extract users: %v", err)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := []SecurityGroup{
|
||||||
|
SecurityGroup{
|
||||||
|
ID: groupID,
|
||||||
|
Description: "default",
|
||||||
|
Name: "default",
|
||||||
|
Rules: []Rule{},
|
||||||
|
TenantID: "openstack",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
th.CheckDeepEquals(t, expected, actual)
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
th.AssertEquals(t, 1, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListByServer(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
mockListGroupsByServerResponse(t, serverID)
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
|
||||||
|
err := ListByServer(client.ServiceClient(), serverID).EachPage(func(page pagination.Page) (bool, error) {
|
||||||
|
count++
|
||||||
|
actual, err := ExtractSecurityGroups(page)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed to extract users: %v", err)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := []SecurityGroup{
|
||||||
|
SecurityGroup{
|
||||||
|
ID: groupID,
|
||||||
|
Description: "default",
|
||||||
|
Name: "default",
|
||||||
|
Rules: []Rule{},
|
||||||
|
TenantID: "openstack",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
th.CheckDeepEquals(t, expected, actual)
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
th.AssertEquals(t, 1, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreate(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
mockCreateGroupResponse(t)
|
||||||
|
|
||||||
|
opts := CreateOpts{
|
||||||
|
Name: "test",
|
||||||
|
Description: "something",
|
||||||
|
}
|
||||||
|
|
||||||
|
group, err := Create(client.ServiceClient(), opts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
expected := &SecurityGroup{
|
||||||
|
ID: groupID,
|
||||||
|
Name: "test",
|
||||||
|
Description: "something",
|
||||||
|
TenantID: "openstack",
|
||||||
|
Rules: []Rule{},
|
||||||
|
}
|
||||||
|
th.AssertDeepEquals(t, expected, group)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdate(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
mockUpdateGroupResponse(t, groupID)
|
||||||
|
|
||||||
|
opts := UpdateOpts{
|
||||||
|
Name: "new_name",
|
||||||
|
Description: "new_desc",
|
||||||
|
}
|
||||||
|
|
||||||
|
group, err := Update(client.ServiceClient(), groupID, opts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
expected := &SecurityGroup{
|
||||||
|
ID: groupID,
|
||||||
|
Name: "new_name",
|
||||||
|
Description: "something",
|
||||||
|
TenantID: "openstack",
|
||||||
|
Rules: []Rule{},
|
||||||
|
}
|
||||||
|
th.AssertDeepEquals(t, expected, group)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGet(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
mockGetGroupsResponse(t, groupID)
|
||||||
|
|
||||||
|
group, err := Get(client.ServiceClient(), groupID).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
expected := &SecurityGroup{
|
||||||
|
ID: groupID,
|
||||||
|
Description: "default",
|
||||||
|
Name: "default",
|
||||||
|
TenantID: "openstack",
|
||||||
|
Rules: []Rule{
|
||||||
|
Rule{
|
||||||
|
FromPort: 80,
|
||||||
|
ToPort: 85,
|
||||||
|
IPProtocol: "TCP",
|
||||||
|
IPRange: IPRange{CIDR: "0.0.0.0"},
|
||||||
|
Group: Group{TenantID: "openstack", Name: "default"},
|
||||||
|
ParentGroupID: groupID,
|
||||||
|
ID: ruleID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
th.AssertDeepEquals(t, expected, group)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetNumericID(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
numericGroupID := 12345
|
||||||
|
|
||||||
|
mockGetNumericIDGroupResponse(t, numericGroupID)
|
||||||
|
|
||||||
|
group, err := Get(client.ServiceClient(), "12345").Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
expected := &SecurityGroup{ID: "12345"}
|
||||||
|
th.AssertDeepEquals(t, expected, group)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDelete(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
mockDeleteGroupResponse(t, groupID)
|
||||||
|
|
||||||
|
err := Delete(client.ServiceClient(), groupID).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddRule(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
mockAddRuleResponse(t)
|
||||||
|
|
||||||
|
opts := CreateRuleOpts{
|
||||||
|
ParentGroupID: groupID,
|
||||||
|
FromPort: 22,
|
||||||
|
ToPort: 22,
|
||||||
|
IPProtocol: "TCP",
|
||||||
|
CIDR: "0.0.0.0/0",
|
||||||
|
}
|
||||||
|
|
||||||
|
rule, err := CreateRule(client.ServiceClient(), opts).Extract()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
|
||||||
|
expected := &Rule{
|
||||||
|
FromPort: 22,
|
||||||
|
ToPort: 22,
|
||||||
|
Group: Group{},
|
||||||
|
IPProtocol: "TCP",
|
||||||
|
ParentGroupID: groupID,
|
||||||
|
IPRange: IPRange{CIDR: "0.0.0.0/0"},
|
||||||
|
ID: ruleID,
|
||||||
|
}
|
||||||
|
|
||||||
|
th.AssertDeepEquals(t, expected, rule)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteRule(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
mockDeleteRuleResponse(t, ruleID)
|
||||||
|
|
||||||
|
err := DeleteRule(client.ServiceClient(), ruleID).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddServer(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
mockAddServerToGroupResponse(t, serverID)
|
||||||
|
|
||||||
|
err := AddServerToGroup(client.ServiceClient(), serverID, "test").ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemoveServer(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
mockRemoveServerFromGroupResponse(t, serverID)
|
||||||
|
|
||||||
|
err := RemoveServerFromGroup(client.ServiceClient(), serverID, "test").ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
147
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups/results.go
generated
vendored
Normal file
147
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups/results.go
generated
vendored
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
package secgroups
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
"github.com/rackspace/gophercloud/pagination"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SecurityGroup represents a security group.
|
||||||
|
type SecurityGroup struct {
|
||||||
|
// The unique ID of the group. If Neutron is installed, this ID will be
|
||||||
|
// represented as a string UUID; if Neutron is not installed, it will be a
|
||||||
|
// numeric ID. For the sake of consistency, we always cast it to a string.
|
||||||
|
ID string
|
||||||
|
|
||||||
|
// The human-readable name of the group, which needs to be unique.
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// The human-readable description of the group.
|
||||||
|
Description string
|
||||||
|
|
||||||
|
// The rules which determine how this security group operates.
|
||||||
|
Rules []Rule
|
||||||
|
|
||||||
|
// The ID of the tenant to which this security group belongs.
|
||||||
|
TenantID string `mapstructure:"tenant_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rule represents a security group rule, a policy which determines how a
|
||||||
|
// security group operates and what inbound traffic it allows in.
|
||||||
|
type Rule struct {
|
||||||
|
// The unique ID. If Neutron is installed, this ID will be
|
||||||
|
// represented as a string UUID; if Neutron is not installed, it will be a
|
||||||
|
// numeric ID. For the sake of consistency, we always cast it to a string.
|
||||||
|
ID string
|
||||||
|
|
||||||
|
// The lower bound of the port range which this security group should open up
|
||||||
|
FromPort int `mapstructure:"from_port"`
|
||||||
|
|
||||||
|
// The upper bound of the port range which this security group should open up
|
||||||
|
ToPort int `mapstructure:"to_port"`
|
||||||
|
|
||||||
|
// The IP protocol (e.g. TCP) which the security group accepts
|
||||||
|
IPProtocol string `mapstructure:"ip_protocol"`
|
||||||
|
|
||||||
|
// The CIDR IP range whose traffic can be received
|
||||||
|
IPRange IPRange `mapstructure:"ip_range"`
|
||||||
|
|
||||||
|
// The security group ID to which this rule belongs
|
||||||
|
ParentGroupID string `mapstructure:"parent_group_id"`
|
||||||
|
|
||||||
|
// Not documented.
|
||||||
|
Group Group
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPRange represents the IP range whose traffic will be accepted by the
|
||||||
|
// security group.
|
||||||
|
type IPRange struct {
|
||||||
|
CIDR string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group represents a group.
|
||||||
|
type Group struct {
|
||||||
|
TenantID string `mapstructure:"tenant_id"`
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecurityGroupPage is a single page of a SecurityGroup collection.
|
||||||
|
type SecurityGroupPage struct {
|
||||||
|
pagination.SinglePageBase
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEmpty determines whether or not a page of Security Groups contains any results.
|
||||||
|
func (page SecurityGroupPage) IsEmpty() (bool, error) {
|
||||||
|
users, err := ExtractSecurityGroups(page)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return len(users) == 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractSecurityGroups returns a slice of SecurityGroups contained in a single page of results.
|
||||||
|
func ExtractSecurityGroups(page pagination.Page) ([]SecurityGroup, error) {
|
||||||
|
casted := page.(SecurityGroupPage).Body
|
||||||
|
var response struct {
|
||||||
|
SecurityGroups []SecurityGroup `mapstructure:"security_groups"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := mapstructure.WeakDecode(casted, &response)
|
||||||
|
|
||||||
|
return response.SecurityGroups, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type commonResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateResult represents the result of a create operation.
|
||||||
|
type CreateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetResult represents the result of a get operation.
|
||||||
|
type GetResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateResult represents the result of an update operation.
|
||||||
|
type UpdateResult struct {
|
||||||
|
commonResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract will extract a SecurityGroup struct from most responses.
|
||||||
|
func (r commonResult) Extract() (*SecurityGroup, error) {
|
||||||
|
if r.Err != nil {
|
||||||
|
return nil, r.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
var response struct {
|
||||||
|
SecurityGroup SecurityGroup `mapstructure:"security_group"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := mapstructure.WeakDecode(r.Body, &response)
|
||||||
|
|
||||||
|
return &response.SecurityGroup, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRuleResult represents the result when adding rules to a security group.
|
||||||
|
type CreateRuleResult struct {
|
||||||
|
gophercloud.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract will extract a Rule struct from a CreateRuleResult.
|
||||||
|
func (r CreateRuleResult) Extract() (*Rule, error) {
|
||||||
|
if r.Err != nil {
|
||||||
|
return nil, r.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
var response struct {
|
||||||
|
Rule Rule `mapstructure:"security_group_rule"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := mapstructure.WeakDecode(r.Body, &response)
|
||||||
|
|
||||||
|
return &response.Rule, err
|
||||||
|
}
|
32
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups/urls.go
generated
vendored
Normal file
32
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups/urls.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package secgroups
|
||||||
|
|
||||||
|
import "github.com/rackspace/gophercloud"
|
||||||
|
|
||||||
|
const (
|
||||||
|
secgrouppath = "os-security-groups"
|
||||||
|
rulepath = "os-security-group-rules"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL(secgrouppath, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func rootURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL(secgrouppath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listByServerURL(c *gophercloud.ServiceClient, serverID string) string {
|
||||||
|
return c.ServiceURL(secgrouppath, "servers", serverID, secgrouppath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func rootRuleURL(c *gophercloud.ServiceClient) string {
|
||||||
|
return c.ServiceURL(rulepath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceRuleURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL(rulepath, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func serverActionURL(c *gophercloud.ServiceClient, id string) string {
|
||||||
|
return c.ServiceURL("servers", id, "action")
|
||||||
|
}
|
5
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/startstop/doc.go
generated
vendored
Normal file
5
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/startstop/doc.go
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
/*
|
||||||
|
Package startstop provides functionality to start and stop servers that have
|
||||||
|
been provisioned by the OpenStack Compute service.
|
||||||
|
*/
|
||||||
|
package startstop
|
27
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/startstop/fixtures.go
generated
vendored
Normal file
27
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/startstop/fixtures.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package startstop
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
"github.com/rackspace/gophercloud/testhelper/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mockStartServerResponse(t *testing.T, id string) {
|
||||||
|
th.Mux.HandleFunc("/servers/"+id+"/action", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "POST")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
|
||||||
|
th.TestJSONRequest(t, r, `{"os-start": null}`)
|
||||||
|
w.WriteHeader(http.StatusAccepted)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockStopServerResponse(t *testing.T, id string) {
|
||||||
|
th.Mux.HandleFunc("/servers/"+id+"/action", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "POST")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
|
||||||
|
th.TestJSONRequest(t, r, `{"os-stop": null}`)
|
||||||
|
w.WriteHeader(http.StatusAccepted)
|
||||||
|
})
|
||||||
|
}
|
40
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/startstop/requests.go
generated
vendored
Normal file
40
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/startstop/requests.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package startstop
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/racker/perigee"
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
)
|
||||||
|
|
||||||
|
func actionURL(client *gophercloud.ServiceClient, id string) string {
|
||||||
|
return client.ServiceURL("servers", id, "action")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start is the operation responsible for starting a Compute server.
|
||||||
|
func Start(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
|
||||||
|
var res gophercloud.ErrResult
|
||||||
|
|
||||||
|
reqBody := map[string]interface{}{"os-start": nil}
|
||||||
|
|
||||||
|
_, res.Err = perigee.Request("POST", actionURL(client, id), perigee.Options{
|
||||||
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
ReqBody: reqBody,
|
||||||
|
OkCodes: []int{202},
|
||||||
|
})
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop is the operation responsible for stopping a Compute server.
|
||||||
|
func Stop(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
|
||||||
|
var res gophercloud.ErrResult
|
||||||
|
|
||||||
|
reqBody := map[string]interface{}{"os-stop": nil}
|
||||||
|
|
||||||
|
_, res.Err = perigee.Request("POST", actionURL(client, id), perigee.Options{
|
||||||
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
ReqBody: reqBody,
|
||||||
|
OkCodes: []int{202},
|
||||||
|
})
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
30
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/startstop/requests_test.go
generated
vendored
Normal file
30
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/startstop/requests_test.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package startstop
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
th "github.com/rackspace/gophercloud/testhelper"
|
||||||
|
"github.com/rackspace/gophercloud/testhelper/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
const serverID = "{serverId}"
|
||||||
|
|
||||||
|
func TestStart(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
mockStartServerResponse(t, serverID)
|
||||||
|
|
||||||
|
err := Start(client.ServiceClient(), serverID).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStop(t *testing.T) {
|
||||||
|
th.SetupHTTP()
|
||||||
|
defer th.TeardownHTTP()
|
||||||
|
|
||||||
|
mockStopServerResponse(t, serverID)
|
||||||
|
|
||||||
|
err := Stop(client.ServiceClient(), serverID).ExtractErr()
|
||||||
|
th.AssertNoErr(t, err)
|
||||||
|
}
|
@@ -457,3 +457,103 @@ func HandleRebuildSuccessfully(t *testing.T, response string) {
|
|||||||
fmt.Fprintf(w, response)
|
fmt.Fprintf(w, response)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HandleServerRescueSuccessfully sets up the test server to respond to a server Rescue request.
|
||||||
|
func HandleServerRescueSuccessfully(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc("/servers/1234asdf/action", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "POST")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
|
||||||
|
th.TestJSONRequest(t, r, `{ "rescue": { "adminPass": "1234567890" } }`)
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write([]byte(`{ "adminPass": "1234567890" }`))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleMetadatumGetSuccessfully sets up the test server to respond to a metadatum Get request.
|
||||||
|
func HandleMetadatumGetSuccessfully(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc("/servers/1234asdf/metadata/foo", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "GET")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
|
||||||
|
th.TestHeader(t, r, "Accept", "application/json")
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.Write([]byte(`{ "meta": {"foo":"bar"}}`))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleMetadatumCreateSuccessfully sets up the test server to respond to a metadatum Create request.
|
||||||
|
func HandleMetadatumCreateSuccessfully(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc("/servers/1234asdf/metadata/foo", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "PUT")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
|
||||||
|
th.TestJSONRequest(t, r, `{
|
||||||
|
"meta": {
|
||||||
|
"foo": "bar"
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.Write([]byte(`{ "meta": {"foo":"bar"}}`))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleMetadatumDeleteSuccessfully sets up the test server to respond to a metadatum Delete request.
|
||||||
|
func HandleMetadatumDeleteSuccessfully(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc("/servers/1234asdf/metadata/foo", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "DELETE")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleMetadataGetSuccessfully sets up the test server to respond to a metadata Get request.
|
||||||
|
func HandleMetadataGetSuccessfully(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc("/servers/1234asdf/metadata", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "GET")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
|
||||||
|
th.TestHeader(t, r, "Accept", "application/json")
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write([]byte(`{ "metadata": {"foo":"bar", "this":"that"}}`))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleMetadataResetSuccessfully sets up the test server to respond to a metadata Create request.
|
||||||
|
func HandleMetadataResetSuccessfully(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc("/servers/1234asdf/metadata", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "PUT")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
|
||||||
|
th.TestJSONRequest(t, r, `{
|
||||||
|
"metadata": {
|
||||||
|
"foo": "bar",
|
||||||
|
"this": "that"
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.Write([]byte(`{ "metadata": {"foo":"bar", "this":"that"}}`))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleMetadataUpdateSuccessfully sets up the test server to respond to a metadata Update request.
|
||||||
|
func HandleMetadataUpdateSuccessfully(t *testing.T) {
|
||||||
|
th.Mux.HandleFunc("/servers/1234asdf/metadata", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
th.TestMethod(t, r, "POST")
|
||||||
|
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
|
||||||
|
th.TestJSONRequest(t, r, `{
|
||||||
|
"metadata": {
|
||||||
|
"foo": "baz",
|
||||||
|
"this": "those"
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
w.Write([]byte(`{ "metadata": {"foo":"baz", "this":"those"}}`))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@@ -2,6 +2,7 @@ package servers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/racker/perigee"
|
"github.com/racker/perigee"
|
||||||
@@ -131,6 +132,16 @@ type CreateOpts struct {
|
|||||||
|
|
||||||
// ConfigDrive [optional] enables metadata injection through a configuration drive.
|
// ConfigDrive [optional] enables metadata injection through a configuration drive.
|
||||||
ConfigDrive bool
|
ConfigDrive bool
|
||||||
|
|
||||||
|
// AdminPass [optional] sets the root user password. If not set, a randomly-generated
|
||||||
|
// password will be created and returned in the response.
|
||||||
|
AdminPass string
|
||||||
|
|
||||||
|
// AccessIPv4 [optional] specifies an IPv4 address for the instance.
|
||||||
|
AccessIPv4 string
|
||||||
|
|
||||||
|
// AccessIPv6 [optional] specifies an IPv6 address for the instance.
|
||||||
|
AccessIPv6 string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToServerCreateMap assembles a request body based on the contents of a CreateOpts.
|
// ToServerCreateMap assembles a request body based on the contents of a CreateOpts.
|
||||||
@@ -158,12 +169,22 @@ func (opts CreateOpts) ToServerCreateMap() (map[string]interface{}, error) {
|
|||||||
if opts.Metadata != nil {
|
if opts.Metadata != nil {
|
||||||
server["metadata"] = opts.Metadata
|
server["metadata"] = opts.Metadata
|
||||||
}
|
}
|
||||||
|
if opts.AdminPass != "" {
|
||||||
|
server["adminPass"] = opts.AdminPass
|
||||||
|
}
|
||||||
|
if opts.AccessIPv4 != "" {
|
||||||
|
server["accessIPv4"] = opts.AccessIPv4
|
||||||
|
}
|
||||||
|
if opts.AccessIPv6 != "" {
|
||||||
|
server["accessIPv6"] = opts.AccessIPv6
|
||||||
|
}
|
||||||
|
|
||||||
if len(opts.SecurityGroups) > 0 {
|
if len(opts.SecurityGroups) > 0 {
|
||||||
securityGroups := make([]map[string]interface{}, len(opts.SecurityGroups))
|
securityGroups := make([]map[string]interface{}, len(opts.SecurityGroups))
|
||||||
for i, groupName := range opts.SecurityGroups {
|
for i, groupName := range opts.SecurityGroups {
|
||||||
securityGroups[i] = map[string]interface{}{"name": groupName}
|
securityGroups[i] = map[string]interface{}{"name": groupName}
|
||||||
}
|
}
|
||||||
|
server["security_groups"] = securityGroups
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(opts.Networks) > 0 {
|
if len(opts.Networks) > 0 {
|
||||||
@@ -221,6 +242,7 @@ func Get(client *gophercloud.ServiceClient, id string) GetResult {
|
|||||||
_, result.Err = perigee.Request("GET", getURL(client, id), perigee.Options{
|
_, result.Err = perigee.Request("GET", getURL(client, id), perigee.Options{
|
||||||
Results: &result.Body,
|
Results: &result.Body,
|
||||||
MoreHeaders: client.AuthenticatedHeaders(),
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
OkCodes: []int{200, 203},
|
||||||
})
|
})
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -475,7 +497,7 @@ type ResizeOpts struct {
|
|||||||
FlavorRef string
|
FlavorRef string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToServerResizeMap formats a ResizeOpts as a map that can be used as a JSON request body to the
|
// ToServerResizeMap formats a ResizeOpts as a map that can be used as a JSON request body for the
|
||||||
// Resize request.
|
// Resize request.
|
||||||
func (opts ResizeOpts) ToServerResizeMap() (map[string]interface{}, error) {
|
func (opts ResizeOpts) ToServerResizeMap() (map[string]interface{}, error) {
|
||||||
resize := map[string]interface{}{
|
resize := map[string]interface{}{
|
||||||
@@ -536,3 +558,182 @@ func RevertResize(client *gophercloud.ServiceClient, id string) ActionResult {
|
|||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RescueOptsBuilder is an interface that allows extensions to override the
|
||||||
|
// default structure of a Rescue request.
|
||||||
|
type RescueOptsBuilder interface {
|
||||||
|
ToServerRescueMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RescueOpts represents the configuration options used to control a Rescue
|
||||||
|
// option.
|
||||||
|
type RescueOpts struct {
|
||||||
|
// AdminPass is the desired administrative password for the instance in
|
||||||
|
// RESCUE mode. If it's left blank, the server will generate a password.
|
||||||
|
AdminPass string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToServerRescueMap formats a RescueOpts as a map that can be used as a JSON
|
||||||
|
// request body for the Rescue request.
|
||||||
|
func (opts RescueOpts) ToServerRescueMap() (map[string]interface{}, error) {
|
||||||
|
server := make(map[string]interface{})
|
||||||
|
if opts.AdminPass != "" {
|
||||||
|
server["adminPass"] = opts.AdminPass
|
||||||
|
}
|
||||||
|
return map[string]interface{}{"rescue": server}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rescue instructs the provider to place the server into RESCUE mode.
|
||||||
|
func Rescue(client *gophercloud.ServiceClient, id string, opts RescueOptsBuilder) RescueResult {
|
||||||
|
var result RescueResult
|
||||||
|
|
||||||
|
if id == "" {
|
||||||
|
result.Err = fmt.Errorf("ID is required")
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
reqBody, err := opts.ToServerRescueMap()
|
||||||
|
if err != nil {
|
||||||
|
result.Err = err
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
_, result.Err = perigee.Request("POST", actionURL(client, id), perigee.Options{
|
||||||
|
Results: &result.Body,
|
||||||
|
ReqBody: &reqBody,
|
||||||
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
OkCodes: []int{200},
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetMetadataOptsBuilder allows extensions to add additional parameters to the
|
||||||
|
// Reset request.
|
||||||
|
type ResetMetadataOptsBuilder interface {
|
||||||
|
ToMetadataResetMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MetadataOpts is a map that contains key-value pairs.
|
||||||
|
type MetadataOpts map[string]string
|
||||||
|
|
||||||
|
// ToMetadataResetMap assembles a body for a Reset request based on the contents of a MetadataOpts.
|
||||||
|
func (opts MetadataOpts) ToMetadataResetMap() (map[string]interface{}, error) {
|
||||||
|
return map[string]interface{}{"metadata": opts}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToMetadataUpdateMap assembles a body for an Update request based on the contents of a MetadataOpts.
|
||||||
|
func (opts MetadataOpts) ToMetadataUpdateMap() (map[string]interface{}, error) {
|
||||||
|
return map[string]interface{}{"metadata": opts}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetMetadata will create multiple new key-value pairs for the given server ID.
|
||||||
|
// Note: Using this operation will erase any already-existing metadata and create
|
||||||
|
// the new metadata provided. To keep any already-existing metadata, use the
|
||||||
|
// UpdateMetadatas or UpdateMetadata function.
|
||||||
|
func ResetMetadata(client *gophercloud.ServiceClient, id string, opts ResetMetadataOptsBuilder) ResetMetadataResult {
|
||||||
|
var res ResetMetadataResult
|
||||||
|
metadata, err := opts.ToMetadataResetMap()
|
||||||
|
if err != nil {
|
||||||
|
res.Err = err
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
_, res.Err = perigee.Request("PUT", metadataURL(client, id), perigee.Options{
|
||||||
|
ReqBody: metadata,
|
||||||
|
Results: &res.Body,
|
||||||
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metadata requests all the metadata for the given server ID.
|
||||||
|
func Metadata(client *gophercloud.ServiceClient, id string) GetMetadataResult {
|
||||||
|
var res GetMetadataResult
|
||||||
|
_, res.Err = perigee.Request("GET", metadataURL(client, id), perigee.Options{
|
||||||
|
Results: &res.Body,
|
||||||
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateMetadataOptsBuilder allows extensions to add additional parameters to the
|
||||||
|
// Create request.
|
||||||
|
type UpdateMetadataOptsBuilder interface {
|
||||||
|
ToMetadataUpdateMap() (map[string]interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateMetadata updates (or creates) all the metadata specified by opts for the given server ID.
|
||||||
|
// This operation does not affect already-existing metadata that is not specified
|
||||||
|
// by opts.
|
||||||
|
func UpdateMetadata(client *gophercloud.ServiceClient, id string, opts UpdateMetadataOptsBuilder) UpdateMetadataResult {
|
||||||
|
var res UpdateMetadataResult
|
||||||
|
metadata, err := opts.ToMetadataUpdateMap()
|
||||||
|
if err != nil {
|
||||||
|
res.Err = err
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
_, res.Err = perigee.Request("POST", metadataURL(client, id), perigee.Options{
|
||||||
|
ReqBody: metadata,
|
||||||
|
Results: &res.Body,
|
||||||
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// MetadatumOptsBuilder allows extensions to add additional parameters to the
|
||||||
|
// Create request.
|
||||||
|
type MetadatumOptsBuilder interface {
|
||||||
|
ToMetadatumCreateMap() (map[string]interface{}, string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MetadatumOpts is a map of length one that contains a key-value pair.
|
||||||
|
type MetadatumOpts map[string]string
|
||||||
|
|
||||||
|
// ToMetadatumCreateMap assembles a body for a Create request based on the contents of a MetadataumOpts.
|
||||||
|
func (opts MetadatumOpts) ToMetadatumCreateMap() (map[string]interface{}, string, error) {
|
||||||
|
if len(opts) != 1 {
|
||||||
|
return nil, "", errors.New("CreateMetadatum operation must have 1 and only 1 key-value pair.")
|
||||||
|
}
|
||||||
|
metadatum := map[string]interface{}{"meta": opts}
|
||||||
|
var key string
|
||||||
|
for k := range metadatum["meta"].(MetadatumOpts) {
|
||||||
|
key = k
|
||||||
|
}
|
||||||
|
return metadatum, key, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateMetadatum will create or update the key-value pair with the given key for the given server ID.
|
||||||
|
func CreateMetadatum(client *gophercloud.ServiceClient, id string, opts MetadatumOptsBuilder) CreateMetadatumResult {
|
||||||
|
var res CreateMetadatumResult
|
||||||
|
metadatum, key, err := opts.ToMetadatumCreateMap()
|
||||||
|
if err != nil {
|
||||||
|
res.Err = err
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
_, res.Err = perigee.Request("PUT", metadatumURL(client, id, key), perigee.Options{
|
||||||
|
ReqBody: metadatum,
|
||||||
|
Results: &res.Body,
|
||||||
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metadatum requests the key-value pair with the given key for the given server ID.
|
||||||
|
func Metadatum(client *gophercloud.ServiceClient, id, key string) GetMetadatumResult {
|
||||||
|
var res GetMetadatumResult
|
||||||
|
_, res.Err = perigee.Request("GET", metadatumURL(client, id, key), perigee.Options{
|
||||||
|
Results: &res.Body,
|
||||||
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteMetadatum will delete the key-value pair with the given key for the given server ID.
|
||||||
|
func DeleteMetadatum(client *gophercloud.ServiceClient, id, key string) DeleteMetadatumResult {
|
||||||
|
var res DeleteMetadatumResult
|
||||||
|
_, res.Err = perigee.Request("DELETE", metadatumURL(client, id, key), perigee.Options{
|
||||||
|
Results: &res.Body,
|
||||||
|
MoreHeaders: client.AuthenticatedHeaders(),
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user