Merge pull request #4478 from thommay/rackspace_cloud_base
Basic Rackspace cloud support
This commit is contained in:
commit
003c0986b4
4
Godeps/Godeps.json
generated
4
Godeps/Godeps.json
generated
@ -203,8 +203,8 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/rackspace/gophercloud",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "da56de6a59e53fdd61be1b5d9b87df34c47ac420"
|
||||
"Comment": "v1.0.0-336-g2a6e319",
|
||||
"Rev": "2a6e3190447abe5d000f951595ead1cf98df72d8"
|
||||
},
|
||||
{
|
||||
"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:
|
||||
- 1.1
|
||||
- 1.2
|
||||
- 1.3
|
||||
- 1.4
|
||||
- tip
|
||||
script: script/cibuild
|
||||
after_success:
|
||||
@ -12,3 +14,4 @@ after_success:
|
||||
- go get github.com/mattn/goveralls
|
||||
- export PATH=$PATH:$HOME/gopath/bin/
|
||||
- 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:
|
||||
|
||||
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:
|
||||
|
||||
|
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)
|
||||
|
||||
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)
|
||||
|
||||
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) {
|
||||
|
||||
client, err := newClient()
|
||||
client, err := newClient(t)
|
||||
th.AssertNoErr(t, err)
|
||||
|
||||
|
||||
v, err := volumes.Create(client, &volumes.CreateOpts{
|
||||
Name: "gophercloud-test-volume",
|
||||
Size: 1,
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
th "github.com/rackspace/gophercloud/testhelper"
|
||||
)
|
||||
|
||||
func newClient() (*gophercloud.ServiceClient, error) {
|
||||
func newClient(t *testing.T) (*gophercloud.ServiceClient, error) {
|
||||
ao, err := openstack.AuthOptionsFromEnv()
|
||||
th.AssertNoErr(t, err)
|
||||
|
||||
@ -26,7 +26,7 @@ func newClient() (*gophercloud.ServiceClient, error) {
|
||||
}
|
||||
|
||||
func TestVolumes(t *testing.T) {
|
||||
client, err := newClient()
|
||||
client, err := newClient(t)
|
||||
th.AssertNoErr(t, err)
|
||||
|
||||
cv, err := volumes.Create(client, &volumes.CreateOpts{
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
func TestVolumeTypes(t *testing.T) {
|
||||
client, err := newClient()
|
||||
client, err := newClient(t)
|
||||
th.AssertNoErr(t, err)
|
||||
|
||||
vt, err := volumetypes.Create(client, &volumetypes.CreateOpts{
|
||||
|
@ -5,10 +5,10 @@ package v2
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/rackspace/gophercloud/acceptance/tools"
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume"
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
||||
th "github.com/rackspace/gophercloud/testhelper"
|
||||
"github.com/smashwilson/gophercloud/acceptance/tools"
|
||||
)
|
||||
|
||||
func TestBootFromVolume(t *testing.T) {
|
||||
@ -37,14 +37,19 @@ func TestBootFromVolume(t *testing.T) {
|
||||
|
||||
serverCreateOpts := servers.CreateOpts{
|
||||
Name: name,
|
||||
FlavorRef: "3",
|
||||
FlavorRef: choices.FlavorID,
|
||||
ImageRef: choices.ImageID,
|
||||
}
|
||||
server, err := bootfromvolume.Create(client, bootfromvolume.CreateOptsExt{
|
||||
serverCreateOpts,
|
||||
bd,
|
||||
}).Extract()
|
||||
th.AssertNoErr(t, err)
|
||||
if err = waitForStatus(client, server, "ACTIVE"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Logf("Created server: %+v\n", server)
|
||||
//defer deleteServer(t, client, server)
|
||||
defer servers.Delete(client, server.ID)
|
||||
t.Logf("Deleting server [%s]...", name)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// +build acceptance
|
||||
// +build acceptance common
|
||||
|
||||
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/networking/v2/networks"
|
||||
"github.com/rackspace/gophercloud/pagination"
|
||||
th "github.com/rackspace/gophercloud/testhelper"
|
||||
)
|
||||
|
||||
func TestListServers(t *testing.T) {
|
||||
@ -94,6 +95,8 @@ func createServer(t *testing.T, client *gophercloud.ServiceClient, choices *Comp
|
||||
name := tools.RandomString("ACPTTEST", 16)
|
||||
t.Logf("Attempting to create server: %s\n", name)
|
||||
|
||||
pwd := tools.MakeNewPassword("")
|
||||
|
||||
server, err := servers.Create(client, servers.CreateOpts{
|
||||
Name: name,
|
||||
FlavorRef: choices.FlavorID,
|
||||
@ -101,11 +104,14 @@ func createServer(t *testing.T, client *gophercloud.ServiceClient, choices *Comp
|
||||
Networks: []servers.Network{
|
||||
servers.Network{UUID: network.ID},
|
||||
},
|
||||
AdminPass: pwd,
|
||||
}).Extract()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create server: %v", err)
|
||||
}
|
||||
|
||||
th.AssertEquals(t, pwd, server.AdminPass)
|
||||
|
||||
return server, err
|
||||
}
|
||||
|
||||
@ -391,3 +397,54 @@ func TestActionResizeRevert(t *testing.T) {
|
||||
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
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// +build acceptance
|
||||
// +build acceptance identity
|
||||
|
||||
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
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// +build acceptance
|
||||
// +build acceptance identity
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,10 @@ func TestAccounts(t *testing.T) {
|
||||
|
||||
// Update an account's 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 func() {
|
||||
@ -29,11 +32,14 @@ func TestAccounts(t *testing.T) {
|
||||
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.
|
||||
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)
|
||||
for k := range metadata {
|
||||
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 (
|
||||
"testing"
|
||||
|
||||
"github.com/rackspace/gophercloud/acceptance/tools"
|
||||
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/servers"
|
||||
th "github.com/rackspace/gophercloud/testhelper"
|
||||
"github.com/smashwilson/gophercloud/acceptance/tools"
|
||||
)
|
||||
|
||||
func TestBootFromVolume(t *testing.T) {
|
||||
@ -41,6 +41,9 @@ func TestBootFromVolume(t *testing.T) {
|
||||
}).Extract()
|
||||
th.AssertNoErr(t, err)
|
||||
t.Logf("Created server: %+v\n", server)
|
||||
//defer deleteServer(t, client, server)
|
||||
t.Logf("Deleting server [%s]...", name)
|
||||
defer deleteServer(t, client, server)
|
||||
|
||||
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)
|
||||
|
||||
pwd := tools.MakeNewPassword("")
|
||||
|
||||
opts := &servers.CreateOpts{
|
||||
Name: name,
|
||||
ImageRef: options.imageID,
|
||||
FlavorRef: options.flavorID,
|
||||
DiskConfig: diskconfig.Manual,
|
||||
AdminPass: pwd,
|
||||
}
|
||||
|
||||
if keyName != "" {
|
||||
@ -59,6 +62,8 @@ func createServer(t *testing.T, client *gophercloud.ServiceClient, keyName strin
|
||||
th.AssertNoErr(t, err)
|
||||
t.Logf("Server created successfully.")
|
||||
|
||||
th.CheckEquals(t, pwd, s.AdminPass)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
@ -95,6 +100,18 @@ func getServer(t *testing.T, client *gophercloud.ServiceClient, server *os.Serve
|
||||
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) {
|
||||
t.Logf("> servers.List")
|
||||
|
||||
@ -120,7 +137,7 @@ func changeAdminPassword(t *testing.T, client *gophercloud.ServiceClient, server
|
||||
original := server.AdminPass
|
||||
|
||||
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)
|
||||
|
||||
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) {
|
||||
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)
|
||||
|
||||
err = servers.WaitForStatus(client, server.ID, "ACTIVE", 300)
|
||||
@ -192,6 +209,7 @@ func TestServerOperations(t *testing.T) {
|
||||
defer deleteServer(t, client, server)
|
||||
|
||||
getServer(t, client, server)
|
||||
updateServer(t, client, server)
|
||||
listServers(t, client)
|
||||
changeAdminPassword(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)
|
||||
th.AssertNoErr(t, err)
|
||||
|
||||
updateres := raxAccounts.Update(c, raxAccounts.UpdateOpts{Metadata: map[string]string{"white": "mountains"}})
|
||||
th.AssertNoErr(t, updateres.Err)
|
||||
t.Logf("Headers from Update Account request: %+v\n", updateres.Header)
|
||||
updateHeaders, err := raxAccounts.Update(c, raxAccounts.UpdateOpts{Metadata: map[string]string{"white": "mountains"}}).Extract()
|
||||
th.AssertNoErr(t, err)
|
||||
t.Logf("Update Account Response Headers: %+v\n", updateHeaders)
|
||||
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)
|
||||
metadata, err := raxAccounts.Get(c).ExtractMetadata()
|
||||
th.AssertNoErr(t, err)
|
||||
@ -25,8 +25,13 @@ func TestAccounts(t *testing.T) {
|
||||
th.CheckEquals(t, metadata["White"], "")
|
||||
}()
|
||||
|
||||
metadata, err := raxAccounts.Get(c).ExtractMetadata()
|
||||
th.AssertNoErr(t, err)
|
||||
getResp := raxAccounts.Get(c)
|
||||
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)
|
||||
|
||||
th.CheckEquals(t, metadata["White"], "mountains")
|
||||
|
@ -26,10 +26,11 @@ func TestCDNContainers(t *testing.T) {
|
||||
|
||||
raxCDNClient, err := createClient(t, true)
|
||||
th.AssertNoErr(t, err)
|
||||
|
||||
r := raxCDNContainers.Enable(raxCDNClient, "gophercloud-test", raxCDNContainers.EnableOpts{CDNEnabled: true, TTL: 900})
|
||||
th.AssertNoErr(t, r.Err)
|
||||
t.Logf("Headers from Enable CDN Container request: %+v\n", r.Header)
|
||||
enableRes := raxCDNContainers.Enable(raxCDNClient, "gophercloud-test", raxCDNContainers.EnableOpts{CDNEnabled: true, TTL: 900})
|
||||
t.Logf("Header map from Enable CDN Container request: %+v\n", enableRes.Header)
|
||||
enableHeader, err := enableRes.Extract()
|
||||
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:")
|
||||
count := 0
|
||||
@ -51,11 +52,15 @@ func TestCDNContainers(t *testing.T) {
|
||||
t.Errorf("No CDN containers listed for your current token.")
|
||||
}
|
||||
|
||||
updateres := raxCDNContainers.Update(raxCDNClient, "gophercloud-test", raxCDNContainers.UpdateOpts{CDNEnabled: false})
|
||||
th.AssertNoErr(t, updateres.Err)
|
||||
t.Logf("Headers from Update CDN Container request: %+v\n", updateres.Header)
|
||||
|
||||
metadata, err := raxCDNContainers.Get(raxCDNClient, "gophercloud-test").ExtractMetadata()
|
||||
updateOpts := raxCDNContainers.UpdateOpts{XCDNEnabled: raxCDNContainers.Disabled, XLogRetention: raxCDNContainers.Enabled}
|
||||
updateHeader, err := raxCDNContainers.Update(raxCDNClient, "gophercloud-test", updateOpts).Extract()
|
||||
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.")
|
||||
}
|
||||
|
||||
createres := raxContainers.Create(c, "gophercloud-test", nil)
|
||||
th.AssertNoErr(t, createres.Err)
|
||||
createHeader, err := raxContainers.Create(c, "gophercloud-test", nil).Extract()
|
||||
th.AssertNoErr(t, err)
|
||||
t.Logf("Headers from Create Container request: %+v\n", createHeader)
|
||||
defer func() {
|
||||
res := raxContainers.Delete(c, "gophercloud-test")
|
||||
th.AssertNoErr(t, res.Err)
|
||||
deleteres := raxContainers.Delete(c, "gophercloud-test")
|
||||
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"}})
|
||||
th.AssertNoErr(t, updateres.Err)
|
||||
t.Logf("Headers from Update Account request: %+v\n", updateres.Header)
|
||||
updateHeader, err := raxContainers.Update(c, "gophercloud-test", raxContainers.UpdateOpts{Metadata: map[string]string{"white": "mountains"}}).Extract()
|
||||
th.AssertNoErr(t, err)
|
||||
t.Logf("Headers from Update Container request: %+v\n", updateHeader)
|
||||
defer func() {
|
||||
res := raxContainers.Update(c, "gophercloud-test", raxContainers.UpdateOpts{Metadata: map[string]string{"white": ""}})
|
||||
th.AssertNoErr(t, res.Err)
|
||||
metadata, err := raxContainers.Get(c, "gophercloud-test").ExtractMetadata()
|
||||
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"], "")
|
||||
}()
|
||||
|
||||
getres := raxContainers.Get(c, "gophercloud-test")
|
||||
t.Logf("Headers from Get Account request (after update): %+v\n", getres.Header)
|
||||
metadata, err := getres.ExtractMetadata()
|
||||
getHeader, err := getres.Extract()
|
||||
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")
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ func TestObjects(t *testing.T) {
|
||||
th.AssertNoErr(t, res.Err)
|
||||
|
||||
defer func() {
|
||||
t.Logf("Deleting container...")
|
||||
res := raxContainers.Delete(c, "gophercloud-test")
|
||||
th.AssertNoErr(t, res.Err)
|
||||
}()
|
||||
@ -29,7 +30,9 @@ func TestObjects(t *testing.T) {
|
||||
options := &osObjects.CreateOpts{ContentType: "text/plain"}
|
||||
createres := raxObjects.Create(c, "gophercloud-test", "o1", content, options)
|
||||
th.AssertNoErr(t, createres.Err)
|
||||
|
||||
defer func() {
|
||||
t.Logf("Deleting object o1...")
|
||||
res := raxObjects.Delete(c, "gophercloud-test", "o1", nil)
|
||||
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"})
|
||||
th.AssertNoErr(t, copyres.Err)
|
||||
defer func() {
|
||||
t.Logf("Deleting object o2...")
|
||||
res := raxObjects.Delete(c, "gophercloud-test", "o2", nil)
|
||||
th.AssertNoErr(t, res.Err)
|
||||
}()
|
||||
@ -99,7 +103,7 @@ func TestObjects(t *testing.T) {
|
||||
metadata, err := raxObjects.Get(c, "gophercloud-test", "o2", nil).ExtractMetadata()
|
||||
th.AssertNoErr(t, err)
|
||||
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)
|
||||
@ -108,5 +112,13 @@ func TestObjects(t *testing.T) {
|
||||
metadata, err := getres.ExtractMetadata()
|
||||
th.AssertNoErr(t, err)
|
||||
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
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
mrand "math/rand"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
@ -72,6 +73,12 @@ func RandomString(prefix string, n int) string {
|
||||
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
|
||||
// a comfortable 40 characters.
|
||||
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
|
||||
|
||||
// AuthOptions allows anyone calling Authenticate to supply the required access
|
||||
// credentials. Its fields are the union of those recognized by each identity
|
||||
// implementation and provider.
|
||||
/*
|
||||
AuthOptions stores information needed to authenticate to an OpenStack cluster.
|
||||
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 {
|
||||
// IdentityEndpoint specifies the HTTP endpoint that is required to work with
|
||||
// the Identity API of the appropriate version. Required by the identity
|
||||
// services, but often populated by a provider Client.
|
||||
// the Identity API of the appropriate version. While it's ultimately needed by
|
||||
// all of the identity services, it will often be populated by a provider-level
|
||||
// function.
|
||||
IdentityEndpoint string
|
||||
|
||||
// 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
|
||||
// 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
|
||||
|
||||
// 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
|
||||
// preferred method of authentication.
|
||||
Password, APIKey string
|
||||
@ -25,7 +33,7 @@ type AuthOptions struct {
|
||||
|
||||
// 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 require both. Your provider's authentication policies will determine
|
||||
// Some require both. Your provider's authentication policies will determine
|
||||
// how these fields influence authentication.
|
||||
TenantID, TenantName string
|
||||
|
||||
@ -34,5 +42,7 @@ type AuthOptions struct {
|
||||
// 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
|
||||
// possible. This setting defaults to false.
|
||||
//
|
||||
// This setting is speculative and is currently not respected!
|
||||
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"
|
||||
|
||||
// AuthResults encapsulates the raw results from an authentication request. As OpenStack allows
|
||||
// extensions to influence the structure returned in ways that Gophercloud cannot predict at
|
||||
// compile-time, you should use type-safe accessors to work with the data represented by this type,
|
||||
// such as ServiceCatalog and TokenID.
|
||||
// AuthResults [deprecated] is a leftover type from the v0.x days. It was
|
||||
// intended to describe common functionality among identity service results, but
|
||||
// is not actually used anywhere.
|
||||
type AuthResults interface {
|
||||
// TokenID returns the token's ID value from the authentication response.
|
||||
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"
|
||||
|
||||
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.")
|
||||
|
||||
// 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.")
|
||||
)
|
||||
|
||||
// Availability indicates whether a specific service endpoint is accessible.
|
||||
// Identity v2 lists these as different kinds of URLs ("adminURL",
|
||||
// "internalURL", and "publicURL"), while v3 lists them as "Interfaces".
|
||||
// Availability indicates to whom a specific service endpoint is accessible:
|
||||
// the internet at large, internal networks only, or only to administrators.
|
||||
// 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
|
||||
|
||||
const (
|
||||
// AvailabilityAdmin makes an endpoint only available to administrators.
|
||||
// AvailabilityAdmin indicates that an endpoint is only available to
|
||||
// administrators.
|
||||
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"
|
||||
|
||||
// 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"
|
||||
)
|
||||
|
||||
// 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 is the service type for the client (e.g., "compute", "object-store").
|
||||
// Required.
|
||||
// Type [required] is the service type for the client (e.g., "compute",
|
||||
// "object-store"). Generally, this will be supplied by the service client
|
||||
// function, but a user-given value will be honored if provided.
|
||||
Type string
|
||||
|
||||
// Name is the service name for the client (e.g., "nova") as it appears in
|
||||
// the service catalog. Services can have the same Type but a different Name,
|
||||
// which is why both Type and Name are sometimes needed. Optional.
|
||||
// Name [optional] is the service name for the client (e.g., "nova") as it
|
||||
// appears in the service catalog. Services can have the same Type but a
|
||||
// different Name, which is why both Type and Name are sometimes needed.
|
||||
Name string
|
||||
|
||||
// Region is the geographic region in which the service resides. Required only
|
||||
// for services that span multiple regions.
|
||||
// Region [required] is the geographic region in which the endpoint resides,
|
||||
// generally specifying which datacenter should house your resources.
|
||||
// Required only for services that span multiple regions.
|
||||
Region string
|
||||
|
||||
// Availability is the visibility of the endpoint to be returned. Valid types
|
||||
// are: AvailabilityPublic, AvailabilityInternal, or AvailabilityAdmin.
|
||||
// Availability is not required, and defaults to AvailabilityPublic.
|
||||
// Not all providers or services offer all Availability options.
|
||||
// Availability [optional] is the visibility of the endpoint to be returned.
|
||||
// Valid types include the constants AvailabilityPublic, AvailabilityInternal,
|
||||
// or AvailabilityAdmin from this package.
|
||||
//
|
||||
// Availability is not required, and defaults to AvailabilityPublic. Not all
|
||||
// providers or services offer all Availability options.
|
||||
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
|
||||
// during ProviderClient authentication and used to discover related ServiceClients.
|
||||
/*
|
||||
EndpointLocator is an internal function to be used by provider implementations.
|
||||
|
||||
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)
|
||||
|
||||
// ApplyDefaults sets EndpointOpts fields if not already set. Currently,
|
||||
// EndpointOpts.Availability defaults to the public endpoint.
|
||||
// ApplyDefaults is an internal method to be used by provider implementations.
|
||||
//
|
||||
// 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) {
|
||||
if eo.Type == "" {
|
||||
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"`
|
||||
|
||||
// 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.
|
||||
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
|
||||
}
|
||||
|
||||
// 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/rackspace/gophercloud"
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
||||
"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.
|
||||
func List(client *gophercloud.ServiceClient) pagination.Pager {
|
||||
return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
|
||||
@ -21,7 +46,7 @@ type CreateOptsBuilder interface {
|
||||
ToKeyPairCreateMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// CreateOpts species keypair creation or import parameters.
|
||||
// CreateOpts specifies keypair creation or import parameters.
|
||||
type CreateOpts struct {
|
||||
// Name [required] is a friendly name to refer to this KeyPair in other services.
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
// 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 (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/racker/perigee"
|
||||
@ -131,6 +132,16 @@ type CreateOpts struct {
|
||||
|
||||
// ConfigDrive [optional] enables metadata injection through a configuration drive.
|
||||
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.
|
||||
@ -158,12 +169,22 @@ func (opts CreateOpts) ToServerCreateMap() (map[string]interface{}, error) {
|
||||
if opts.Metadata != nil {
|
||||
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 {
|
||||
securityGroups := make([]map[string]interface{}, len(opts.SecurityGroups))
|
||||
for i, groupName := range opts.SecurityGroups {
|
||||
securityGroups[i] = map[string]interface{}{"name": groupName}
|
||||
}
|
||||
server["security_groups"] = securityGroups
|
||||
}
|
||||
|
||||
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{
|
||||
Results: &result.Body,
|
||||
MoreHeaders: client.AuthenticatedHeaders(),
|
||||
OkCodes: []int{200, 203},
|
||||
})
|
||||
return result
|
||||
}
|
||||
@ -475,7 +497,7 @@ type ResizeOpts struct {
|
||||
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.
|
||||
func (opts ResizeOpts) ToServerResizeMap() (map[string]interface{}, error) {
|
||||
resize := map[string]interface{}{
|
||||
@ -536,3 +558,182 @@ func RevertResize(client *gophercloud.ServiceClient, id string) ActionResult {
|
||||
|
||||
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
Loading…
Reference in New Issue
Block a user