Merge pull request #7020 from kazegusuri/reenable_auto_reauth

Update gophercloud to HEAD and reenable auto reauth
This commit is contained in:
Brendan Burns
2015-04-20 11:57:07 -07:00
137 changed files with 5543 additions and 1240 deletions

4
Godeps/Godeps.json generated
View File

@@ -372,8 +372,8 @@
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud", "ImportPath": "github.com/rackspace/gophercloud",
"Comment": "v1.0.0-490-g32d0a89", "Comment": "v1.0.0-569-gf3ced00",
"Rev": "32d0a893a8ef70abe76dc5153e2925b39cbea7f7" "Rev": "f3ced00552c1c7d4a6184500af9062cfb4ff4463"
}, },
{ {
"ImportPath": "github.com/russross/blackfriday", "ImportPath": "github.com/russross/blackfriday",

View File

@@ -9,7 +9,7 @@ go:
- tip - tip
script: script/cibuild script: script/cibuild
after_success: after_success:
- go get code.google.com/p/go.tools/cmd/cover - go get golang.org/x/tools/cmd/cover
- go get github.com/axw/gocov/gocov - go get github.com/axw/gocov/gocov
- go get github.com/mattn/goveralls - go get github.com/mattn/goveralls
- export PATH=$PATH:$HOME/gopath/bin/ - export PATH=$PATH:$HOME/gopath/bin/

View File

@@ -205,7 +205,7 @@ On of the easiest ways to get readily involved in our project is to let us know
about your experiences using our SDK. Feedback like this is incredibly useful about your experiences using our SDK. Feedback like this is incredibly useful
to us, because it allows us to refine and change features based on what our to us, because it allows us to refine and change features based on what our
users want and expect of us. There are a bunch of ways to get in contact! You users want and expect of us. There are a bunch of ways to get in contact! You
can [ping us](mailto:sdk-support@rackspace.com) via e-mail, talk to us on irc can [ping us](https://developer.rackspace.com/support/) via e-mail, talk to us on irc
(#rackspace-dev on freenode), [tweet us](https://twitter.com/rackspace), or (#rackspace-dev on freenode), [tweet us](https://twitter.com/rackspace), or
submit an issue on our [bug tracker](/issues). Things you might like to tell us submit an issue on our [bug tracker](/issues). Things you might like to tell us
are: are:

View File

@@ -25,7 +25,7 @@ export GOPATH=$HOME/go
``` ```
To protect yourself against changes in your dependencies, we highly recommend choosing a To protect yourself against changes in your dependencies, we highly recommend choosing a
[dependency management solution](https://code.google.com/p/go-wiki/wiki/PackageManagementTools) for [dependency management solution](https://github.com/golang/go/wiki/PackageManagementTools) for
your projects, such as [godep](https://github.com/tools/godep). Once this is set up, you can install your projects, such as [godep](https://github.com/tools/godep). Once this is set up, you can install
Gophercloud as a dependency like so: Gophercloud as a dependency like so:
@@ -151,11 +151,10 @@ Engaging the community and lowering barriers for contributors is something we
care a lot about. For this reason, we've taken the time to write a [contributing care a lot about. For this reason, we've taken the time to write a [contributing
guide](./CONTRIBUTING.md) for folks interested in getting involved in our project. guide](./CONTRIBUTING.md) for folks interested in getting involved in our project.
If you're not sure how you can get involved, feel free to submit an issue or If you're not sure how you can get involved, feel free to submit an issue or
[e-mail us](mailto:sdk-support@rackspace.com) privately. You don't need to be a [contact us](https://developer.rackspace.com/support/). You don't need to be a
Go expert - all members of the community are welcome! Go expert - all members of the community are welcome!
## Help and feedback ## Help and feedback
If you're struggling with something or have spotted a potential bug, feel free If you're struggling with something or have spotted a potential bug, feel free
to submit an issue to our [bug tracker](/issues) or e-mail us directly at to submit an issue to our [bug tracker](/issues) or [contact us directly](https://developer.rackspace.com/support/).
[sdk-support@rackspace.com](mailto:sdk-support@rackspace.com).

View File

@@ -8,7 +8,7 @@ extensible, maintainable and easy-to-use.
Below we've compiled upgrade instructions for the various services that Below we've compiled upgrade instructions for the various services that
existed before. If you have a specific issue that is not addressed below, existed before. If you have a specific issue that is not addressed below,
please [submit an issue](/issues/new) or please [submit an issue](/issues/new) or
[e-mail our support team](mailto:sdk-support@rackspace.com). [e-mail our support team](https://developer.rackspace.com/support/).
* [Authentication](#authentication) * [Authentication](#authentication)
* [Servers](#servers) * [Servers](#servers)

View File

@@ -56,6 +56,9 @@ type ComputeChoices struct {
// FlavorIDResize contains the ID of a different flavor available on the same OpenStack installation, that is distinct // FlavorIDResize contains the ID of a different flavor available on the same OpenStack installation, that is distinct
// from FlavorID. // from FlavorID.
FlavorIDResize string FlavorIDResize string
// NetworkName is the name of a network to launch the instance on.
NetworkName string
} }
// ComputeChoicesFromEnv populates a ComputeChoices struct from environment variables. // ComputeChoicesFromEnv populates a ComputeChoices struct from environment variables.
@@ -64,6 +67,7 @@ func ComputeChoicesFromEnv() (*ComputeChoices, error) {
imageID := os.Getenv("OS_IMAGE_ID") imageID := os.Getenv("OS_IMAGE_ID")
flavorID := os.Getenv("OS_FLAVOR_ID") flavorID := os.Getenv("OS_FLAVOR_ID")
flavorIDResize := os.Getenv("OS_FLAVOR_ID_RESIZE") flavorIDResize := os.Getenv("OS_FLAVOR_ID_RESIZE")
networkName := os.Getenv("OS_NETWORK_NAME")
missing := make([]string, 0, 3) missing := make([]string, 0, 3)
if imageID == "" { if imageID == "" {
@@ -75,6 +79,9 @@ func ComputeChoicesFromEnv() (*ComputeChoices, error) {
if flavorIDResize == "" { if flavorIDResize == "" {
missing = append(missing, "OS_FLAVOR_ID_RESIZE") missing = append(missing, "OS_FLAVOR_ID_RESIZE")
} }
if networkName == "" {
networkName = "public"
}
notDistinct := "" notDistinct := ""
if flavorID == flavorIDResize { if flavorID == flavorIDResize {
@@ -93,5 +100,5 @@ func ComputeChoicesFromEnv() (*ComputeChoices, error) {
return nil, fmt.Errorf(text) return nil, fmt.Errorf(text)
} }
return &ComputeChoices{ImageID: imageID, FlavorID: flavorID, FlavorIDResize: flavorIDResize}, nil return &ComputeChoices{ImageID: imageID, FlavorID: flavorID, FlavorIDResize: flavorIDResize, NetworkName: networkName}, nil
} }

View File

@@ -12,7 +12,7 @@ import (
"github.com/rackspace/gophercloud/openstack/compute/v2/servers" "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
th "github.com/rackspace/gophercloud/testhelper" th "github.com/rackspace/gophercloud/testhelper"
"code.google.com/p/go.crypto/ssh" "golang.org/x/crypto/ssh"
) )
const keyName = "gophercloud_test_key_pair" const keyName = "gophercloud_test_key_pair"

View File

@@ -0,0 +1,58 @@
// +build acceptance compute servers
package v2
import (
"testing"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/servergroups"
)
func createServerGroup(t *testing.T, computeClient *gophercloud.ServiceClient) (*servergroups.ServerGroup, error) {
sg, err := servergroups.Create(computeClient, &servergroups.CreateOpts{
Name: "test",
Policies: []string{"affinity"},
}).Extract()
if err != nil {
t.Fatalf("Unable to create server group: %v", err)
}
t.Logf("Created server group: %v", sg.ID)
t.Logf("It has policies: %v", sg.Policies)
return sg, nil
}
func getServerGroup(t *testing.T, computeClient *gophercloud.ServiceClient, sgID string) error {
sg, err := servergroups.Get(computeClient, sgID).Extract()
if err != nil {
t.Fatalf("Unable to get server group: %v", err)
}
t.Logf("Got server group: %v", sg.Name)
return nil
}
func TestServerGroups(t *testing.T) {
computeClient, err := newClient()
if err != nil {
t.Fatalf("Unable to create a compute client: %v", err)
}
sg, err := createServerGroup(t, computeClient)
if err != nil {
t.Fatalf("Unable to create server group: %v", err)
}
defer func() {
servergroups.Delete(computeClient, sg.ID)
t.Logf("ServerGroup deleted.")
}()
err = getServerGroup(t, computeClient, sg.ID)
if err != nil {
t.Fatalf("Unable to get server group: %v", err)
}
}

View File

@@ -57,7 +57,6 @@ func networkingClient() (*gophercloud.ServiceClient, error) {
} }
return openstack.NewNetworkV2(provider, gophercloud.EndpointOpts{ return openstack.NewNetworkV2(provider, gophercloud.EndpointOpts{
Name: "neutron",
Region: os.Getenv("OS_REGION_NAME"), Region: os.Getenv("OS_REGION_NAME"),
}) })
} }
@@ -74,7 +73,10 @@ func createServer(t *testing.T, client *gophercloud.ServiceClient, choices *Comp
t.Fatalf("Unable to create a networking client: %v", err) t.Fatalf("Unable to create a networking client: %v", err)
} }
pager := networks.List(networkingClient, networks.ListOpts{Name: "public", Limit: 1}) pager := networks.List(networkingClient, networks.ListOpts{
Name: choices.NetworkName,
Limit: 1,
})
pager.EachPage(func(page pagination.Page) (bool, error) { pager.EachPage(func(page pagination.Page) (bool, error) {
networks, err := networks.ExtractNetworks(page) networks, err := networks.ExtractNetworks(page)
if err != nil { if err != nil {
@@ -138,6 +140,32 @@ func TestCreateDestroyServer(t *testing.T) {
if err = waitForStatus(client, server, "ACTIVE"); err != nil { if err = waitForStatus(client, server, "ACTIVE"); err != nil {
t.Fatalf("Unable to wait for server: %v", err) t.Fatalf("Unable to wait for server: %v", err)
} }
pager := servers.ListAddresses(client, server.ID)
pager.EachPage(func(page pagination.Page) (bool, error) {
networks, err := servers.ExtractAddresses(page)
if err != nil {
return false, err
}
for n, a := range networks {
t.Logf("%s: %+v\n", n, a)
}
return true, nil
})
pager = servers.ListAddressesByNetwork(client, server.ID, choices.NetworkName)
pager.EachPage(func(page pagination.Page) (bool, error) {
addresses, err := servers.ExtractNetworkAddresses(page)
if err != nil {
return false, err
}
for _, a := range addresses {
t.Logf("%+v\n", a)
}
return true, nil
})
} }
func TestUpdateServer(t *testing.T) { func TestUpdateServer(t *testing.T) {

View File

@@ -0,0 +1,109 @@
// +build acceptance compute servers
package v2
import (
"os"
"testing"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/acceptance/tools"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks"
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
th "github.com/rackspace/gophercloud/testhelper"
)
func getNetworkID(t *testing.T, client *gophercloud.ServiceClient, networkName string) (string, error) {
allPages, err := tenantnetworks.List(client).AllPages()
if err != nil {
t.Fatalf("Unable to list networks: %v", err)
}
networkList, err := tenantnetworks.ExtractNetworks(allPages)
if err != nil {
t.Fatalf("Unable to list networks: %v", err)
}
networkID := ""
for _, network := range networkList {
t.Logf("Network: %v", network)
if network.Name == networkName {
networkID = network.ID
}
}
t.Logf("Found network ID for %s: %s\n", networkName, networkID)
return networkID, nil
}
func createNetworkServer(t *testing.T, client *gophercloud.ServiceClient, choices *ComputeChoices, networkID string) (*servers.Server, error) {
if testing.Short() {
t.Skip("Skipping test that requires server creation in short mode.")
}
name := tools.RandomString("ACPTTEST", 16)
t.Logf("Attempting to create server: %s\n", name)
pwd := tools.MakeNewPassword("")
networks := make([]servers.Network, 1)
networks[0] = servers.Network{
UUID: networkID,
}
server, err := servers.Create(client, servers.CreateOpts{
Name: name,
FlavorRef: choices.FlavorID,
ImageRef: choices.ImageID,
AdminPass: pwd,
Networks: networks,
}).Extract()
if err != nil {
t.Fatalf("Unable to create server: %v", err)
}
th.AssertEquals(t, pwd, server.AdminPass)
return server, err
}
func TestTenantNetworks(t *testing.T) {
networkName := os.Getenv("OS_NETWORK_NAME")
if networkName == "" {
t.Fatalf("OS_NETWORK_NAME must be set")
}
choices, err := ComputeChoicesFromEnv()
if err != nil {
t.Fatal(err)
}
client, err := newClient()
if err != nil {
t.Fatalf("Unable to create a compute client: %v", err)
}
networkID, err := getNetworkID(t, client, networkName)
if err != nil {
t.Fatalf("Unable to get network ID: %v", err)
}
server, err := createNetworkServer(t, client, choices, networkID)
if err != nil {
t.Fatalf("Unable to create server: %v", err)
}
defer func() {
servers.Delete(client, server.ID)
t.Logf("Server deleted.")
}()
if err = waitForStatus(client, server, "ACTIVE"); err != nil {
t.Fatalf("Unable to wait for server: %v", err)
}
allPages, err := tenantnetworks.List(client).AllPages()
allNetworks, err := tenantnetworks.ExtractNetworks(allPages)
th.AssertNoErr(t, err)
t.Logf("Retrieved all %d networks: %+v", len(allNetworks), allNetworks)
}

View File

@@ -0,0 +1,165 @@
// +build acceptance networking security
package v2
import (
"testing"
osGroups "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/groups"
osRules "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/security/rules"
osNetworks "github.com/rackspace/gophercloud/openstack/networking/v2/networks"
osPorts "github.com/rackspace/gophercloud/openstack/networking/v2/ports"
"github.com/rackspace/gophercloud/pagination"
rsNetworks "github.com/rackspace/gophercloud/rackspace/networking/v2/networks"
rsPorts "github.com/rackspace/gophercloud/rackspace/networking/v2/ports"
rsGroups "github.com/rackspace/gophercloud/rackspace/networking/v2/security/groups"
rsRules "github.com/rackspace/gophercloud/rackspace/networking/v2/security/rules"
th "github.com/rackspace/gophercloud/testhelper"
)
func TestSecurityGroups(t *testing.T) {
Setup(t)
defer Teardown()
// create security group
groupID := createSecGroup(t)
// delete security group
defer deleteSecGroup(t, groupID)
// list security group
listSecGroups(t)
// get security group
getSecGroup(t, groupID)
}
func TestSecurityGroupRules(t *testing.T) {
Setup(t)
defer Teardown()
// create security group
groupID := createSecGroup(t)
defer deleteSecGroup(t, groupID)
// create security group rule
ruleID := createSecRule(t, groupID)
// delete security group rule
defer deleteSecRule(t, ruleID)
// list security group rule
listSecRules(t)
// get security group rule
getSecRule(t, ruleID)
}
func createSecGroup(t *testing.T) string {
sg, err := rsGroups.Create(Client, osGroups.CreateOpts{
Name: "new-webservers",
Description: "security group for webservers",
}).Extract()
th.AssertNoErr(t, err)
t.Logf("Created security group %s", sg.ID)
return sg.ID
}
func listSecGroups(t *testing.T) {
err := rsGroups.List(Client, osGroups.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
list, err := osGroups.ExtractGroups(page)
if err != nil {
t.Errorf("Failed to extract secgroups: %v", err)
return false, err
}
for _, sg := range list {
t.Logf("Listing security group: ID [%s] Name [%s]", sg.ID, sg.Name)
}
return true, nil
})
th.AssertNoErr(t, err)
}
func getSecGroup(t *testing.T, id string) {
sg, err := rsGroups.Get(Client, id).Extract()
th.AssertNoErr(t, err)
t.Logf("Getting security group: ID [%s] Name [%s] Description [%s]", sg.ID, sg.Name, sg.Description)
}
func createSecGroupPort(t *testing.T, groupID string) (string, string) {
n, err := rsNetworks.Create(Client, osNetworks.CreateOpts{Name: "tmp_network"}).Extract()
th.AssertNoErr(t, err)
t.Logf("Created network %s", n.ID)
opts := osPorts.CreateOpts{
NetworkID: n.ID,
Name: "my_port",
SecurityGroups: []string{groupID},
}
p, err := rsPorts.Create(Client, opts).Extract()
th.AssertNoErr(t, err)
t.Logf("Created port %s with security group %s", p.ID, groupID)
return n.ID, p.ID
}
func deleteSecGroup(t *testing.T, groupID string) {
res := rsGroups.Delete(Client, groupID)
th.AssertNoErr(t, res.Err)
t.Logf("Deleted security group %s", groupID)
}
func createSecRule(t *testing.T, groupID string) string {
r, err := rsRules.Create(Client, osRules.CreateOpts{
Direction: "ingress",
PortRangeMin: 80,
EtherType: "IPv4",
PortRangeMax: 80,
Protocol: "tcp",
SecGroupID: groupID,
}).Extract()
th.AssertNoErr(t, err)
t.Logf("Created security group rule %s", r.ID)
return r.ID
}
func listSecRules(t *testing.T) {
err := rsRules.List(Client, osRules.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
list, err := osRules.ExtractRules(page)
if err != nil {
t.Errorf("Failed to extract sec rules: %v", err)
return false, err
}
for _, r := range list {
t.Logf("Listing security rule: ID [%s]", r.ID)
}
return true, nil
})
th.AssertNoErr(t, err)
}
func getSecRule(t *testing.T, id string) {
r, err := rsRules.Get(Client, id).Extract()
th.AssertNoErr(t, err)
t.Logf("Getting security rule: ID [%s] Direction [%s] EtherType [%s] Protocol [%s]",
r.ID, r.Direction, r.EtherType, r.Protocol)
}
func deleteSecRule(t *testing.T, id string) {
res := rsRules.Delete(Client, id)
th.AssertNoErr(t, res.Err)
t.Logf("Deleted security rule %s", id)
}

View File

@@ -0,0 +1,36 @@
// +build acceptance
package v3
import (
"fmt"
"testing"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/rackspace/rackconnect/v3/cloudnetworks"
th "github.com/rackspace/gophercloud/testhelper"
)
func TestCloudNetworks(t *testing.T) {
c := newClient(t)
cnID := testListNetworks(t, c)
testGetNetworks(t, c, cnID)
}
func testListNetworks(t *testing.T, c *gophercloud.ServiceClient) string {
allPages, err := cloudnetworks.List(c).AllPages()
th.AssertNoErr(t, err)
allcn, err := cloudnetworks.ExtractCloudNetworks(allPages)
fmt.Printf("Listing all cloud networks: %+v\n\n", allcn)
var cnID string
if len(allcn) > 0 {
cnID = allcn[0].ID
}
return cnID
}
func testGetNetworks(t *testing.T, c *gophercloud.ServiceClient, id string) {
cn, err := cloudnetworks.Get(c, id).Extract()
th.AssertNoErr(t, err)
fmt.Printf("Retrieved cloud network: %+v\n\n", cn)
}

View File

@@ -0,0 +1,26 @@
// +build acceptance
package v3
import (
"os"
"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.NewRackConnectV3(client, gophercloud.EndpointOpts{
Region: os.Getenv("RS_REGION_NAME"),
})
th.AssertNoErr(t, err)
return c
}

View File

@@ -0,0 +1,71 @@
// +build acceptance
package v3
import (
"fmt"
"testing"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/rackspace/rackconnect/v3/lbpools"
th "github.com/rackspace/gophercloud/testhelper"
)
func TestLBPools(t *testing.T) {
c := newClient(t)
pID := testListPools(t, c)
testGetPools(t, c, pID)
nID := testListNodes(t, c, pID)
testListNodeDetails(t, c, pID)
testGetNode(t, c, pID, nID)
testGetNodeDetails(t, c, pID, nID)
}
func testListPools(t *testing.T, c *gophercloud.ServiceClient) string {
allPages, err := lbpools.List(c).AllPages()
th.AssertNoErr(t, err)
allp, err := lbpools.ExtractPools(allPages)
fmt.Printf("Listing all LB pools: %+v\n\n", allp)
var pID string
if len(allp) > 0 {
pID = allp[0].ID
}
return pID
}
func testGetPools(t *testing.T, c *gophercloud.ServiceClient, pID string) {
p, err := lbpools.Get(c, pID).Extract()
th.AssertNoErr(t, err)
fmt.Printf("Retrieved LB pool: %+v\n\n", p)
}
func testListNodes(t *testing.T, c *gophercloud.ServiceClient, pID string) string {
allPages, err := lbpools.ListNodes(c, pID).AllPages()
th.AssertNoErr(t, err)
alln, err := lbpools.ExtractNodes(allPages)
fmt.Printf("Listing all LB pool nodes for pool (%s): %+v\n\n", pID, alln)
var nID string
if len(alln) > 0 {
nID = alln[0].ID
}
return nID
}
func testListNodeDetails(t *testing.T, c *gophercloud.ServiceClient, pID string) {
allPages, err := lbpools.ListNodesDetails(c, pID).AllPages()
th.AssertNoErr(t, err)
alln, err := lbpools.ExtractNodesDetails(allPages)
fmt.Printf("Listing all LB pool nodes details for pool (%s): %+v\n\n", pID, alln)
}
func testGetNode(t *testing.T, c *gophercloud.ServiceClient, pID, nID string) {
n, err := lbpools.GetNode(c, pID, nID).Extract()
th.AssertNoErr(t, err)
fmt.Printf("Retrieved LB node: %+v\n\n", n)
}
func testGetNodeDetails(t *testing.T, c *gophercloud.ServiceClient, pID, nID string) {
n, err := lbpools.GetNodeDetails(c, pID, nID).Extract()
th.AssertNoErr(t, err)
fmt.Printf("Retrieved LB node details: %+v\n\n", n)
}

View File

@@ -0,0 +1,45 @@
// +build acceptance
package v3
import (
"fmt"
"testing"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/rackspace/rackconnect/v3/publicips"
th "github.com/rackspace/gophercloud/testhelper"
)
func TestPublicIPs(t *testing.T) {
c := newClient(t)
ipID := testListIPs(t, c)
sID := testGetIP(t, c, ipID)
testListIPsForServer(t, c, sID)
}
func testListIPs(t *testing.T, c *gophercloud.ServiceClient) string {
allPages, err := publicips.List(c).AllPages()
th.AssertNoErr(t, err)
allip, err := publicips.ExtractPublicIPs(allPages)
fmt.Printf("Listing all public IPs: %+v\n\n", allip)
var ipID string
if len(allip) > 0 {
ipID = allip[0].ID
}
return ipID
}
func testGetIP(t *testing.T, c *gophercloud.ServiceClient, ipID string) string {
ip, err := publicips.Get(c, ipID).Extract()
th.AssertNoErr(t, err)
fmt.Printf("Retrieved public IP (%s): %+v\n\n", ipID, ip)
return ip.CloudServer.ID
}
func testListIPsForServer(t *testing.T, c *gophercloud.ServiceClient, sID string) {
allPages, err := publicips.ListForServer(c, sID).AllPages()
th.AssertNoErr(t, err)
allip, err := publicips.ExtractPublicIPs(allPages)
fmt.Printf("Listing all public IPs for server (%s): %+v\n\n", sID, allip)
}

View File

@@ -16,9 +16,6 @@ func List(c *gophercloud.ServiceClient) pagination.Pager {
// type from the result, call the Extract method on the GetResult. // type from the result, call the Extract method on the GetResult.
func Get(client *gophercloud.ServiceClient, v string) GetResult { func Get(client *gophercloud.ServiceClient, v string) GetResult {
var res GetResult var res GetResult
_, res.Err = client.Request("GET", getURL(client, v), gophercloud.RequestOpts{ _, res.Err = client.Get(getURL(client, v), &res.Body, nil)
OkCodes: []int{200},
JSONResponse: &res.Body,
})
return res return res
} }

View File

@@ -67,10 +67,8 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
return res return res
} }
_, res.Err = client.Request("POST", createURL(client), gophercloud.RequestOpts{ _, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
OkCodes: []int{200, 201}, OkCodes: []int{200, 201},
JSONBody: &reqBody,
JSONResponse: &res.Body,
}) })
return res return res
} }
@@ -78,9 +76,7 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
// Delete will delete the existing Snapshot with the provided ID. // Delete will delete the existing Snapshot with the provided ID.
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult { func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = client.Request("DELETE", deleteURL(client, id), gophercloud.RequestOpts{ _, res.Err = client.Delete(deleteURL(client, id), nil)
OkCodes: []int{202, 204},
})
return res return res
} }
@@ -88,10 +84,7 @@ func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
// object from the response, call the Extract method on the GetResult. // object from the response, call the Extract method on the GetResult.
func Get(client *gophercloud.ServiceClient, id string) GetResult { func Get(client *gophercloud.ServiceClient, id string) GetResult {
var res GetResult var res GetResult
_, res.Err = client.Request("GET", getURL(client, id), gophercloud.RequestOpts{ _, res.Err = client.Get(getURL(client, id), &res.Body, nil)
OkCodes: []int{200},
JSONResponse: &res.Body,
})
return res return res
} }
@@ -173,10 +166,8 @@ func UpdateMetadata(client *gophercloud.ServiceClient, id string, opts UpdateMet
return res return res
} }
_, res.Err = client.Request("PUT", updateMetadataURL(client, id), gophercloud.RequestOpts{ _, res.Err = client.Put(updateMetadataURL(client, id), reqBody, &res.Body, &gophercloud.RequestOpts{
OkCodes: []int{200}, OkCodes: []int{200},
JSONBody: &reqBody,
JSONResponse: &res.Body,
}) })
return res return res
} }

View File

@@ -83,10 +83,8 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
return res return res
} }
_, res.Err = client.Request("POST", createURL(client), gophercloud.RequestOpts{ _, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
OkCodes: []int{200, 201}, OkCodes: []int{200, 201},
JSONBody: &reqBody,
JSONResponse: &res.Body,
}) })
return res return res
} }
@@ -94,9 +92,7 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
// Delete will delete the existing Volume with the provided ID. // Delete will delete the existing Volume with the provided ID.
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult { func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = client.Request("DELETE", deleteURL(client, id), gophercloud.RequestOpts{ _, res.Err = client.Delete(deleteURL(client, id), nil)
OkCodes: []int{202, 204},
})
return res return res
} }
@@ -104,10 +100,7 @@ func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
// from the response, call the Extract method on the GetResult. // from the response, call the Extract method on the GetResult.
func Get(client *gophercloud.ServiceClient, id string) GetResult { func Get(client *gophercloud.ServiceClient, id string) GetResult {
var res GetResult var res GetResult
_, res.Err = client.Request("GET", getURL(client, id), gophercloud.RequestOpts{ _, res.Err = client.Get(getURL(client, id), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
@@ -203,10 +196,8 @@ func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder
return res return res
} }
_, res.Err = client.Request("PUT", updateURL(client, id), gophercloud.RequestOpts{ _, res.Err = client.Put(updateURL(client, id), reqBody, &res.Body, &gophercloud.RequestOpts{
OkCodes: []int{200}, OkCodes: []int{200},
JSONBody: &reqBody,
JSONResponse: &res.Body,
}) })
return res return res
} }

View File

@@ -44,11 +44,8 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
return res return res
} }
_, res.Err = client.Request("POST", createURL(client), gophercloud.RequestOpts{ _, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
MoreHeaders: client.AuthenticatedHeaders(),
OkCodes: []int{200, 201}, OkCodes: []int{200, 201},
JSONBody: &reqBody,
JSONResponse: &res.Body,
}) })
return res return res
} }
@@ -56,10 +53,7 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
// Delete will delete the volume type with the provided ID. // Delete will delete the volume type with the provided ID.
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult { func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = client.Request("DELETE", deleteURL(client, id), gophercloud.RequestOpts{ _, res.Err = client.Delete(deleteURL(client, id), nil)
MoreHeaders: client.AuthenticatedHeaders(),
OkCodes: []int{202},
})
return res return res
} }
@@ -67,11 +61,7 @@ func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
// type from the result, call the Extract method on the GetResult. // type from the result, call the Extract method on the GetResult.
func Get(client *gophercloud.ServiceClient, id string) GetResult { func Get(client *gophercloud.ServiceClient, id string) GetResult {
var res GetResult var res GetResult
_, err := client.Request("GET", getURL(client, id), gophercloud.RequestOpts{ _, err := client.Get(getURL(client, id), &res.Body, nil)
MoreHeaders: client.AuthenticatedHeaders(),
OkCodes: []int{200},
JSONResponse: &res.Body,
})
res.Err = err res.Err = err
return res return res
} }

View File

@@ -6,17 +6,14 @@ import "github.com/rackspace/gophercloud"
// entire API. // entire API.
func Get(c *gophercloud.ServiceClient) GetResult { func Get(c *gophercloud.ServiceClient) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", getURL(c), gophercloud.RequestOpts{ _, res.Err = c.Get(getURL(c), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
// Ping retrieves a ping to the server. // Ping retrieves a ping to the server.
func Ping(c *gophercloud.ServiceClient) PingResult { func Ping(c *gophercloud.ServiceClient) PingResult {
var res PingResult var res PingResult
_, res.Err = c.Request("GET", pingURL(c), gophercloud.RequestOpts{ _, res.Err = c.Get(pingURL(c), nil, &gophercloud.RequestOpts{
OkCodes: []int{204}, OkCodes: []int{204},
MoreHeaders: map[string]string{"Accept": ""}, MoreHeaders: map[string]string{"Accept": ""},
}) })

View File

@@ -17,9 +17,6 @@ func List(c *gophercloud.ServiceClient) pagination.Pager {
// Get retrieves a specific flavor based on its unique ID. // Get retrieves a specific flavor based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) GetResult { func Get(c *gophercloud.ServiceClient, id string) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", getURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Get(getURL(c, id), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }

View File

@@ -83,7 +83,6 @@ func TestGet(t *testing.T) {
}, },
} }
actual, err := Get(fake.ServiceClient(), "asia").Extract() actual, err := Get(fake.ServiceClient(), "asia").Extract()
th.AssertNoErr(t, err) th.AssertNoErr(t, err)
th.AssertDeepEquals(t, expected, actual) th.AssertDeepEquals(t, expected, actual)

View File

@@ -43,8 +43,6 @@ func Delete(c *gophercloud.ServiceClient, idOrURL string, opts DeleteOptsBuilder
} }
var res DeleteResult var res DeleteResult
_, res.Err = c.Request("DELETE", url, gophercloud.RequestOpts{ _, res.Err = c.Delete(url, nil)
OkCodes: []int{202},
})
return res return res
} }

View File

@@ -177,10 +177,7 @@ func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
} }
// Send request to API // Send request to API
resp, err := c.Request("POST", createURL(c), gophercloud.RequestOpts{ resp, err := c.Post(createURL(c), &reqBody, nil, nil)
JSONBody: &reqBody,
OkCodes: []int{202},
})
res.Header = resp.Header res.Header = resp.Header
res.Err = err res.Err = err
return res return res
@@ -199,10 +196,7 @@ func Get(c *gophercloud.ServiceClient, idOrURL string) GetResult {
} }
var res GetResult var res GetResult
_, res.Err = c.Request("GET", url, gophercloud.RequestOpts{ _, res.Err = c.Get(url, &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
@@ -379,8 +373,6 @@ func Delete(c *gophercloud.ServiceClient, idOrURL string) DeleteResult {
} }
var res DeleteResult var res DeleteResult
_, res.Err = c.Request("DELETE", url, gophercloud.RequestOpts{ _, res.Err = c.Delete(url, nil)
OkCodes: []int{202},
})
return res return res
} }

View File

@@ -109,6 +109,7 @@ func v2auth(client *gophercloud.ProviderClient, endpoint string, options gopherc
if options.AllowReauth { if options.AllowReauth {
client.ReauthFunc = func() error { client.ReauthFunc = func() error {
client.TokenID = ""
return AuthenticateV2(client, options) return AuthenticateV2(client, options)
} }
} }
@@ -132,10 +133,36 @@ func v3auth(client *gophercloud.ProviderClient, endpoint string, options gopherc
v3Client.Endpoint = endpoint v3Client.Endpoint = endpoint
} }
token, err := tokens3.Create(v3Client, options, nil).Extract() var scope *tokens3.Scope
if options.TenantID != "" {
scope = &tokens3.Scope{
ProjectID: options.TenantID,
}
options.TenantID = ""
options.TenantName = ""
} else {
if options.TenantName != "" {
scope = &tokens3.Scope{
ProjectName: options.TenantName,
DomainID: options.DomainID,
DomainName: options.DomainName,
}
options.TenantName = ""
}
}
result := tokens3.Create(v3Client, options, scope)
token, err := result.ExtractToken()
if err != nil { if err != nil {
return err return err
} }
catalog, err := result.ExtractServiceCatalog()
if err != nil {
return err
}
client.TokenID = token.ID client.TokenID = token.ID
if options.AllowReauth { if options.AllowReauth {
@@ -144,7 +171,7 @@ func v3auth(client *gophercloud.ProviderClient, endpoint string, options gopherc
} }
} }
client.EndpointLocator = func(opts gophercloud.EndpointOpts) (string, error) { client.EndpointLocator = func(opts gophercloud.EndpointOpts) (string, error) {
return V3EndpointURL(v3Client, opts) return V3EndpointURL(catalog, opts)
} }
return nil return nil

View File

@@ -8,10 +8,7 @@ import (
// Get retrieves information for a specific extension using its alias. // Get retrieves information for a specific extension using its alias.
func Get(c *gophercloud.ServiceClient, alias string) GetResult { func Get(c *gophercloud.ServiceClient, alias string) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", ExtensionURL(c, alias), gophercloud.RequestOpts{ _, res.Err = c.Get(ExtensionURL(c, alias), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }

View File

@@ -99,9 +99,7 @@ func Create(client *gophercloud.ServiceClient, opts servers.CreateOptsBuilder) s
return res return res
} }
_, res.Err = client.Request("POST", createURL(client), gophercloud.RequestOpts{ _, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: reqBody,
JSONResponse: &res.Body,
OkCodes: []int{200, 202}, OkCodes: []int{200, 202},
}) })
return res return res

View File

@@ -73,9 +73,7 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
return result return result
} }
_, result.Err = client.Request("POST", rootURL(client), gophercloud.RequestOpts{ _, result.Err = client.Post(rootURL(client), reqBody, &result.Body, &gophercloud.RequestOpts{
JSONResponse: &result.Body,
JSONBody: &reqBody,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
@@ -85,22 +83,13 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
// Get will return details for a particular default rule. // Get will return details for a particular default rule.
func Get(client *gophercloud.ServiceClient, id string) GetResult { func Get(client *gophercloud.ServiceClient, id string) GetResult {
var result GetResult var result GetResult
_, result.Err = client.Get(resourceURL(client, id), &result.Body, nil)
_, result.Err = client.Request("GET", resourceURL(client, id), gophercloud.RequestOpts{
JSONResponse: &result.Body,
OkCodes: []int{200},
})
return result return result
} }
// Delete will permanently delete a default rule from the project. // Delete will permanently delete a default rule from the project.
func Delete(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult { func Delete(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
var result gophercloud.ErrResult var result gophercloud.ErrResult
_, result.Err = client.Delete(resourceURL(client, id), nil)
_, result.Err = client.Request("DELETE", resourceURL(client, id), gophercloud.RequestOpts{
OkCodes: []int{204},
})
return result return result
} }

View File

@@ -45,9 +45,7 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
return res return res
} }
_, res.Err = client.Request("POST", createURL(client), gophercloud.RequestOpts{ _, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: reqBody,
JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
return res return res
@@ -56,19 +54,14 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
// Get returns data about a previously created FloatingIP. // Get returns data about a previously created FloatingIP.
func Get(client *gophercloud.ServiceClient, id string) GetResult { func Get(client *gophercloud.ServiceClient, id string) GetResult {
var res GetResult var res GetResult
_, res.Err = client.Request("GET", getURL(client, id), gophercloud.RequestOpts{ _, res.Err = client.Get(getURL(client, id), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
// Delete requests the deletion of a previous allocated FloatingIP. // Delete requests the deletion of a previous allocated FloatingIP.
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult { func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = client.Request("DELETE", deleteURL(client, id), gophercloud.RequestOpts{ _, res.Err = client.Delete(deleteURL(client, id), nil)
OkCodes: []int{202},
})
return res return res
} }
@@ -82,10 +75,7 @@ func Associate(client *gophercloud.ServiceClient, serverId, fip string) Associat
addFloatingIp["address"] = fip addFloatingIp["address"] = fip
reqBody := map[string]interface{}{"addFloatingIp": addFloatingIp} reqBody := map[string]interface{}{"addFloatingIp": addFloatingIp}
_, res.Err = client.Request("POST", associateURL(client, serverId), gophercloud.RequestOpts{ _, res.Err = client.Post(associateURL(client, serverId), reqBody, nil, nil)
JSONBody: reqBody,
OkCodes: []int{202},
})
return res return res
} }
@@ -97,9 +87,6 @@ func Disassociate(client *gophercloud.ServiceClient, serverId, fip string) Disas
removeFloatingIp["address"] = fip removeFloatingIp["address"] = fip
reqBody := map[string]interface{}{"removeFloatingIp": removeFloatingIp} reqBody := map[string]interface{}{"removeFloatingIp": removeFloatingIp}
_, res.Err = client.Request("POST", disassociateURL(client, serverId), gophercloud.RequestOpts{ _, res.Err = client.Post(disassociateURL(client, serverId), reqBody, nil, nil)
JSONBody: reqBody,
OkCodes: []int{202},
})
return res return res
} }

View File

@@ -81,9 +81,7 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
return res return res
} }
_, res.Err = client.Request("POST", createURL(client), gophercloud.RequestOpts{ _, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: reqBody,
JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
return res return res
@@ -92,18 +90,13 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
// Get returns public data about a previously uploaded KeyPair. // Get returns public data about a previously uploaded KeyPair.
func Get(client *gophercloud.ServiceClient, name string) GetResult { func Get(client *gophercloud.ServiceClient, name string) GetResult {
var res GetResult var res GetResult
_, res.Err = client.Request("GET", getURL(client, name), gophercloud.RequestOpts{ _, res.Err = client.Get(getURL(client, name), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
// Delete requests the deletion of a previous stored KeyPair from the server. // Delete requests the deletion of a previous stored KeyPair from the server.
func Delete(client *gophercloud.ServiceClient, name string) DeleteResult { func Delete(client *gophercloud.ServiceClient, name string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = client.Request("DELETE", deleteURL(client, name), gophercloud.RequestOpts{ _, res.Err = client.Delete(deleteURL(client, name), nil)
OkCodes: []int{202},
})
return res return res
} }

View File

@@ -78,9 +78,7 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
return result return result
} }
_, result.Err = client.Request("POST", rootURL(client), gophercloud.RequestOpts{ _, result.Err = client.Post(rootURL(client), reqBody, &result.Body, &gophercloud.RequestOpts{
JSONResponse: &result.Body,
JSONBody: &reqBody,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
@@ -123,9 +121,7 @@ func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder
return result return result
} }
_, result.Err = client.Request("PUT", resourceURL(client, id), gophercloud.RequestOpts{ _, result.Err = client.Put(resourceURL(client, id), reqBody, &result.Body, &gophercloud.RequestOpts{
JSONResponse: &result.Body,
JSONBody: &reqBody,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
@@ -135,23 +131,14 @@ func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder
// Get will return details for a particular security group. // Get will return details for a particular security group.
func Get(client *gophercloud.ServiceClient, id string) GetResult { func Get(client *gophercloud.ServiceClient, id string) GetResult {
var result GetResult var result GetResult
_, result.Err = client.Get(resourceURL(client, id), &result.Body, nil)
_, result.Err = client.Request("GET", resourceURL(client, id), gophercloud.RequestOpts{
JSONResponse: &result.Body,
OkCodes: []int{200},
})
return result return result
} }
// Delete will permanently delete a security group from the project. // Delete will permanently delete a security group from the project.
func Delete(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult { func Delete(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
var result gophercloud.ErrResult var result gophercloud.ErrResult
_, result.Err = client.Delete(resourceURL(client, id), nil)
_, result.Err = client.Request("DELETE", resourceURL(client, id), gophercloud.RequestOpts{
OkCodes: []int{202},
})
return result return result
} }
@@ -234,9 +221,7 @@ func CreateRule(client *gophercloud.ServiceClient, opts CreateRuleOptsBuilder) C
return result return result
} }
_, result.Err = client.Request("POST", rootRuleURL(client), gophercloud.RequestOpts{ _, result.Err = client.Post(rootRuleURL(client), reqBody, &result.Body, &gophercloud.RequestOpts{
JSONResponse: &result.Body,
JSONBody: &reqBody,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
@@ -246,11 +231,7 @@ func CreateRule(client *gophercloud.ServiceClient, opts CreateRuleOptsBuilder) C
// DeleteRule will permanently delete a rule from a security group. // DeleteRule will permanently delete a rule from a security group.
func DeleteRule(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult { func DeleteRule(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
var result gophercloud.ErrResult var result gophercloud.ErrResult
_, result.Err = client.Delete(resourceRuleURL(client, id), nil)
_, result.Err = client.Request("DELETE", resourceRuleURL(client, id), gophercloud.RequestOpts{
OkCodes: []int{202},
})
return result return result
} }
@@ -264,25 +245,13 @@ func actionMap(prefix, groupName string) map[string]map[string]string {
// rules of the group on the server. // rules of the group on the server.
func AddServerToGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult { func AddServerToGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
var result gophercloud.ErrResult var result gophercloud.ErrResult
_, result.Err = client.Post(serverActionURL(client, serverID), actionMap("add", groupName), &result.Body, nil)
_, result.Err = client.Request("POST", serverActionURL(client, serverID), gophercloud.RequestOpts{
JSONResponse: &result.Body,
JSONBody: actionMap("add", groupName),
OkCodes: []int{202},
})
return result return result
} }
// RemoveServerFromGroup will disassociate a server from a security group. // RemoveServerFromGroup will disassociate a server from a security group.
func RemoveServerFromGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult { func RemoveServerFromGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
var result gophercloud.ErrResult var result gophercloud.ErrResult
_, result.Err = client.Post(serverActionURL(client, serverID), actionMap("remove", groupName), &result.Body, nil)
_, result.Err = client.Request("POST", serverActionURL(client, serverID), gophercloud.RequestOpts{
JSONResponse: &result.Body,
JSONBody: actionMap("remove", groupName),
OkCodes: []int{202},
})
return result return result
} }

View File

@@ -0,0 +1,2 @@
// Package servergroups provides the ability to manage server groups
package servergroups

View File

@@ -0,0 +1,161 @@
// +build fixtures
package servergroups
import (
"fmt"
"net/http"
"testing"
th "github.com/rackspace/gophercloud/testhelper"
"github.com/rackspace/gophercloud/testhelper/client"
)
// ListOutput is a sample response to a List call.
const ListOutput = `
{
"server_groups": [
{
"id": "616fb98f-46ca-475e-917e-2563e5a8cd19",
"name": "test",
"policies": [
"anti-affinity"
],
"members": [],
"metadata": {}
},
{
"id": "4d8c3732-a248-40ed-bebc-539a6ffd25c0",
"name": "test2",
"policies": [
"affinity"
],
"members": [],
"metadata": {}
}
]
}
`
// GetOutput is a sample response to a Get call.
const GetOutput = `
{
"server_group": {
"id": "616fb98f-46ca-475e-917e-2563e5a8cd19",
"name": "test",
"policies": [
"anti-affinity"
],
"members": [],
"metadata": {}
}
}
`
// CreateOutput is a sample response to a Post call
const CreateOutput = `
{
"server_group": {
"id": "616fb98f-46ca-475e-917e-2563e5a8cd19",
"name": "test",
"policies": [
"anti-affinity"
],
"members": [],
"metadata": {}
}
}
`
// FirstServerGroup is the first result in ListOutput.
var FirstServerGroup = ServerGroup{
ID: "616fb98f-46ca-475e-917e-2563e5a8cd19",
Name: "test",
Policies: []string{
"anti-affinity",
},
Members: []string{},
Metadata: map[string]interface{}{},
}
// SecondServerGroup is the second result in ListOutput.
var SecondServerGroup = ServerGroup{
ID: "4d8c3732-a248-40ed-bebc-539a6ffd25c0",
Name: "test2",
Policies: []string{
"affinity",
},
Members: []string{},
Metadata: map[string]interface{}{},
}
// ExpectedServerGroupSlice is the slice of results that should be parsed
// from ListOutput, in the expected order.
var ExpectedServerGroupSlice = []ServerGroup{FirstServerGroup, SecondServerGroup}
// CreatedServerGroup is the parsed result from CreateOutput.
var CreatedServerGroup = ServerGroup{
ID: "616fb98f-46ca-475e-917e-2563e5a8cd19",
Name: "test",
Policies: []string{
"anti-affinity",
},
Members: []string{},
Metadata: map[string]interface{}{},
}
// HandleListSuccessfully configures the test server to respond to a List request.
func HandleListSuccessfully(t *testing.T) {
th.Mux.HandleFunc("/os-server-groups", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
w.Header().Add("Content-Type", "application/json")
fmt.Fprintf(w, ListOutput)
})
}
// HandleGetSuccessfully configures the test server to respond to a Get request
// for an existing server group
func HandleGetSuccessfully(t *testing.T) {
th.Mux.HandleFunc("/os-server-groups/4d8c3732-a248-40ed-bebc-539a6ffd25c0", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
w.Header().Add("Content-Type", "application/json")
fmt.Fprintf(w, GetOutput)
})
}
// HandleCreateSuccessfully configures the test server to respond to a Create request
// for a new server group
func HandleCreateSuccessfully(t *testing.T) {
th.Mux.HandleFunc("/os-server-groups", 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, `
{
"server_group": {
"name": "test",
"policies": [
"anti-affinity"
]
}
}
`)
w.Header().Add("Content-Type", "application/json")
fmt.Fprintf(w, CreateOutput)
})
}
// HandleDeleteSuccessfully configures the test server to respond to a Delete request for a
// an existing server group
func HandleDeleteSuccessfully(t *testing.T) {
th.Mux.HandleFunc("/os-server-groups/616fb98f-46ca-475e-917e-2563e5a8cd19", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "DELETE")
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
w.WriteHeader(http.StatusAccepted)
})
}

View File

@@ -0,0 +1,77 @@
package servergroups
import (
"errors"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
)
// List returns a Pager that allows you to iterate over a collection of ServerGroups.
func List(client *gophercloud.ServiceClient) pagination.Pager {
return pagination.NewPager(client, listURL(client), func(r pagination.PageResult) pagination.Page {
return ServerGroupsPage{pagination.SinglePageBase(r)}
})
}
// CreateOptsBuilder describes struct types that can be accepted by the Create call. Notably, the
// CreateOpts struct in this package does.
type CreateOptsBuilder interface {
ToServerGroupCreateMap() (map[string]interface{}, error)
}
// CreateOpts specifies a Server Group allocation request
type CreateOpts struct {
// Name is the name of the server group
Name string
// Policies are the server group policies
Policies []string
}
// ToServerGroupCreateMap constructs a request body from CreateOpts.
func (opts CreateOpts) ToServerGroupCreateMap() (map[string]interface{}, error) {
if opts.Name == "" {
return nil, errors.New("Missing field required for server group creation: Name")
}
if len(opts.Policies) < 1 {
return nil, errors.New("Missing field required for server group creation: Policies")
}
serverGroup := make(map[string]interface{})
serverGroup["name"] = opts.Name
serverGroup["policies"] = opts.Policies
return map[string]interface{}{"server_group": serverGroup}, nil
}
// Create requests the creation of a new Server Group
func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
var res CreateResult
reqBody, err := opts.ToServerGroupCreateMap()
if err != nil {
res.Err = err
return res
}
_, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
OkCodes: []int{200},
})
return res
}
// Get returns data about a previously created ServerGroup.
func Get(client *gophercloud.ServiceClient, id string) GetResult {
var res GetResult
_, res.Err = client.Get(getURL(client, id), &res.Body, nil)
return res
}
// Delete requests the deletion of a previously allocated ServerGroup.
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
var res DeleteResult
_, res.Err = client.Delete(deleteURL(client, id), nil)
return res
}

View File

@@ -0,0 +1,59 @@
package servergroups
import (
"testing"
"github.com/rackspace/gophercloud/pagination"
th "github.com/rackspace/gophercloud/testhelper"
"github.com/rackspace/gophercloud/testhelper/client"
)
func TestList(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
HandleListSuccessfully(t)
count := 0
err := List(client.ServiceClient()).EachPage(func(page pagination.Page) (bool, error) {
count++
actual, err := ExtractServerGroups(page)
th.AssertNoErr(t, err)
th.CheckDeepEquals(t, ExpectedServerGroupSlice, actual)
return true, nil
})
th.AssertNoErr(t, err)
th.CheckEquals(t, 1, count)
}
func TestCreate(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
HandleCreateSuccessfully(t)
actual, err := Create(client.ServiceClient(), CreateOpts{
Name: "test",
Policies: []string{"anti-affinity"},
}).Extract()
th.AssertNoErr(t, err)
th.CheckDeepEquals(t, &CreatedServerGroup, actual)
}
func TestGet(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
HandleGetSuccessfully(t)
actual, err := Get(client.ServiceClient(), "4d8c3732-a248-40ed-bebc-539a6ffd25c0").Extract()
th.AssertNoErr(t, err)
th.CheckDeepEquals(t, &FirstServerGroup, actual)
}
func TestDelete(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
HandleDeleteSuccessfully(t)
err := Delete(client.ServiceClient(), "616fb98f-46ca-475e-917e-2563e5a8cd19").ExtractErr()
th.AssertNoErr(t, err)
}

View File

@@ -0,0 +1,87 @@
package servergroups
import (
"github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
)
// A ServerGroup creates a policy for instance placement in the cloud
type ServerGroup struct {
// ID is the unique ID of the Server Group.
ID string `mapstructure:"id"`
// Name is the common name of the server group.
Name string `mapstructure:"name"`
// Polices are the group policies.
Policies []string `mapstructure:"policies"`
// Members are the members of the server group.
Members []string `mapstructure:"members"`
// Metadata includes a list of all user-specified key-value pairs attached to the Server Group.
Metadata map[string]interface{}
}
// ServerGroupsPage stores a single, only page of ServerGroups
// results from a List call.
type ServerGroupsPage struct {
pagination.SinglePageBase
}
// IsEmpty determines whether or not a ServerGroupsPage is empty.
func (page ServerGroupsPage) IsEmpty() (bool, error) {
va, err := ExtractServerGroups(page)
return len(va) == 0, err
}
// ExtractServerGroups interprets a page of results as a slice of
// ServerGroups.
func ExtractServerGroups(page pagination.Page) ([]ServerGroup, error) {
casted := page.(ServerGroupsPage).Body
var response struct {
ServerGroups []ServerGroup `mapstructure:"server_groups"`
}
err := mapstructure.WeakDecode(casted, &response)
return response.ServerGroups, err
}
type ServerGroupResult struct {
gophercloud.Result
}
// Extract is a method that attempts to interpret any Server Group resource
// response as a ServerGroup struct.
func (r ServerGroupResult) Extract() (*ServerGroup, error) {
if r.Err != nil {
return nil, r.Err
}
var res struct {
ServerGroup *ServerGroup `json:"server_group" mapstructure:"server_group"`
}
err := mapstructure.WeakDecode(r.Body, &res)
return res.ServerGroup, err
}
// CreateResult is the response from a Create operation. Call its Extract method to interpret it
// as a ServerGroup.
type CreateResult struct {
ServerGroupResult
}
// GetResult is the response from a Get operation. Call its Extract method to interpret it
// as a ServerGroup.
type GetResult struct {
ServerGroupResult
}
// DeleteResult is the response from a Delete operation. Call its Extract method to determine if
// the call succeeded or failed.
type DeleteResult struct {
gophercloud.ErrResult
}

View File

@@ -0,0 +1,25 @@
package servergroups
import "github.com/rackspace/gophercloud"
const resourcePath = "os-server-groups"
func resourceURL(c *gophercloud.ServiceClient) string {
return c.ServiceURL(resourcePath)
}
func listURL(c *gophercloud.ServiceClient) string {
return resourceURL(c)
}
func createURL(c *gophercloud.ServiceClient) string {
return resourceURL(c)
}
func getURL(c *gophercloud.ServiceClient, id string) string {
return c.ServiceURL(resourcePath, id)
}
func deleteURL(c *gophercloud.ServiceClient, id string) string {
return getURL(c, id)
}

View File

@@ -0,0 +1,42 @@
package servergroups
import (
"testing"
th "github.com/rackspace/gophercloud/testhelper"
"github.com/rackspace/gophercloud/testhelper/client"
)
func TestListURL(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
c := client.ServiceClient()
th.CheckEquals(t, c.Endpoint+"os-server-groups", listURL(c))
}
func TestCreateURL(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
c := client.ServiceClient()
th.CheckEquals(t, c.Endpoint+"os-server-groups", createURL(c))
}
func TestGetURL(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
c := client.ServiceClient()
id := "1"
th.CheckEquals(t, c.Endpoint+"os-server-groups/"+id, getURL(c, id))
}
func TestDeleteURL(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
c := client.ServiceClient()
id := "1"
th.CheckEquals(t, c.Endpoint+"os-server-groups/"+id, deleteURL(c, id))
}

View File

@@ -9,27 +9,15 @@ func actionURL(client *gophercloud.ServiceClient, id string) string {
// Start is the operation responsible for starting a Compute server. // Start is the operation responsible for starting a Compute server.
func Start(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult { func Start(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
var res gophercloud.ErrResult var res gophercloud.ErrResult
reqBody := map[string]interface{}{"os-start": nil} reqBody := map[string]interface{}{"os-start": nil}
_, res.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
_, res.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{
JSONBody: reqBody,
OkCodes: []int{202},
})
return res return res
} }
// Stop is the operation responsible for stopping a Compute server. // Stop is the operation responsible for stopping a Compute server.
func Stop(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult { func Stop(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
var res gophercloud.ErrResult var res gophercloud.ErrResult
reqBody := map[string]interface{}{"os-stop": nil} reqBody := map[string]interface{}{"os-stop": nil}
_, res.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
_, res.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{
JSONBody: reqBody,
OkCodes: []int{202},
})
return res return res
} }

View File

@@ -0,0 +1,2 @@
// Package tenantnetworks provides the ability for tenants to see information about the networks they have access to
package tenantnetworks

View File

@@ -0,0 +1,84 @@
// +build fixtures
package tenantnetworks
import (
"fmt"
"net/http"
"testing"
"time"
th "github.com/rackspace/gophercloud/testhelper"
"github.com/rackspace/gophercloud/testhelper/client"
)
// ListOutput is a sample response to a List call.
const ListOutput = `
{
"networks": [
{
"cidr": "10.0.0.0/29",
"id": "20c8acc0-f747-4d71-a389-46d078ebf047",
"label": "mynet_0"
},
{
"cidr": "10.0.0.10/29",
"id": "20c8acc0-f747-4d71-a389-46d078ebf000",
"label": "mynet_1"
}
]
}
`
// GetOutput is a sample response to a Get call.
const GetOutput = `
{
"network": {
"cidr": "10.0.0.10/29",
"id": "20c8acc0-f747-4d71-a389-46d078ebf000",
"label": "mynet_1"
}
}
`
// FirstNetwork is the first result in ListOutput.
var nilTime time.Time
var FirstNetwork = Network{
CIDR: "10.0.0.0/29",
ID: "20c8acc0-f747-4d71-a389-46d078ebf047",
Name: "mynet_0",
}
// SecondNetwork is the second result in ListOutput.
var SecondNetwork = Network{
CIDR: "10.0.0.10/29",
ID: "20c8acc0-f747-4d71-a389-46d078ebf000",
Name: "mynet_1",
}
// ExpectedNetworkSlice is the slice of results that should be parsed
// from ListOutput, in the expected order.
var ExpectedNetworkSlice = []Network{FirstNetwork, SecondNetwork}
// HandleListSuccessfully configures the test server to respond to a List request.
func HandleListSuccessfully(t *testing.T) {
th.Mux.HandleFunc("/os-tenant-networks", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
w.Header().Add("Content-Type", "application/json")
fmt.Fprintf(w, ListOutput)
})
}
// HandleGetSuccessfully configures the test server to respond to a Get request
// for an existing network.
func HandleGetSuccessfully(t *testing.T) {
th.Mux.HandleFunc("/os-tenant-networks/20c8acc0-f747-4d71-a389-46d078ebf000", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
w.Header().Add("Content-Type", "application/json")
fmt.Fprintf(w, GetOutput)
})
}

View File

@@ -0,0 +1,22 @@
package tenantnetworks
import (
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
)
// List returns a Pager that allows you to iterate over a collection of Network.
func List(client *gophercloud.ServiceClient) pagination.Pager {
url := listURL(client)
createPage := func(r pagination.PageResult) pagination.Page {
return NetworkPage{pagination.SinglePageBase(r)}
}
return pagination.NewPager(client, url, createPage)
}
// Get returns data about a previously created Network.
func Get(client *gophercloud.ServiceClient, id string) GetResult {
var res GetResult
_, res.Err = client.Get(getURL(client, id), &res.Body, nil)
return res
}

View File

@@ -0,0 +1,37 @@
package tenantnetworks
import (
"testing"
"github.com/rackspace/gophercloud/pagination"
th "github.com/rackspace/gophercloud/testhelper"
"github.com/rackspace/gophercloud/testhelper/client"
)
func TestList(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
HandleListSuccessfully(t)
count := 0
err := List(client.ServiceClient()).EachPage(func(page pagination.Page) (bool, error) {
count++
actual, err := ExtractNetworks(page)
th.AssertNoErr(t, err)
th.CheckDeepEquals(t, ExpectedNetworkSlice, actual)
return true, nil
})
th.AssertNoErr(t, err)
th.CheckEquals(t, 1, count)
}
func TestGet(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
HandleGetSuccessfully(t)
actual, err := Get(client.ServiceClient(), "20c8acc0-f747-4d71-a389-46d078ebf000").Extract()
th.AssertNoErr(t, err)
th.CheckDeepEquals(t, &SecondNetwork, actual)
}

View File

@@ -0,0 +1,68 @@
package tenantnetworks
import (
"github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud"
"github.com/rackspace/gophercloud/pagination"
)
// A Network represents a nova-network that an instance communicates on
type Network struct {
// CIDR is the IPv4 subnet.
CIDR string `mapstructure:"cidr"`
// ID is the UUID of the network.
ID string `mapstructure:"id"`
// Name is the common name that the network has.
Name string `mapstructure:"label"`
}
// NetworkPage stores a single, only page of Networks
// results from a List call.
type NetworkPage struct {
pagination.SinglePageBase
}
// IsEmpty determines whether or not a NetworkPage is empty.
func (page NetworkPage) IsEmpty() (bool, error) {
va, err := ExtractNetworks(page)
return len(va) == 0, err
}
// ExtractNetworks interprets a page of results as a slice of Networks
func ExtractNetworks(page pagination.Page) ([]Network, error) {
networks := page.(NetworkPage).Body
var res struct {
Networks []Network `mapstructure:"networks"`
}
err := mapstructure.WeakDecode(networks, &res)
return res.Networks, err
}
type NetworkResult struct {
gophercloud.Result
}
// Extract is a method that attempts to interpret any Network resource
// response as a Network struct.
func (r NetworkResult) Extract() (*Network, error) {
if r.Err != nil {
return nil, r.Err
}
var res struct {
Network *Network `json:"network" mapstructure:"network"`
}
err := mapstructure.Decode(r.Body, &res)
return res.Network, err
}
// GetResult is the response from a Get operation. Call its Extract method to interpret it
// as a Network.
type GetResult struct {
NetworkResult
}

View File

@@ -0,0 +1,17 @@
package tenantnetworks
import "github.com/rackspace/gophercloud"
const resourcePath = "os-tenant-networks"
func resourceURL(c *gophercloud.ServiceClient) string {
return c.ServiceURL(resourcePath)
}
func listURL(c *gophercloud.ServiceClient) string {
return resourceURL(c)
}
func getURL(c *gophercloud.ServiceClient, id string) string {
return c.ServiceURL(resourcePath, id)
}

View File

@@ -0,0 +1,25 @@
package tenantnetworks
import (
"testing"
th "github.com/rackspace/gophercloud/testhelper"
"github.com/rackspace/gophercloud/testhelper/client"
)
func TestListURL(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
c := client.ServiceClient()
th.CheckEquals(t, c.Endpoint+"os-tenant-networks", listURL(c))
}
func TestGetURL(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
c := client.ServiceClient()
id := "1"
th.CheckEquals(t, c.Endpoint+"os-tenant-networks/"+id, getURL(c, id))
}

View File

@@ -54,9 +54,7 @@ func Create(client *gophercloud.ServiceClient, serverId string, opts CreateOptsB
return res return res
} }
_, res.Err = client.Request("POST", createURL(client, serverId), gophercloud.RequestOpts{ _, res.Err = client.Post(createURL(client, serverId), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: reqBody,
JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
return res return res
@@ -65,18 +63,13 @@ func Create(client *gophercloud.ServiceClient, serverId string, opts CreateOptsB
// Get returns public data about a previously created VolumeAttachment. // Get returns public data about a previously created VolumeAttachment.
func Get(client *gophercloud.ServiceClient, serverId, aId string) GetResult { func Get(client *gophercloud.ServiceClient, serverId, aId string) GetResult {
var res GetResult var res GetResult
_, res.Err = client.Request("GET", getURL(client, serverId, aId), gophercloud.RequestOpts{ _, res.Err = client.Get(getURL(client, serverId, aId), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
// Delete requests the deletion of a previous stored VolumeAttachment from the server. // Delete requests the deletion of a previous stored VolumeAttachment from the server.
func Delete(client *gophercloud.ServiceClient, serverId, aId string) DeleteResult { func Delete(client *gophercloud.ServiceClient, serverId, aId string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = client.Request("DELETE", deleteURL(client, serverId, aId), gophercloud.RequestOpts{ _, res.Err = client.Delete(deleteURL(client, serverId, aId), nil)
OkCodes: []int{202},
})
return res return res
} }

View File

@@ -62,9 +62,7 @@ func ListDetail(client *gophercloud.ServiceClient, opts ListOptsBuilder) paginat
// Get instructs OpenStack to provide details on a single flavor, identified by its ID. // Get instructs OpenStack to provide details on a single flavor, identified by its ID.
// Use ExtractFlavor to convert its result into a Flavor. // Use ExtractFlavor to convert its result into a Flavor.
func Get(client *gophercloud.ServiceClient, id string) GetResult { func Get(client *gophercloud.ServiceClient, id string) GetResult {
var gr GetResult var res GetResult
_, gr.Err = client.Request("GET", getURL(client, id), gophercloud.RequestOpts{ _, res.Err = client.Get(getURL(client, id), &res.Body, nil)
JSONResponse: &gr.Body, return res
})
return gr
} }

View File

@@ -60,9 +60,13 @@ func ListDetail(client *gophercloud.ServiceClient, opts ListOptsBuilder) paginat
// Use ExtractImage() to interpret the result as an openstack Image. // Use ExtractImage() to interpret the result as an openstack Image.
func Get(client *gophercloud.ServiceClient, id string) GetResult { func Get(client *gophercloud.ServiceClient, id string) GetResult {
var result GetResult var result GetResult
_, result.Err = client.Request("GET", getURL(client, id), gophercloud.RequestOpts{ _, result.Err = client.Get(getURL(client, id), &result.Body, nil)
JSONResponse: &result.Body, return result
OkCodes: []int{200}, }
})
// Delete deletes the specified image ID.
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
var result DeleteResult
_, result.Err = client.Delete(deleteURL(client, id), nil)
return result return result
} }

View File

@@ -173,3 +173,19 @@ func TestNextPageURL(t *testing.T) {
th.AssertNoErr(t, err) th.AssertNoErr(t, err)
th.CheckEquals(t, expected, actual) th.CheckEquals(t, expected, actual)
} }
// Test Image delete
func TestDeleteImage(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
th.Mux.HandleFunc("/images/12345678", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "DELETE")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
w.WriteHeader(http.StatusNoContent)
})
res := Delete(fake.ServiceClient(), "12345678")
th.AssertNoErr(t, res.Err)
}

View File

@@ -11,6 +11,11 @@ type GetResult struct {
gophercloud.Result gophercloud.Result
} }
// DeleteResult represents the result of an image.Delete operation.
type DeleteResult struct {
gophercloud.ErrResult
}
// Extract interprets a GetResult as an Image. // Extract interprets a GetResult as an Image.
func (gr GetResult) Extract() (*Image, error) { func (gr GetResult) Extract() (*Image, error) {
if gr.Err != nil { if gr.Err != nil {

View File

@@ -9,3 +9,7 @@ func listDetailURL(client *gophercloud.ServiceClient) string {
func getURL(client *gophercloud.ServiceClient, id string) string { func getURL(client *gophercloud.ServiceClient, id string) string {
return client.ServiceURL("images", id) return client.ServiceURL("images", id)
} }
func deleteURL(client *gophercloud.ServiceClient, id string) string {
return client.ServiceURL("images", id)
}

View File

@@ -567,3 +567,98 @@ func HandleMetadataUpdateSuccessfully(t *testing.T) {
w.Write([]byte(`{ "metadata": {"foo":"baz", "this":"those"}}`)) w.Write([]byte(`{ "metadata": {"foo":"baz", "this":"those"}}`))
}) })
} }
// ListAddressesExpected represents an expected repsonse from a ListAddresses request.
var ListAddressesExpected = map[string][]Address{
"public": []Address{
Address{
Version: 4,
Address: "80.56.136.39",
},
Address{
Version: 6,
Address: "2001:4800:790e:510:be76:4eff:fe04:82a8",
},
},
"private": []Address{
Address{
Version: 4,
Address: "10.880.3.154",
},
},
}
// HandleAddressListSuccessfully sets up the test server to respond to a ListAddresses request.
func HandleAddressListSuccessfully(t *testing.T) {
th.Mux.HandleFunc("/servers/asdfasdfasdf/ips", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
w.Header().Add("Content-Type", "application/json")
fmt.Fprintf(w, `{
"addresses": {
"public": [
{
"version": 4,
"addr": "50.56.176.35"
},
{
"version": 6,
"addr": "2001:4800:780e:510:be76:4eff:fe04:84a8"
}
],
"private": [
{
"version": 4,
"addr": "10.180.3.155"
}
]
}
}`)
})
}
// ListNetworkAddressesExpected represents an expected repsonse from a ListAddressesByNetwork request.
var ListNetworkAddressesExpected = []Address{
Address{
Version: 4,
Address: "50.56.176.35",
},
Address{
Version: 6,
Address: "2001:4800:780e:510:be76:4eff:fe04:84a8",
},
}
// HandleNetworkAddressListSuccessfully sets up the test server to respond to a ListAddressesByNetwork request.
func HandleNetworkAddressListSuccessfully(t *testing.T) {
th.Mux.HandleFunc("/servers/asdfasdfasdf/ips/public", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
w.Header().Add("Content-Type", "application/json")
fmt.Fprintf(w, `{
"public": [
{
"version": 4,
"addr": "50.56.176.35"
},
{
"version": 6,
"addr": "2001:4800:780e:510:be76:4eff:fe04:84a8"
}
]
}`)
})
}
// HandleCreateServerImageSuccessfully sets up the test server to respond to a TestCreateServerImage request.
func HandleCreateServerImageSuccessfully(t *testing.T) {
th.Mux.HandleFunc("/servers/serverimage/action", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "POST")
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
w.Header().Add("Location", "https://0.0.0.0/images/xxxx-xxxxx-xxxxx-xxxx")
w.WriteHeader(http.StatusAccepted)
})
}

View File

@@ -14,7 +14,6 @@ import (
type ListOptsBuilder interface { type ListOptsBuilder interface {
ToServerListQuery() (string, error) ToServerListQuery() (string, error)
} }
// ListOpts allows the filtering and sorting of paginated collections through // ListOpts allows the filtering and sorting of paginated collections through
// the API. Filtering is achieved by passing in struct field values that map to // the API. Filtering is achieved by passing in struct field values that map to
// the server attributes you want to see returned. Marker and Limit are used // the server attributes you want to see returned. Marker and Limit are used
@@ -216,28 +215,21 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
return res return res
} }
_, res.Err = client.Request("POST", listURL(client), gophercloud.RequestOpts{ _, res.Err = client.Post(listURL(client), reqBody, &res.Body, nil)
JSONResponse: &res.Body,
JSONBody: reqBody,
OkCodes: []int{202},
})
return res return res
} }
// Delete requests that a server previously provisioned be removed from your account. // Delete requests that a server previously provisioned be removed from your account.
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult { func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = client.Request("DELETE", deleteURL(client, id), gophercloud.RequestOpts{ _, res.Err = client.Delete(deleteURL(client, id), nil)
OkCodes: []int{204},
})
return res return res
} }
// Get requests details on a single server, by ID. // Get requests details on a single server, by ID.
func Get(client *gophercloud.ServiceClient, id string) GetResult { func Get(client *gophercloud.ServiceClient, id string) GetResult {
var result GetResult var result GetResult
_, result.Err = client.Request("GET", getURL(client, id), gophercloud.RequestOpts{ _, result.Err = client.Get(getURL(client, id), &result.Body, &gophercloud.RequestOpts{
JSONResponse: &result.Body,
OkCodes: []int{200, 203}, OkCodes: []int{200, 203},
}) })
return result return result
@@ -280,9 +272,9 @@ func (opts UpdateOpts) ToServerUpdateMap() map[string]interface{} {
// Update requests that various attributes of the indicated server be changed. // Update requests that various attributes of the indicated server be changed.
func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult { func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
var result UpdateResult var result UpdateResult
_, result.Err = client.Request("PUT", updateURL(client, id), gophercloud.RequestOpts{ reqBody := opts.ToServerUpdateMap()
JSONResponse: &result.Body, _, result.Err = client.Put(updateURL(client, id), reqBody, &result.Body, &gophercloud.RequestOpts{
JSONBody: opts.ToServerUpdateMap(), OkCodes: []int{200},
}) })
return result return result
} }
@@ -298,12 +290,7 @@ func ChangeAdminPassword(client *gophercloud.ServiceClient, id, newPassword stri
req.ChangePassword.AdminPass = newPassword req.ChangePassword.AdminPass = newPassword
var res ActionResult var res ActionResult
_, res.Err = client.Post(actionURL(client, id), req, nil, nil)
_, res.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{
JSONBody: req,
OkCodes: []int{202},
})
return res return res
} }
@@ -367,15 +354,13 @@ func Reboot(client *gophercloud.ServiceClient, id string, how RebootMethod) Acti
return res return res
} }
_, res.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{ reqBody := struct {
JSONBody: struct {
C map[string]string `json:"reboot"` C map[string]string `json:"reboot"`
}{ }{
map[string]string{"type": string(how)}, map[string]string{"type": string(how)},
}, }
OkCodes: []int{202},
})
_, res.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
return res return res
} }
@@ -468,12 +453,7 @@ func Rebuild(client *gophercloud.ServiceClient, id string, opts RebuildOptsBuild
return result return result
} }
_, result.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{ _, result.Err = client.Post(actionURL(client, id), reqBody, &result.Body, nil)
JSONBody: &reqBody,
JSONResponse: &result.Body,
OkCodes: []int{202},
})
return result return result
} }
@@ -514,11 +494,7 @@ func Resize(client *gophercloud.ServiceClient, id string, opts ResizeOptsBuilder
return res return res
} }
_, res.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{ _, res.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
JSONBody: reqBody,
OkCodes: []int{202},
})
return res return res
} }
@@ -527,11 +503,10 @@ func Resize(client *gophercloud.ServiceClient, id string, opts ResizeOptsBuilder
func ConfirmResize(client *gophercloud.ServiceClient, id string) ActionResult { func ConfirmResize(client *gophercloud.ServiceClient, id string) ActionResult {
var res ActionResult var res ActionResult
_, res.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{ reqBody := map[string]interface{}{"confirmResize": nil}
JSONBody: map[string]interface{}{"confirmResize": nil}, _, res.Err = client.Post(actionURL(client, id), reqBody, nil, &gophercloud.RequestOpts{
OkCodes: []int{204}, OkCodes: []int{201, 202, 204},
}) })
return res return res
} }
@@ -539,12 +514,8 @@ func ConfirmResize(client *gophercloud.ServiceClient, id string) ActionResult {
// See Resize() for more details. // See Resize() for more details.
func RevertResize(client *gophercloud.ServiceClient, id string) ActionResult { func RevertResize(client *gophercloud.ServiceClient, id string) ActionResult {
var res ActionResult var res ActionResult
reqBody := map[string]interface{}{"revertResize": nil}
_, res.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{ _, res.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
JSONBody: map[string]interface{}{"revertResize": nil},
OkCodes: []int{202},
})
return res return res
} }
@@ -586,9 +557,7 @@ func Rescue(client *gophercloud.ServiceClient, id string, opts RescueOptsBuilder
return result return result
} }
_, result.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{ _, result.Err = client.Post(actionURL(client, id), reqBody, &result.Body, &gophercloud.RequestOpts{
JSONResponse: &result.Body,
JSONBody: &reqBody,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
@@ -625,9 +594,8 @@ func ResetMetadata(client *gophercloud.ServiceClient, id string, opts ResetMetad
res.Err = err res.Err = err
return res return res
} }
_, res.Err = client.Request("PUT", metadataURL(client, id), gophercloud.RequestOpts{ _, res.Err = client.Put(metadataURL(client, id), metadata, &res.Body, &gophercloud.RequestOpts{
JSONBody: metadata, OkCodes: []int{200},
JSONResponse: &res.Body,
}) })
return res return res
} }
@@ -635,9 +603,7 @@ func ResetMetadata(client *gophercloud.ServiceClient, id string, opts ResetMetad
// Metadata requests all the metadata for the given server ID. // Metadata requests all the metadata for the given server ID.
func Metadata(client *gophercloud.ServiceClient, id string) GetMetadataResult { func Metadata(client *gophercloud.ServiceClient, id string) GetMetadataResult {
var res GetMetadataResult var res GetMetadataResult
_, res.Err = client.Request("GET", metadataURL(client, id), gophercloud.RequestOpts{ _, res.Err = client.Get(metadataURL(client, id), &res.Body, nil)
JSONResponse: &res.Body,
})
return res return res
} }
@@ -657,9 +623,8 @@ func UpdateMetadata(client *gophercloud.ServiceClient, id string, opts UpdateMet
res.Err = err res.Err = err
return res return res
} }
_, res.Err = client.Request("POST", metadataURL(client, id), gophercloud.RequestOpts{ _, res.Err = client.Post(metadataURL(client, id), metadata, &res.Body, &gophercloud.RequestOpts{
JSONBody: metadata, OkCodes: []int{200},
JSONResponse: &res.Body,
}) })
return res return res
} }
@@ -695,9 +660,8 @@ func CreateMetadatum(client *gophercloud.ServiceClient, id string, opts Metadatu
return res return res
} }
_, res.Err = client.Request("PUT", metadatumURL(client, id, key), gophercloud.RequestOpts{ _, res.Err = client.Put(metadatumURL(client, id, key), metadatum, &res.Body, &gophercloud.RequestOpts{
JSONBody: metadatum, OkCodes: []int{200},
JSONResponse: &res.Body,
}) })
return res return res
} }
@@ -714,8 +678,68 @@ func Metadatum(client *gophercloud.ServiceClient, id, key string) GetMetadatumRe
// DeleteMetadatum will delete the key-value pair with the given key for the given server ID. // 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 { func DeleteMetadatum(client *gophercloud.ServiceClient, id, key string) DeleteMetadatumResult {
var res DeleteMetadatumResult var res DeleteMetadatumResult
_, res.Err = client.Request("DELETE", metadatumURL(client, id, key), gophercloud.RequestOpts{ _, res.Err = client.Delete(metadatumURL(client, id, key), &gophercloud.RequestOpts{
JSONResponse: &res.Body, JSONResponse: &res.Body,
}) })
return res return res
} }
// ListAddresses makes a request against the API to list the servers IP addresses.
func ListAddresses(client *gophercloud.ServiceClient, id string) pagination.Pager {
createPageFn := func(r pagination.PageResult) pagination.Page {
return AddressPage{pagination.SinglePageBase(r)}
}
return pagination.NewPager(client, listAddressesURL(client, id), createPageFn)
}
// ListAddressesByNetwork makes a request against the API to list the servers IP addresses
// for the given network.
func ListAddressesByNetwork(client *gophercloud.ServiceClient, id, network string) pagination.Pager {
createPageFn := func(r pagination.PageResult) pagination.Page {
return NetworkAddressPage{pagination.SinglePageBase(r)}
}
return pagination.NewPager(client, listAddressesByNetworkURL(client, id, network), createPageFn)
}
type CreateImageOpts struct {
// Name [required] of the image/snapshot
Name string
// Metadata [optional] contains key-value pairs (up to 255 bytes each) to attach to the created image.
Metadata map[string]string
}
type CreateImageOptsBuilder interface {
ToServerCreateImageMap() (map[string]interface{}, error)
}
// ToServerCreateImageMap formats a CreateImageOpts structure into a request body.
func (opts CreateImageOpts) ToServerCreateImageMap() (map[string]interface{}, error) {
var err error
img := make(map[string]interface{})
if opts.Name == "" {
return nil, fmt.Errorf("Cannot create a server image without a name")
}
img["name"] = opts.Name
if opts.Metadata != nil {
img["metadata"] = opts.Metadata
}
createImage := make(map[string]interface{})
createImage["createImage"] = img
return createImage, err
}
// CreateImage makes a request against the nova API to schedule an image to be created of the server
func CreateImage(client *gophercloud.ServiceClient, serverId string, opts CreateImageOptsBuilder) CreateImageResult {
var res CreateImageResult
reqBody, err := opts.ToServerCreateImageMap()
if err != nil {
res.Err = err
return res
}
response, err := client.Post(actionURL(client, serverId), reqBody, nil, &gophercloud.RequestOpts{
OkCodes: []int{202},
})
res.Err = err
res.Header = response.Header
return res
}

View File

@@ -277,3 +277,60 @@ func TestUpdateMetadata(t *testing.T) {
th.AssertNoErr(t, err) th.AssertNoErr(t, err)
th.AssertDeepEquals(t, expected, actual) th.AssertDeepEquals(t, expected, actual)
} }
func TestListAddresses(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
HandleAddressListSuccessfully(t)
expected := ListAddressesExpected
pages := 0
err := ListAddresses(client.ServiceClient(), "asdfasdfasdf").EachPage(func(page pagination.Page) (bool, error) {
pages++
actual, err := ExtractAddresses(page)
th.AssertNoErr(t, err)
if len(actual) != 2 {
t.Fatalf("Expected 2 networks, got %d", len(actual))
}
th.CheckDeepEquals(t, expected, actual)
return true, nil
})
th.AssertNoErr(t, err)
th.CheckEquals(t, 1, pages)
}
func TestListAddressesByNetwork(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
HandleNetworkAddressListSuccessfully(t)
expected := ListNetworkAddressesExpected
pages := 0
err := ListAddressesByNetwork(client.ServiceClient(), "asdfasdfasdf", "public").EachPage(func(page pagination.Page) (bool, error) {
pages++
actual, err := ExtractNetworkAddresses(page)
th.AssertNoErr(t, err)
if len(actual) != 2 {
t.Fatalf("Expected 2 addresses, got %d", len(actual))
}
th.CheckDeepEquals(t, expected, actual)
return true, nil
})
th.AssertNoErr(t, err)
th.CheckEquals(t, 1, pages)
}
func TestCreateServerImage(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
HandleCreateServerImageSuccessfully(t)
_, err := CreateImage(client.ServiceClient(), "serverimage", CreateImageOpts{Name: "test"}).ExtractImageID()
th.AssertNoErr(t, err)
}

View File

@@ -2,6 +2,9 @@ package servers
import ( import (
"reflect" "reflect"
"fmt"
"path"
"net/url"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud"
@@ -74,6 +77,28 @@ type RescueResult struct {
ActionResult ActionResult
} }
// CreateImageResult represents the result of an image creation operation
type CreateImageResult struct {
gophercloud.Result
}
// ExtractImageID gets the ID of the newly created server image from the header
func (res CreateImageResult) ExtractImageID() (string, error) {
if res.Err != nil {
return "", res.Err
}
// Get the image id from the header
u, err := url.ParseRequestURI(res.Header.Get("Location"))
if err != nil {
return "", fmt.Errorf("Failed to parse the image id: %s", err.Error())
}
imageId := path.Base(u.Path)
if imageId == "." || imageId == "/" {
return "", fmt.Errorf("Failed to parse the ID of newly created image: %s", u)
}
return imageId, nil
}
// Extract interprets any RescueResult as an AdminPass, if possible. // Extract interprets any RescueResult as an AdminPass, if possible.
func (r RescueResult) Extract() (string, error) { func (r RescueResult) Extract() (string, error) {
if r.Err != nil { if r.Err != nil {
@@ -194,7 +219,6 @@ func ExtractServers(page pagination.Page) ([]Server, error) {
err = decoder.Decode(casted) err = decoder.Decode(casted)
//err := mapstructure.Decode(casted, &response)
return response.Servers, err return response.Servers, err
} }
@@ -272,3 +296,77 @@ func toMapFromString(from reflect.Kind, to reflect.Kind, data interface{}) (inte
} }
return data, nil return data, nil
} }
// Address represents an IP address.
type Address struct {
Version int `mapstructure:"version"`
Address string `mapstructure:"addr"`
}
// AddressPage abstracts the raw results of making a ListAddresses() request against the API.
// As OpenStack extensions may freely alter the response bodies of structures returned
// to the client, you may only safely access the data provided through the ExtractAddresses call.
type AddressPage struct {
pagination.SinglePageBase
}
// IsEmpty returns true if an AddressPage contains no networks.
func (r AddressPage) IsEmpty() (bool, error) {
addresses, err := ExtractAddresses(r)
if err != nil {
return true, err
}
return len(addresses) == 0, nil
}
// ExtractAddresses interprets the results of a single page from a ListAddresses() call,
// producing a map of addresses.
func ExtractAddresses(page pagination.Page) (map[string][]Address, error) {
casted := page.(AddressPage).Body
var response struct {
Addresses map[string][]Address `mapstructure:"addresses"`
}
err := mapstructure.Decode(casted, &response)
if err != nil {
return nil, err
}
return response.Addresses, err
}
// NetworkAddressPage abstracts the raw results of making a ListAddressesByNetwork() request against the API.
// As OpenStack extensions may freely alter the response bodies of structures returned
// to the client, you may only safely access the data provided through the ExtractAddresses call.
type NetworkAddressPage struct {
pagination.SinglePageBase
}
// IsEmpty returns true if a NetworkAddressPage contains no addresses.
func (r NetworkAddressPage) IsEmpty() (bool, error) {
addresses, err := ExtractNetworkAddresses(r)
if err != nil {
return true, err
}
return len(addresses) == 0, nil
}
// ExtractNetworkAddresses interprets the results of a single page from a ListAddressesByNetwork() call,
// producing a slice of addresses.
func ExtractNetworkAddresses(page pagination.Page) ([]Address, error) {
casted := page.(NetworkAddressPage).Body
var response map[string][]Address
err := mapstructure.Decode(casted, &response)
if err != nil {
return nil, err
}
var key string
for k := range response {
key = k
}
return response[key], err
}

View File

@@ -37,3 +37,11 @@ func metadatumURL(client *gophercloud.ServiceClient, id, key string) string {
func metadataURL(client *gophercloud.ServiceClient, id string) string { func metadataURL(client *gophercloud.ServiceClient, id string) string {
return client.ServiceURL("servers", id, "metadata") return client.ServiceURL("servers", id, "metadata")
} }
func listAddressesURL(client *gophercloud.ServiceClient, id string) string {
return client.ServiceURL("servers", id, "ips")
}
func listAddressesByNetworkURL(client *gophercloud.ServiceClient, id, network string) string {
return client.ServiceURL("servers", id, "ips", network)
}

View File

@@ -5,9 +5,7 @@ import (
"github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud"
tokens2 "github.com/rackspace/gophercloud/openstack/identity/v2/tokens" tokens2 "github.com/rackspace/gophercloud/openstack/identity/v2/tokens"
endpoints3 "github.com/rackspace/gophercloud/openstack/identity/v3/endpoints" tokens3 "github.com/rackspace/gophercloud/openstack/identity/v3/tokens"
services3 "github.com/rackspace/gophercloud/openstack/identity/v3/services"
"github.com/rackspace/gophercloud/pagination"
) )
// V2EndpointURL discovers the endpoint URL for a specific service from a ServiceCatalog acquired // V2EndpointURL discovers the endpoint URL for a specific service from a ServiceCatalog acquired
@@ -52,73 +50,42 @@ func V2EndpointURL(catalog *tokens2.ServiceCatalog, opts gophercloud.EndpointOpt
return "", gophercloud.ErrEndpointNotFound return "", gophercloud.ErrEndpointNotFound
} }
// V3EndpointURL discovers the endpoint URL for a specific service using multiple calls against // V3EndpointURL discovers the endpoint URL for a specific service from a Catalog acquired
// an identity v3 service endpoint. The specified EndpointOpts are used to identify a unique, // during the v3 identity service. The specified EndpointOpts are used to identify a unique,
// unambiguous endpoint to return. It's an error both when multiple endpoints match the provided // unambiguous endpoint to return. It's an error both when multiple endpoints match the provided
// criteria and when none do. The minimum that can be specified is a Type, but you will also often // criteria and when none do. The minimum that can be specified is a Type, but you will also often
// need to specify a Name and/or a Region depending on what's available on your OpenStack // need to specify a Name and/or a Region depending on what's available on your OpenStack
// deployment. // deployment.
func V3EndpointURL(v3Client *gophercloud.ServiceClient, opts gophercloud.EndpointOpts) (string, error) { func V3EndpointURL(catalog *tokens3.ServiceCatalog, opts gophercloud.EndpointOpts) (string, error) {
// Discover the service we're interested in. // Extract Endpoints from the catalog entries that match the requested Type, Interface,
var services = make([]services3.Service, 0, 1) // Name if provided, and Region if provided.
servicePager := services3.List(v3Client, services3.ListOpts{ServiceType: opts.Type}) var endpoints = make([]tokens3.Endpoint, 0, 1)
err := servicePager.EachPage(func(page pagination.Page) (bool, error) { for _, entry := range catalog.Entries {
part, err := services3.ExtractServices(page) if (entry.Type == opts.Type) && (opts.Name == "" || entry.Name == opts.Name) {
if err != nil { for _, endpoint := range entry.Endpoints {
return false, err if opts.Availability != gophercloud.AvailabilityAdmin &&
opts.Availability != gophercloud.AvailabilityPublic &&
opts.Availability != gophercloud.AvailabilityInternal {
return "", fmt.Errorf("Unexpected availability in endpoint query: %s", opts.Availability)
} }
if (opts.Availability == gophercloud.Availability(endpoint.Interface)) &&
for _, service := range part { (opts.Region == "" || endpoint.Region == opts.Region) {
if service.Name == opts.Name {
services = append(services, service)
}
}
return true, nil
})
if err != nil {
return "", err
}
if len(services) == 0 {
return "", gophercloud.ErrServiceNotFound
}
if len(services) > 1 {
return "", fmt.Errorf("Discovered %d matching services: %#v", len(services), services)
}
service := services[0]
// Enumerate the endpoints available for this service.
var endpoints []endpoints3.Endpoint
endpointPager := endpoints3.List(v3Client, endpoints3.ListOpts{
Availability: opts.Availability,
ServiceID: service.ID,
})
err = endpointPager.EachPage(func(page pagination.Page) (bool, error) {
part, err := endpoints3.ExtractEndpoints(page)
if err != nil {
return false, err
}
for _, endpoint := range part {
if opts.Region == "" || endpoint.Region == opts.Region {
endpoints = append(endpoints, endpoint) endpoints = append(endpoints, endpoint)
} }
} }
}
return true, nil
})
if err != nil {
return "", err
} }
if len(endpoints) == 0 { // Report an error if the options were ambiguous.
return "", gophercloud.ErrEndpointNotFound
}
if len(endpoints) > 1 { if len(endpoints) > 1 {
return "", fmt.Errorf("Discovered %d matching endpoints: %#v", len(endpoints), endpoints) return "", fmt.Errorf("Discovered %d matching endpoints: %#v", len(endpoints), endpoints)
} }
endpoint := endpoints[0]
// Extract the URL from the matching Endpoint.
for _, endpoint := range endpoints {
return gophercloud.NormalizeURL(endpoint.URL), nil return gophercloud.NormalizeURL(endpoint.URL), nil
}
// Report an error if there were no matching endpoints.
return "", gophercloud.ErrEndpointNotFound
} }

View File

@@ -1,15 +1,13 @@
package openstack package openstack
import ( import (
"fmt"
"net/http"
"strings" "strings"
"testing" "testing"
"github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud"
tokens2 "github.com/rackspace/gophercloud/openstack/identity/v2/tokens" tokens2 "github.com/rackspace/gophercloud/openstack/identity/v2/tokens"
tokens3 "github.com/rackspace/gophercloud/openstack/identity/v3/tokens"
th "github.com/rackspace/gophercloud/testhelper" th "github.com/rackspace/gophercloud/testhelper"
fake "github.com/rackspace/gophercloud/testhelper/client"
) )
// Service catalog fixtures take too much vertical space! // Service catalog fixtures take too much vertical space!
@@ -107,119 +105,124 @@ func TestV2EndpointBadAvailability(t *testing.T) {
Region: "same", Region: "same",
Availability: "wat", Availability: "wat",
}) })
th.CheckEquals(t, err.Error(), "Unexpected availability in endpoint query: wat") th.CheckEquals(t, "Unexpected availability in endpoint query: wat", err.Error())
} }
func setupV3Responses(t *testing.T) { var catalog3 = tokens3.ServiceCatalog{
// Mock the service query. Entries: []tokens3.CatalogEntry{
th.Mux.HandleFunc("/services", func(w http.ResponseWriter, r *http.Request) { tokens3.CatalogEntry{
th.TestMethod(t, r, "GET") Type: "same",
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) Name: "same",
Endpoints: []tokens3.Endpoint{
w.Header().Add("Content-Type", "application/json") tokens3.Endpoint{
fmt.Fprintf(w, ` ID: "1",
{ Region: "same",
"links": { Interface: "public",
"next": null, URL: "https://public.correct.com/",
"previous": null },
tokens3.Endpoint{
ID: "2",
Region: "same",
Interface: "admin",
URL: "https://admin.correct.com/",
},
tokens3.Endpoint{
ID: "3",
Region: "same",
Interface: "internal",
URL: "https://internal.correct.com/",
},
tokens3.Endpoint{
ID: "4",
Region: "different",
Interface: "public",
URL: "https://badregion.com/",
},
},
},
tokens3.CatalogEntry{
Type: "same",
Name: "different",
Endpoints: []tokens3.Endpoint{
tokens3.Endpoint{
ID: "5",
Region: "same",
Interface: "public",
URL: "https://badname.com/",
},
tokens3.Endpoint{
ID: "6",
Region: "different",
Interface: "public",
URL: "https://badname.com/+badregion",
},
},
},
tokens3.CatalogEntry{
Type: "different",
Name: "different",
Endpoints: []tokens3.Endpoint{
tokens3.Endpoint{
ID: "7",
Region: "same",
Interface: "public",
URL: "https://badtype.com/+badname",
},
tokens3.Endpoint{
ID: "8",
Region: "different",
Interface: "public",
URL: "https://badtype.com/+badregion+badname",
},
}, },
"services": [
{
"description": "Correct",
"id": "1234",
"name": "same",
"type": "same"
}, },
{
"description": "Bad Name",
"id": "9876",
"name": "different",
"type": "same"
}
]
}
`)
})
// Mock the endpoint query.
th.Mux.HandleFunc("/endpoints", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "GET")
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
th.TestFormValues(t, r, map[string]string{
"service_id": "1234",
"interface": "public",
})
w.Header().Add("Content-Type", "application/json")
fmt.Fprintf(w, `
{
"endpoints": [
{
"id": "12",
"interface": "public",
"name": "the-right-one",
"region": "same",
"service_id": "1234",
"url": "https://correct:9000/"
}, },
{
"id": "14",
"interface": "public",
"name": "bad-region",
"region": "different",
"service_id": "1234",
"url": "https://bad-region:9001/"
}
],
"links": {
"next": null,
"previous": null
}
}
`)
})
} }
func TestV3EndpointExact(t *testing.T) { func TestV3EndpointExact(t *testing.T) {
th.SetupHTTP() expectedURLs := map[gophercloud.Availability]string{
defer th.TeardownHTTP() gophercloud.AvailabilityPublic: "https://public.correct.com/",
setupV3Responses(t) gophercloud.AvailabilityAdmin: "https://admin.correct.com/",
gophercloud.AvailabilityInternal: "https://internal.correct.com/",
}
actual, err := V3EndpointURL(fake.ServiceClient(), gophercloud.EndpointOpts{ for availability, expected := range expectedURLs {
actual, err := V3EndpointURL(&catalog3, gophercloud.EndpointOpts{
Type: "same", Type: "same",
Name: "same", Name: "same",
Region: "same", Region: "same",
Availability: gophercloud.AvailabilityPublic, Availability: availability,
}) })
th.AssertNoErr(t, err) th.AssertNoErr(t, err)
th.CheckEquals(t, actual, "https://correct:9000/") th.CheckEquals(t, expected, actual)
}
} }
func TestV3EndpointNoService(t *testing.T) { func TestV3EndpointNone(t *testing.T) {
th.SetupHTTP() _, err := V3EndpointURL(&catalog3, gophercloud.EndpointOpts{
defer th.TeardownHTTP()
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().Add("Content-Type", "application/json")
fmt.Fprintf(w, `
{
"links": {
"next": null,
"previous": null
},
"services": []
}
`)
})
_, err := V3EndpointURL(fake.ServiceClient(), gophercloud.EndpointOpts{
Type: "nope", Type: "nope",
Name: "same", Availability: gophercloud.AvailabilityPublic,
})
th.CheckEquals(t, gophercloud.ErrEndpointNotFound, err)
}
func TestV3EndpointMultiple(t *testing.T) {
_, err := V3EndpointURL(&catalog3, gophercloud.EndpointOpts{
Type: "same",
Region: "same", Region: "same",
Availability: gophercloud.AvailabilityPublic, Availability: gophercloud.AvailabilityPublic,
}) })
th.CheckEquals(t, gophercloud.ErrServiceNotFound, err) if !strings.HasPrefix(err.Error(), "Discovered 2 matching endpoints:") {
t.Errorf("Received unexpected error: %v", err)
}
}
func TestV3EndpointBadAvailability(t *testing.T) {
_, err := V3EndpointURL(&catalog3, gophercloud.EndpointOpts{
Type: "same",
Name: "same",
Region: "same",
Availability: "wat",
})
th.CheckEquals(t, "Unexpected availability in endpoint query: wat", err.Error())
} }

View File

@@ -19,11 +19,7 @@ func List(client *gophercloud.ServiceClient) pagination.Pager {
// ID is a required argument. // ID is a required argument.
func AddUserRole(client *gophercloud.ServiceClient, tenantID, userID, roleID string) UserRoleResult { func AddUserRole(client *gophercloud.ServiceClient, tenantID, userID, roleID string) UserRoleResult {
var result UserRoleResult var result UserRoleResult
_, result.Err = client.Put(userRoleURL(client, tenantID, userID, roleID), nil, nil, nil)
_, result.Err = client.Request("PUT", userRoleURL(client, tenantID, userID, roleID), gophercloud.RequestOpts{
OkCodes: []int{200, 201},
})
return result return result
} }
@@ -32,10 +28,6 @@ func AddUserRole(client *gophercloud.ServiceClient, tenantID, userID, roleID str
// tenant ID is a required argument. // tenant ID is a required argument.
func DeleteUserRole(client *gophercloud.ServiceClient, tenantID, userID, roleID string) UserRoleResult { func DeleteUserRole(client *gophercloud.ServiceClient, tenantID, userID, roleID string) UserRoleResult {
var result UserRoleResult var result UserRoleResult
_, result.Err = client.Delete(userRoleURL(client, tenantID, userID, roleID), nil)
_, result.Err = client.Request("DELETE", userRoleURL(client, tenantID, userID, roleID), gophercloud.RequestOpts{
OkCodes: []int{204},
})
return result return result
} }

View File

@@ -75,9 +75,7 @@ func Create(client *gophercloud.ServiceClient, auth AuthOptionsBuilder) CreateRe
} }
var result CreateResult var result CreateResult
_, result.Err = client.Request("POST", CreateURL(client), gophercloud.RequestOpts{ _, result.Err = client.Post(CreateURL(client), request, &result.Body, &gophercloud.RequestOpts{
JSONBody: &request,
JSONResponse: &result.Body,
OkCodes: []int{200, 203}, OkCodes: []int{200, 203},
}) })
return result return result

View File

@@ -90,9 +90,7 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
return res return res
} }
_, res.Err = client.Request("POST", rootURL(client), gophercloud.RequestOpts{ _, res.Err = client.Post(rootURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONResponse: &res.Body,
JSONBody: reqBody,
OkCodes: []int{200, 201}, OkCodes: []int{200, 201},
}) })
@@ -102,12 +100,7 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
// Get requests details on a single user, either by ID. // Get requests details on a single user, either by ID.
func Get(client *gophercloud.ServiceClient, id string) GetResult { func Get(client *gophercloud.ServiceClient, id string) GetResult {
var result GetResult var result GetResult
_, result.Err = client.Get(ResourceURL(client, id), &result.Body, nil)
_, result.Err = client.Request("GET", ResourceURL(client, id), gophercloud.RequestOpts{
JSONResponse: &result.Body,
OkCodes: []int{200},
})
return result return result
} }
@@ -145,24 +138,17 @@ func (opts UpdateOpts) ToUserUpdateMap() map[string]interface{} {
// Update is the operation responsible for updating exist users by their UUID. // Update is the operation responsible for updating exist users by their UUID.
func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult { func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
var result UpdateResult var result UpdateResult
reqBody := opts.ToUserUpdateMap()
_, result.Err = client.Request("PUT", ResourceURL(client, id), gophercloud.RequestOpts{ _, result.Err = client.Put(ResourceURL(client, id), reqBody, &result.Body, &gophercloud.RequestOpts{
JSONResponse: &result.Body,
JSONBody: opts.ToUserUpdateMap(),
OkCodes: []int{200}, OkCodes: []int{200},
}) })
return result return result
} }
// Delete is the operation responsible for permanently deleting an API user. // Delete is the operation responsible for permanently deleting an API user.
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult { func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
var result DeleteResult var result DeleteResult
_, result.Err = client.Delete(ResourceURL(client, id), nil)
_, result.Err = client.Request("DELETE", ResourceURL(client, id), gophercloud.RequestOpts{
OkCodes: []int{204},
})
return result return result
} }

View File

@@ -56,11 +56,7 @@ func Create(client *gophercloud.ServiceClient, opts EndpointOpts) CreateResult {
reqBody.Endpoint.Region = gophercloud.MaybeString(opts.Region) reqBody.Endpoint.Region = gophercloud.MaybeString(opts.Region)
var result CreateResult var result CreateResult
_, result.Err = client.Request("POST", listURL(client), gophercloud.RequestOpts{ _, result.Err = client.Post(listURL(client), reqBody, &result.Body, nil)
JSONBody: &reqBody,
JSONResponse: &result.Body,
OkCodes: []int{201},
})
return result return result
} }
@@ -122,8 +118,6 @@ func Update(client *gophercloud.ServiceClient, endpointID string, opts EndpointO
// Delete removes an endpoint from the service catalog. // Delete removes an endpoint from the service catalog.
func Delete(client *gophercloud.ServiceClient, endpointID string) DeleteResult { func Delete(client *gophercloud.ServiceClient, endpointID string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = client.Request("DELETE", endpointURL(client, endpointID), gophercloud.RequestOpts{ _, res.Err = client.Delete(endpointURL(client, endpointID), nil)
OkCodes: []int{204},
})
return res return res
} }

View File

@@ -18,11 +18,7 @@ func Create(client *gophercloud.ServiceClient, serviceType string) CreateResult
req := request{Type: serviceType} req := request{Type: serviceType}
var result CreateResult var result CreateResult
_, result.Err = client.Request("POST", listURL(client), gophercloud.RequestOpts{ _, result.Err = client.Post(listURL(client), req, &result.Body, nil)
JSONBody: &req,
JSONResponse: &result.Body,
OkCodes: []int{201},
})
return result return result
} }
@@ -51,10 +47,7 @@ func List(client *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
// Get returns additional information about a service, given its ID. // Get returns additional information about a service, given its ID.
func Get(client *gophercloud.ServiceClient, serviceID string) GetResult { func Get(client *gophercloud.ServiceClient, serviceID string) GetResult {
var result GetResult var result GetResult
_, result.Err = client.Request("GET", serviceURL(client, serviceID), gophercloud.RequestOpts{ _, result.Err = client.Get(serviceURL(client, serviceID), &result.Body, nil)
JSONResponse: &result.Body,
OkCodes: []int{200},
})
return result return result
} }
@@ -79,8 +72,6 @@ func Update(client *gophercloud.ServiceClient, serviceID string, serviceType str
// It either deletes all associated endpoints, or fails until all endpoints are deleted. // It either deletes all associated endpoints, or fails until all endpoints are deleted.
func Delete(client *gophercloud.ServiceClient, serviceID string) DeleteResult { func Delete(client *gophercloud.ServiceClient, serviceID string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = client.Request("DELETE", serviceURL(client, serviceID), gophercloud.RequestOpts{ _, res.Err = client.Delete(serviceURL(client, serviceID), nil)
OkCodes: []int{204},
})
return res return res
} }

View File

@@ -235,11 +235,7 @@ func Create(c *gophercloud.ServiceClient, options gophercloud.AuthOptions, scope
var result CreateResult var result CreateResult
var response *http.Response var response *http.Response
response, result.Err = c.Request("POST", tokenURL(c), gophercloud.RequestOpts{ response, result.Err = c.Post(tokenURL(c), req, &result.Body, nil)
JSONBody: &req,
JSONResponse: &result.Body,
OkCodes: []int{201},
})
if result.Err != nil { if result.Err != nil {
return result return result
} }
@@ -251,9 +247,8 @@ func Create(c *gophercloud.ServiceClient, options gophercloud.AuthOptions, scope
func Get(c *gophercloud.ServiceClient, token string) GetResult { func Get(c *gophercloud.ServiceClient, token string) GetResult {
var result GetResult var result GetResult
var response *http.Response var response *http.Response
response, result.Err = c.Request("GET", tokenURL(c), gophercloud.RequestOpts{ response, result.Err = c.Get(tokenURL(c), &result.Body, &gophercloud.RequestOpts{
MoreHeaders: subjectTokenHeaders(c, token), MoreHeaders: subjectTokenHeaders(c, token),
JSONResponse: &result.Body,
OkCodes: []int{200, 203}, OkCodes: []int{200, 203},
}) })
if result.Err != nil { if result.Err != nil {
@@ -279,9 +274,8 @@ func Validate(c *gophercloud.ServiceClient, token string) (bool, error) {
// Revoke immediately makes specified token invalid. // Revoke immediately makes specified token invalid.
func Revoke(c *gophercloud.ServiceClient, token string) RevokeResult { func Revoke(c *gophercloud.ServiceClient, token string) RevokeResult {
var res RevokeResult var res RevokeResult
_, res.Err = c.Request("DELETE", tokenURL(c), gophercloud.RequestOpts{ _, res.Err = c.Delete(tokenURL(c), &gophercloud.RequestOpts{
MoreHeaders: subjectTokenHeaders(c, token), MoreHeaders: subjectTokenHeaders(c, token),
OkCodes: []int{204},
}) })
return res return res
} }

View File

@@ -7,13 +7,58 @@ import (
"github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud"
) )
// Endpoint represents a single API endpoint offered by a service.
// It matches either a public, internal or admin URL.
// If supported, it contains a region specifier, again if provided.
// The significance of the Region field will depend upon your provider.
type Endpoint struct {
ID string `mapstructure:"id"`
Region string `mapstructure:"region"`
Interface string `mapstructure:"interface"`
URL string `mapstructure:"url"`
}
// CatalogEntry provides a type-safe interface to an Identity API V3 service catalog listing.
// Each class of service, such as cloud DNS or block storage services, could have multiple
// CatalogEntry representing it (one by interface type, e.g public, admin or internal).
//
// Note: when looking for the desired service, try, whenever possible, to key off the type field.
// Otherwise, you'll tie the representation of the service to a specific provider.
type CatalogEntry struct {
// Service ID
ID string `mapstructure:"id"`
// Name will contain the provider-specified name for the service.
Name string `mapstructure:"name"`
// Type will contain a type string if OpenStack defines a type for the service.
// Otherwise, for provider-specific services, the provider may assign their own type strings.
Type string `mapstructure:"type"`
// Endpoints will let the caller iterate over all the different endpoints that may exist for
// the service.
Endpoints []Endpoint `mapstructure:"endpoints"`
}
// ServiceCatalog provides a view into the service catalog from a previous, successful authentication.
type ServiceCatalog struct {
Entries []CatalogEntry
}
// commonResult is the deferred result of a Create or a Get call. // commonResult is the deferred result of a Create or a Get call.
type commonResult struct { type commonResult struct {
gophercloud.Result gophercloud.Result
} }
// Extract interprets a commonResult as a Token. // Extract is a shortcut for ExtractToken.
// This function is deprecated and still present for backward compatibility.
func (r commonResult) Extract() (*Token, error) { func (r commonResult) Extract() (*Token, error) {
return r.ExtractToken()
}
// ExtractToken interprets a commonResult as a Token.
func (r commonResult) ExtractToken() (*Token, error) {
if r.Err != nil { if r.Err != nil {
return nil, r.Err return nil, r.Err
} }
@@ -40,7 +85,28 @@ func (r commonResult) Extract() (*Token, error) {
return &token, err return &token, err
} }
// CreateResult is the deferred response from a Create call. // ExtractServiceCatalog returns the ServiceCatalog that was generated along with the user's Token.
func (result CreateResult) ExtractServiceCatalog() (*ServiceCatalog, error) {
if result.Err != nil {
return nil, result.Err
}
var response struct {
Token struct {
Entries []CatalogEntry `mapstructure:"catalog"`
} `mapstructure:"token"`
}
err := mapstructure.Decode(result.Body, &response)
if err != nil {
return nil, err
}
return &ServiceCatalog{Entries: response.Token.Entries}, nil
}
// CreateResult defers the interpretation of a created token.
// Use ExtractToken() to interpret it as a Token, or ExtractServiceCatalog() to interpret it as a service catalog.
type CreateResult struct { type CreateResult struct {
commonResult commonResult
} }

View File

@@ -1,6 +1,10 @@
package external package external
import "github.com/rackspace/gophercloud/openstack/networking/v2/networks" import (
"time"
"github.com/rackspace/gophercloud/openstack/networking/v2/networks"
)
// AdminState gives users a solid type to work with for create and update // AdminState gives users a solid type to work with for create and update
// operations. It is recommended that users use the `Up` and `Down` enums. // operations. It is recommended that users use the `Up` and `Down` enums.
@@ -25,6 +29,15 @@ type CreateOpts struct {
// ToNetworkCreateMap casts a CreateOpts struct to a map. // ToNetworkCreateMap casts a CreateOpts struct to a map.
func (o CreateOpts) ToNetworkCreateMap() (map[string]interface{}, error) { func (o CreateOpts) ToNetworkCreateMap() (map[string]interface{}, error) {
// DO NOT REMOVE. Though this line seemingly does nothing of value, it is a
// splint to prevent the unit test from failing on Go Tip. We suspect it is a
// compiler issue that will hopefully be worked out prior to our next release.
// Again, for all the unit tests to pass, this line is necessary and sufficient
// at the moment. We should reassess after the Go 1.5 release to determine
// if this line is still needed.
time.Sleep(0 * time.Millisecond)
outer, err := o.Parent.ToNetworkCreateMap() outer, err := o.Parent.ToNetworkCreateMap()
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -68,7 +68,7 @@ func ExtractUpdate(r networks.UpdateResult) (*NetworkExternal, error) {
} }
// ExtractList accepts a Page struct, specifically a NetworkPage struct, and // ExtractList accepts a Page struct, specifically a NetworkPage struct, and
// extracts the elements into a slice of NetworkExtAttrs structs. In other // extracts the elements into a slice of NetworkExternal structs. In other
// words, a generic collection is mapped into a relevant slice. // words, a generic collection is mapped into a relevant slice.
func ExtractList(page pagination.Page) ([]NetworkExternal, error) { func ExtractList(page pagination.Page) ([]NetworkExternal, error) {
var resp struct { var resp struct {

View File

@@ -139,21 +139,14 @@ func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
return res return res
} }
_, res.Err = c.Request("POST", rootURL(c), gophercloud.RequestOpts{ _, res.Err = c.Post(rootURL(c), reqBody, &res.Body, nil)
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{201},
})
return res return res
} }
// Get retrieves a particular firewall based on its unique ID. // Get retrieves a particular firewall based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) GetResult { func Get(c *gophercloud.ServiceClient, id string) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Get(resourceURL(c, id), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
@@ -209,9 +202,7 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) Upd
} }
// Send request to API // Send request to API
_, res.Err = c.Request("PUT", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Put(resourceURL(c, id), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
return res return res
@@ -220,8 +211,6 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) Upd
// Delete will permanently delete a particular firewall based on its unique ID. // Delete will permanently delete a particular firewall based on its unique ID.
func Delete(c *gophercloud.ServiceClient, id string) DeleteResult { func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = c.Request("DELETE", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Delete(resourceURL(c, id), nil)
OkCodes: []int{204},
})
return res return res
} }

View File

@@ -128,21 +128,14 @@ func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
return res return res
} }
_, res.Err = c.Request("POST", rootURL(c), gophercloud.RequestOpts{ _, res.Err = c.Post(rootURL(c), reqBody, &res.Body, nil)
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{201},
})
return res return res
} }
// Get retrieves a particular firewall policy based on its unique ID. // Get retrieves a particular firewall policy based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) GetResult { func Get(c *gophercloud.ServiceClient, id string) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Get(resourceURL(c, id), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
@@ -198,9 +191,7 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) Upd
} }
// Send request to API // Send request to API
_, res.Err = c.Request("PUT", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Put(resourceURL(c, id), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
return res return res
@@ -209,9 +200,7 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) Upd
// Delete will permanently delete a particular firewall policy based on its unique ID. // Delete will permanently delete a particular firewall policy based on its unique ID.
func Delete(c *gophercloud.ServiceClient, id string) DeleteResult { func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = c.Request("DELETE", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Delete(resourceURL(c, id), nil)
OkCodes: []int{204},
})
return res return res
} }
@@ -230,9 +219,7 @@ func InsertRule(c *gophercloud.ServiceClient, policyID, ruleID, beforeID, afterI
// Send request to API // Send request to API
var res commonResult var res commonResult
_, res.Err = c.Request("PUT", insertURL(c, policyID), gophercloud.RequestOpts{ _, res.Err = c.Put(insertURL(c, policyID), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
return res.Err return res.Err
@@ -249,9 +236,7 @@ func RemoveRule(c *gophercloud.ServiceClient, policyID, ruleID string) error {
// Send request to API // Send request to API
var res commonResult var res commonResult
_, res.Err = c.Request("PUT", removeURL(c, policyID), gophercloud.RequestOpts{ _, res.Err = c.Put(removeURL(c, policyID), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
return res.Err return res.Err

View File

@@ -163,21 +163,14 @@ func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
return res return res
} }
_, res.Err = c.Request("POST", rootURL(c), gophercloud.RequestOpts{ _, res.Err = c.Post(rootURL(c), reqBody, &res.Body, nil)
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{201},
})
return res return res
} }
// Get retrieves a particular firewall rule based on its unique ID. // Get retrieves a particular firewall rule based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) GetResult { func Get(c *gophercloud.ServiceClient, id string) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Get(resourceURL(c, id), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
@@ -277,9 +270,7 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) Upd
} }
// Send request to API // Send request to API
_, res.Err = c.Request("PUT", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Put(resourceURL(c, id), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
@@ -289,8 +280,6 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) Upd
// Delete will permanently delete a particular firewall rule based on its unique ID. // Delete will permanently delete a particular firewall rule based on its unique ID.
func Delete(c *gophercloud.ServiceClient, id string) DeleteResult { func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = c.Request("DELETE", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Delete(resourceURL(c, id), nil)
OkCodes: []int{204},
})
return res return res
} }

View File

@@ -107,23 +107,14 @@ func Create(c *gophercloud.ServiceClient, opts CreateOpts) CreateResult {
TenantID: opts.TenantID, TenantID: opts.TenantID,
}} }}
// Send request to API _, res.Err = c.Post(rootURL(c), reqBody, &res.Body, nil)
_, res.Err = c.Request("POST", rootURL(c), gophercloud.RequestOpts{
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{201},
})
return res return res
} }
// Get retrieves a particular floating IP resource based on its unique ID. // Get retrieves a particular floating IP resource based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) GetResult { func Get(c *gophercloud.ServiceClient, id string) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Get(resourceURL(c, id), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
@@ -159,9 +150,7 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResu
// Send request to API // Send request to API
var res UpdateResult var res UpdateResult
_, res.Err = c.Request("PUT", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Put(resourceURL(c, id), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
@@ -173,8 +162,6 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResu
// internal ports. // internal ports.
func Delete(c *gophercloud.ServiceClient, id string) DeleteResult { func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = c.Request("DELETE", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Delete(resourceURL(c, id), nil)
OkCodes: []int{204},
})
return res return res
} }

View File

@@ -81,21 +81,14 @@ func Create(c *gophercloud.ServiceClient, opts CreateOpts) CreateResult {
} }
var res CreateResult var res CreateResult
_, res.Err = c.Request("POST", rootURL(c), gophercloud.RequestOpts{ _, res.Err = c.Post(rootURL(c), reqBody, &res.Body, nil)
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{201},
})
return res return res
} }
// Get retrieves a particular router based on its unique ID. // Get retrieves a particular router based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) GetResult { func Get(c *gophercloud.ServiceClient, id string) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Get(resourceURL(c, id), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
@@ -133,9 +126,7 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResu
// Send request to API // Send request to API
var res UpdateResult var res UpdateResult
_, res.Err = c.Request("PUT", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Put(resourceURL(c, id), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
@@ -145,9 +136,7 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResu
// Delete will permanently delete a particular router based on its unique ID. // Delete will permanently delete a particular router based on its unique ID.
func Delete(c *gophercloud.ServiceClient, id string) DeleteResult { func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = c.Request("DELETE", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Delete(resourceURL(c, id), nil)
OkCodes: []int{204},
})
return res return res
} }
@@ -197,9 +186,7 @@ func AddInterface(c *gophercloud.ServiceClient, id string, opts InterfaceOpts) I
body := request{SubnetID: opts.SubnetID, PortID: opts.PortID} body := request{SubnetID: opts.SubnetID, PortID: opts.PortID}
_, res.Err = c.Request("PUT", addInterfaceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Put(addInterfaceURL(c, id), body, &res.Body, &gophercloud.RequestOpts{
JSONBody: &body,
JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
@@ -229,9 +216,7 @@ func RemoveInterface(c *gophercloud.ServiceClient, id string, opts InterfaceOpts
body := request{SubnetID: opts.SubnetID, PortID: opts.PortID} body := request{SubnetID: opts.SubnetID, PortID: opts.PortID}
_, res.Err = c.Request("PUT", removeInterfaceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Put(removeInterfaceURL(c, id), body, &res.Body, &gophercloud.RequestOpts{
JSONBody: &body,
JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })

View File

@@ -79,21 +79,14 @@ func Create(c *gophercloud.ServiceClient, opts CreateOpts) CreateResult {
}} }}
var res CreateResult var res CreateResult
_, res.Err = c.Request("POST", rootURL(c), gophercloud.RequestOpts{ _, res.Err = c.Post(rootURL(c), reqBody, &res.Body, nil)
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{201},
})
return res return res
} }
// Get retrieves a particular pool member based on its unique ID. // Get retrieves a particular pool member based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) GetResult { func Get(c *gophercloud.ServiceClient, id string) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Get(resourceURL(c, id), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
@@ -116,10 +109,8 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResu
// Send request to API // Send request to API
var res UpdateResult var res UpdateResult
_, res.Err = c.Request("PUT", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Put(resourceURL(c, id), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: &reqBody, OkCodes: []int{200, 201, 202},
JSONResponse: &res.Body,
OkCodes: []int{200},
}) })
return res return res
} }
@@ -127,8 +118,6 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResu
// Delete will permanently delete a particular member based on its unique ID. // Delete will permanently delete a particular member based on its unique ID.
func Delete(c *gophercloud.ServiceClient, id string) DeleteResult { func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = c.Request("DELETE", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Delete(resourceURL(c, id), nil)
OkCodes: []int{204},
})
return res return res
} }

View File

@@ -176,22 +176,14 @@ func Create(c *gophercloud.ServiceClient, opts CreateOpts) CreateResult {
AdminStateUp: opts.AdminStateUp, AdminStateUp: opts.AdminStateUp,
}} }}
_, res.Err = c.Request("POST", rootURL(c), gophercloud.RequestOpts{ _, res.Err = c.Post(rootURL(c), reqBody, &res.Body, nil)
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{201},
})
return res return res
} }
// Get retrieves a particular health monitor based on its unique ID. // Get retrieves a particular health monitor based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) GetResult { func Get(c *gophercloud.ServiceClient, id string) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Get(resourceURL(c, id), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
@@ -258,9 +250,7 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResu
AdminStateUp: opts.AdminStateUp, AdminStateUp: opts.AdminStateUp,
}} }}
_, res.Err = c.Request("PUT", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Put(resourceURL(c, id), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{200, 202}, OkCodes: []int{200, 202},
}) })
@@ -270,8 +260,6 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResu
// Delete will permanently delete a particular monitor based on its unique ID. // Delete will permanently delete a particular monitor based on its unique ID.
func Delete(c *gophercloud.ServiceClient, id string) DeleteResult { func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = c.Request("DELETE", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Delete(resourceURL(c, id), nil)
OkCodes: []int{204},
})
return res return res
} }

View File

@@ -99,21 +99,14 @@ func Create(c *gophercloud.ServiceClient, opts CreateOpts) CreateResult {
}} }}
var res CreateResult var res CreateResult
_, res.Err = c.Request("POST", rootURL(c), gophercloud.RequestOpts{ _, res.Err = c.Post(rootURL(c), reqBody, &res.Body, nil)
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{201},
})
return res return res
} }
// Get retrieves a particular pool based on its unique ID. // Get retrieves a particular pool based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) GetResult { func Get(c *gophercloud.ServiceClient, id string) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Get(resourceURL(c, id), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
@@ -145,9 +138,7 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResu
// Send request to API // Send request to API
var res UpdateResult var res UpdateResult
_, res.Err = c.Request("PUT", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Put(resourceURL(c, id), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
return res return res
@@ -156,9 +147,7 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResu
// Delete will permanently delete a particular pool based on its unique ID. // Delete will permanently delete a particular pool based on its unique ID.
func Delete(c *gophercloud.ServiceClient, id string) DeleteResult { func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = c.Request("DELETE", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Delete(resourceURL(c, id), nil)
OkCodes: []int{204},
})
return res return res
} }
@@ -178,11 +167,7 @@ func AssociateMonitor(c *gophercloud.ServiceClient, poolID, monitorID string) As
reqBody := request{hm{ID: monitorID}} reqBody := request{hm{ID: monitorID}}
var res AssociateResult var res AssociateResult
_, res.Err = c.Request("POST", associateURL(c, poolID), gophercloud.RequestOpts{ _, res.Err = c.Post(associateURL(c, poolID), reqBody, &res.Body, nil)
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{201},
})
return res return res
} }
@@ -191,8 +176,6 @@ func AssociateMonitor(c *gophercloud.ServiceClient, poolID, monitorID string) As
// check for the health of the members of the pool. // check for the health of the members of the pool.
func DisassociateMonitor(c *gophercloud.ServiceClient, poolID, monitorID string) AssociateResult { func DisassociateMonitor(c *gophercloud.ServiceClient, poolID, monitorID string) AssociateResult {
var res AssociateResult var res AssociateResult
_, res.Err = c.Request("DELETE", disassociateURL(c, poolID, monitorID), gophercloud.RequestOpts{ _, res.Err = c.Delete(disassociateURL(c, poolID, monitorID), nil)
OkCodes: []int{204},
})
return res return res
} }

View File

@@ -178,22 +178,14 @@ func Create(c *gophercloud.ServiceClient, opts CreateOpts) CreateResult {
reqBody.VirtualIP.Persistence = opts.Persistence reqBody.VirtualIP.Persistence = opts.Persistence
} }
_, res.Err = c.Request("POST", rootURL(c), gophercloud.RequestOpts{ _, res.Err = c.Post(rootURL(c), reqBody, &res.Body, nil)
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{201},
})
return res return res
} }
// Get retrieves a particular virtual IP based on its unique ID. // Get retrieves a particular virtual IP based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) GetResult { func Get(c *gophercloud.ServiceClient, id string) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Get(resourceURL(c, id), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
@@ -249,9 +241,7 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResu
} }
var res UpdateResult var res UpdateResult
_, res.Err = c.Request("PUT", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Put(resourceURL(c, id), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{200, 202}, OkCodes: []int{200, 202},
}) })
@@ -261,8 +251,6 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResu
// Delete will permanently delete a particular virtual IP based on its unique ID. // Delete will permanently delete a particular virtual IP based on its unique ID.
func Delete(c *gophercloud.ServiceClient, id string) DeleteResult { func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = c.Request("DELETE", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Delete(resourceURL(c, id), nil)
OkCodes: []int{204},
})
return res return res
} }

View File

@@ -73,7 +73,7 @@ func ExtractGet(r networks.GetResult) (*NetworkExtAttrs, error) {
Network *NetworkExtAttrs `json:"network"` Network *NetworkExtAttrs `json:"network"`
} }
err := mapstructure.Decode(r.Body, &res) err := mapstructure.WeakDecode(r.Body, &res)
return res.Network, err return res.Network, err
} }
@@ -89,7 +89,7 @@ func ExtractCreate(r networks.CreateResult) (*NetworkExtAttrs, error) {
Network *NetworkExtAttrs `json:"network"` Network *NetworkExtAttrs `json:"network"`
} }
err := mapstructure.Decode(r.Body, &res) err := mapstructure.WeakDecode(r.Body, &res)
return res.Network, err return res.Network, err
} }
@@ -105,7 +105,7 @@ func ExtractUpdate(r networks.UpdateResult) (*NetworkExtAttrs, error) {
Network *NetworkExtAttrs `json:"network"` Network *NetworkExtAttrs `json:"network"`
} }
err := mapstructure.Decode(r.Body, &res) err := mapstructure.WeakDecode(r.Body, &res)
return res.Network, err return res.Network, err
} }
@@ -118,7 +118,7 @@ func ExtractList(page pagination.Page) ([]NetworkExtAttrs, error) {
Networks []NetworkExtAttrs `mapstructure:"networks" json:"networks"` Networks []NetworkExtAttrs `mapstructure:"networks" json:"networks"`
} }
err := mapstructure.Decode(page.(networks.NetworkPage).Body, &resp) err := mapstructure.WeakDecode(page.(networks.NetworkPage).Body, &resp)
return resp.Networks, err return resp.Networks, err
} }

View File

@@ -49,7 +49,7 @@ func TestList(t *testing.T) {
"tenant_id": "26a7980765d0414dbc1fc1f88cdb7e6e", "tenant_id": "26a7980765d0414dbc1fc1f88cdb7e6e",
"shared": true, "shared": true,
"id": "db193ab3-96e3-4cb3-8fc5-05f4296d0324", "id": "db193ab3-96e3-4cb3-8fc5-05f4296d0324",
"provider:segmentation_id": null, "provider:segmentation_id": 1234567890,
"provider:physical_network": null, "provider:physical_network": null,
"provider:network_type": "local" "provider:network_type": "local"
} }
@@ -91,7 +91,7 @@ func TestList(t *testing.T) {
ID: "db193ab3-96e3-4cb3-8fc5-05f4296d0324", ID: "db193ab3-96e3-4cb3-8fc5-05f4296d0324",
NetworkType: "local", NetworkType: "local",
PhysicalNetwork: "", PhysicalNetwork: "",
SegmentationID: "", SegmentationID: "1234567890",
}, },
} }

View File

@@ -15,13 +15,13 @@
// //
// For ingress traffic (to an instance) // For ingress traffic (to an instance)
// - Only traffic matched with security group rules are allowed. // - Only traffic matched with security group rules are allowed.
// - When there is no rule defined, all traffic are dropped. // - When there is no rule defined, all traffic is dropped.
// //
// For egress traffic (from an instance) // For egress traffic (from an instance)
// - Only traffic matched with security group rules are allowed. // - Only traffic matched with security group rules are allowed.
// - When there is no rule defined, all egress traffic are dropped. // - When there is no rule defined, all egress traffic are dropped.
// - When a new security group is created, rules to allow all egress traffic // - When a new security group is created, rules to allow all egress traffic
// are automatically added. // is automatically added.
// //
// "default security group" is defined for each tenant. // "default security group" is defined for each tenant.
// - For the default security group a rule which allows intercommunication // - For the default security group a rule which allows intercommunication

View File

@@ -74,30 +74,20 @@ func Create(c *gophercloud.ServiceClient, opts CreateOpts) CreateResult {
Description: opts.Description, Description: opts.Description,
}} }}
_, res.Err = c.Request("POST", rootURL(c), gophercloud.RequestOpts{ _, res.Err = c.Post(rootURL(c), reqBody, &res.Body, nil)
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{201},
})
return res return res
} }
// Get retrieves a particular security group based on its unique ID. // Get retrieves a particular security group based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) GetResult { func Get(c *gophercloud.ServiceClient, id string) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Get(resourceURL(c, id), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
// Delete will permanently delete a particular security group based on its unique ID. // Delete will permanently delete a particular security group based on its unique ID.
func Delete(c *gophercloud.ServiceClient, id string) DeleteResult { func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = c.Request("DELETE", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Delete(resourceURL(c, id), nil)
OkCodes: []int{204},
})
return res return res
} }

View File

@@ -150,30 +150,20 @@ func Create(c *gophercloud.ServiceClient, opts CreateOpts) CreateResult {
RemoteIPPrefix: opts.RemoteIPPrefix, RemoteIPPrefix: opts.RemoteIPPrefix,
}} }}
_, res.Err = c.Request("POST", rootURL(c), gophercloud.RequestOpts{ _, res.Err = c.Post(rootURL(c), reqBody, &res.Body, nil)
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{201},
})
return res return res
} }
// Get retrieves a particular security group based on its unique ID. // Get retrieves a particular security group based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) GetResult { func Get(c *gophercloud.ServiceClient, id string) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Get(resourceURL(c, id), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
// Delete will permanently delete a particular security group based on its unique ID. // Delete will permanently delete a particular security group based on its unique ID.
func Delete(c *gophercloud.ServiceClient, id string) DeleteResult { func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = c.Request("DELETE", resourceURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Delete(resourceURL(c, id), nil)
OkCodes: []int{204},
})
return res return res
} }

View File

@@ -79,10 +79,7 @@ func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
// Get retrieves a specific network based on its unique ID. // Get retrieves a specific network based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) GetResult { func Get(c *gophercloud.ServiceClient, id string) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", getURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Get(getURL(c, id), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
@@ -134,12 +131,7 @@ func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
return res return res
} }
// Send request to API _, res.Err = c.Post(createURL(c), reqBody, &res.Body, nil)
_, res.Err = c.Request("POST", createURL(c), gophercloud.RequestOpts{
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{201},
})
return res return res
} }
@@ -184,9 +176,7 @@ func Update(c *gophercloud.ServiceClient, networkID string, opts UpdateOptsBuild
} }
// Send request to API // Send request to API
_, res.Err = c.Request("PUT", updateURL(c, networkID), gophercloud.RequestOpts{ _, res.Err = c.Put(updateURL(c, networkID), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{200, 201}, OkCodes: []int{200, 201},
}) })
@@ -196,8 +186,6 @@ func Update(c *gophercloud.ServiceClient, networkID string, opts UpdateOptsBuild
// Delete accepts a unique ID and deletes the network associated with it. // Delete accepts a unique ID and deletes the network associated with it.
func Delete(c *gophercloud.ServiceClient, networkID string) DeleteResult { func Delete(c *gophercloud.ServiceClient, networkID string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = c.Request("DELETE", deleteURL(c, networkID), gophercloud.RequestOpts{ _, res.Err = c.Delete(deleteURL(c, networkID), nil)
OkCodes: []int{204},
})
return res return res
} }

View File

@@ -79,10 +79,7 @@ func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
// Get retrieves a specific port based on its unique ID. // Get retrieves a specific port based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) GetResult { func Get(c *gophercloud.ServiceClient, id string) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", getURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Get(getURL(c, id), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
@@ -155,13 +152,7 @@ func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
return res return res
} }
// Response _, res.Err = c.Post(createURL(c), reqBody, &res.Body, nil)
_, res.Err = c.Request("POST", createURL(c), gophercloud.RequestOpts{
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{201},
})
return res return res
} }
@@ -220,9 +211,7 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) Upd
return res return res
} }
_, res.Err = c.Request("PUT", updateURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Put(updateURL(c, id), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{200, 201}, OkCodes: []int{200, 201},
}) })
return res return res
@@ -231,8 +220,6 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) Upd
// Delete accepts a unique ID and deletes the port associated with it. // Delete accepts a unique ID and deletes the port associated with it.
func Delete(c *gophercloud.ServiceClient, id string) DeleteResult { func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = c.Request("DELETE", deleteURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Delete(deleteURL(c, id), nil)
OkCodes: []int{204},
})
return res return res
} }

View File

@@ -78,10 +78,7 @@ func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
// Get retrieves a specific subnet based on its unique ID. // Get retrieves a specific subnet based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) GetResult { func Get(c *gophercloud.ServiceClient, id string) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", getURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Get(getURL(c, id), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
@@ -171,12 +168,7 @@ func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
return res return res
} }
_, res.Err = c.Request("POST", createURL(c), gophercloud.RequestOpts{ _, res.Err = c.Post(createURL(c), reqBody, &res.Body, nil)
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{201},
})
return res return res
} }
@@ -229,9 +221,7 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) Upd
return res return res
} }
_, res.Err = c.Request("PUT", updateURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Put(updateURL(c, id), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{200, 201}, OkCodes: []int{200, 201},
}) })
@@ -241,8 +231,6 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) Upd
// Delete accepts a unique ID and deletes the subnet associated with it. // Delete accepts a unique ID and deletes the subnet associated with it.
func Delete(c *gophercloud.ServiceClient, id string) DeleteResult { func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = c.Request("DELETE", deleteURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Delete(deleteURL(c, id), nil)
OkCodes: []int{204},
})
return res return res
} }

View File

@@ -95,7 +95,7 @@ func Update(c *gophercloud.ServiceClient, opts UpdateOptsBuilder) UpdateResult {
resp, err := c.Request("POST", updateURL(c), gophercloud.RequestOpts{ resp, err := c.Request("POST", updateURL(c), gophercloud.RequestOpts{
MoreHeaders: h, MoreHeaders: h,
OkCodes: []int{204}, OkCodes: []int{201, 202, 204},
}) })
res.Header = resp.Header res.Header = resp.Header
res.Err = err res.Err = err

View File

@@ -122,9 +122,7 @@ func Create(c *gophercloud.ServiceClient, containerName string, opts CreateOptsB
// Delete is a function that deletes a container. // Delete is a function that deletes a container.
func Delete(c *gophercloud.ServiceClient, containerName string) DeleteResult { func Delete(c *gophercloud.ServiceClient, containerName string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = c.Request("DELETE", deleteURL(c, containerName), gophercloud.RequestOpts{ _, res.Err = c.Delete(deleteURL(c, containerName), nil)
OkCodes: []int{202, 204},
})
return res return res
} }
@@ -180,7 +178,7 @@ func Update(c *gophercloud.ServiceClient, containerName string, opts UpdateOptsB
resp, err := c.Request("POST", updateURL(c, containerName), gophercloud.RequestOpts{ resp, err := c.Request("POST", updateURL(c, containerName), gophercloud.RequestOpts{
MoreHeaders: h, MoreHeaders: h,
OkCodes: []int{202, 204}, OkCodes: []int{201, 202, 204},
}) })
res.Header = resp.Header res.Header = resp.Header
res.Err = err res.Err = err

View File

@@ -211,7 +211,6 @@ func Create(c *gophercloud.ServiceClient, containerName, objectName string, cont
ropts := gophercloud.RequestOpts{ ropts := gophercloud.RequestOpts{
RawBody: content, RawBody: content,
MoreHeaders: h, MoreHeaders: h,
OkCodes: []int{201, 202},
} }
resp, err := c.Request("PUT", url, ropts) resp, err := c.Request("PUT", url, ropts)
@@ -310,9 +309,7 @@ func Delete(c *gophercloud.ServiceClient, containerName, objectName string, opts
url += query url += query
} }
resp, err := c.Request("DELETE", url, gophercloud.RequestOpts{ resp, err := c.Delete(url, nil)
OkCodes: []int{204},
})
res.Header = resp.Header res.Header = resp.Header
res.Err = err res.Err = err
return res return res
@@ -412,7 +409,6 @@ func Update(c *gophercloud.ServiceClient, containerName, objectName string, opts
url := updateURL(c, containerName, objectName) url := updateURL(c, containerName, objectName)
resp, err := c.Request("POST", url, gophercloud.RequestOpts{ resp, err := c.Request("POST", url, gophercloud.RequestOpts{
MoreHeaders: h, MoreHeaders: h,
OkCodes: []int{202},
}) })
res.Header = resp.Header res.Header = resp.Header
res.Err = err res.Err = err

View File

@@ -5,9 +5,6 @@ import "github.com/rackspace/gophercloud"
// Get retreives data for the given stack template. // Get retreives data for the given stack template.
func Get(c *gophercloud.ServiceClient) GetResult { func Get(c *gophercloud.ServiceClient) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", getURL(c), gophercloud.RequestOpts{ _, res.Err = c.Get(getURL(c), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }

View File

@@ -11,7 +11,6 @@ func Find(c *gophercloud.ServiceClient, stackName string) FindResult {
_, res.Err = c.Request("GET", findURL(c, stackName), gophercloud.RequestOpts{ _, res.Err = c.Request("GET", findURL(c, stackName), gophercloud.RequestOpts{
JSONResponse: &res.Body, JSONResponse: &res.Body,
OkCodes: []int{200},
}) })
return res return res
} }
@@ -197,8 +196,7 @@ func ListResourceEvents(client *gophercloud.ServiceClient, stackName, stackID, r
// Get retreives data for the given stack resource. // Get retreives data for the given stack resource.
func Get(c *gophercloud.ServiceClient, stackName, stackID, resourceName, eventID string) GetResult { func Get(c *gophercloud.ServiceClient, stackName, stackID, resourceName, eventID string) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", getURL(c, stackName, stackID, resourceName, eventID), gophercloud.RequestOpts{ _, res.Err = c.Get(getURL(c, stackName, stackID, resourceName, eventID), &res.Body, &gophercloud.RequestOpts{
JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
return res return res

View File

@@ -1,6 +1,8 @@
package stackevents package stackevents
import ( import (
"fmt"
"reflect"
"time" "time"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
@@ -106,7 +108,15 @@ func ExtractEvents(page pagination.Page) ([]Event, error) {
return nil, err return nil, err
} }
events := casted.(map[string]interface{})["events"].([]interface{}) var events []interface{}
switch casted.(type) {
case map[string]interface{}:
events = casted.(map[string]interface{})["events"].([]interface{})
case map[string][]interface{}:
events = casted.(map[string][]interface{})["events"]
default:
return res.Res, fmt.Errorf("Unknown type: %v", reflect.TypeOf(casted))
}
for i, eventRaw := range events { for i, eventRaw := range events {
event := eventRaw.(map[string]interface{}) event := eventRaw.(map[string]interface{})

View File

@@ -12,7 +12,6 @@ func Find(c *gophercloud.ServiceClient, stackName string) FindResult {
// Send request to API // Send request to API
_, res.Err = c.Request("GET", findURL(c, stackName), gophercloud.RequestOpts{ _, res.Err = c.Request("GET", findURL(c, stackName), gophercloud.RequestOpts{
JSONResponse: &res.Body, JSONResponse: &res.Body,
OkCodes: []int{200},
}) })
return res return res
} }
@@ -71,8 +70,7 @@ func Get(c *gophercloud.ServiceClient, stackName, stackID, resourceName string)
var res GetResult var res GetResult
// Send request to API // Send request to API
_, res.Err = c.Request("GET", getURL(c, stackName, stackID, resourceName), gophercloud.RequestOpts{ _, res.Err = c.Get(getURL(c, stackName, stackID, resourceName), &res.Body, &gophercloud.RequestOpts{
JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
return res return res
@@ -83,8 +81,7 @@ func Metadata(c *gophercloud.ServiceClient, stackName, stackID, resourceName str
var res MetadataResult var res MetadataResult
// Send request to API // Send request to API
_, res.Err = c.Request("GET", metadataURL(c, stackName, stackID, resourceName), gophercloud.RequestOpts{ _, res.Err = c.Get(metadataURL(c, stackName, stackID, resourceName), &res.Body, &gophercloud.RequestOpts{
JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
return res return res
@@ -106,8 +103,7 @@ func Schema(c *gophercloud.ServiceClient, resourceType string) SchemaResult {
var res SchemaResult var res SchemaResult
// Send request to API // Send request to API
_, res.Err = c.Request("GET", schemaURL(c, resourceType), gophercloud.RequestOpts{ _, res.Err = c.Get(schemaURL(c, resourceType), &res.Body, &gophercloud.RequestOpts{
JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
return res return res
@@ -118,8 +114,7 @@ func Template(c *gophercloud.ServiceClient, resourceType string) TemplateResult
var res TemplateResult var res TemplateResult
// Send request to API // Send request to API
_, res.Err = c.Request("GET", templateURL(c, resourceType), gophercloud.RequestOpts{ _, res.Err = c.Get(templateURL(c, resourceType), &res.Body, &gophercloud.RequestOpts{
JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
return res return res

View File

@@ -1,6 +1,8 @@
package stackresources package stackresources
import ( import (
"fmt"
"reflect"
"time" "time"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
@@ -94,7 +96,15 @@ func ExtractResources(page pagination.Page) ([]Resource, error) {
} }
err := mapstructure.Decode(casted, &response) err := mapstructure.Decode(casted, &response)
resources := casted.(map[string]interface{})["resources"].([]interface{}) var resources []interface{}
switch casted.(type) {
case map[string]interface{}:
resources = casted.(map[string]interface{})["resources"].([]interface{})
case map[string][]interface{}:
resources = casted.(map[string][]interface{})["resources"]
default:
return response.Resources, fmt.Errorf("Unknown type: %v", reflect.TypeOf(casted))
}
for i, resourceRaw := range resources { for i, resourceRaw := range resources {
resource := resourceRaw.(map[string]interface{}) resource := resourceRaw.(map[string]interface{})

View File

@@ -111,12 +111,7 @@ func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
return res return res
} }
// Send request to API _, res.Err = c.Post(createURL(c), reqBody, &res.Body, nil)
_, res.Err = c.Request("POST", createURL(c), gophercloud.RequestOpts{
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{201},
})
return res return res
} }
@@ -221,12 +216,7 @@ func Adopt(c *gophercloud.ServiceClient, opts AdoptOptsBuilder) AdoptResult {
return res return res
} }
// Send request to API _, res.Err = c.Post(adoptURL(c), reqBody, &res.Body, nil)
_, res.Err = c.Request("POST", adoptURL(c), gophercloud.RequestOpts{
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{201},
})
return res return res
} }
@@ -302,12 +292,7 @@ func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
// Get retreives a stack based on the stack name and stack ID. // Get retreives a stack based on the stack name and stack ID.
func Get(c *gophercloud.ServiceClient, stackName, stackID string) GetResult { func Get(c *gophercloud.ServiceClient, stackName, stackID string) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Get(getURL(c, stackName, stackID), &res.Body, nil)
// Send request to API
_, res.Err = c.Request("GET", getURL(c, stackName, stackID), gophercloud.RequestOpts{
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
@@ -388,22 +373,14 @@ func Update(c *gophercloud.ServiceClient, stackName, stackID string, opts Update
return res return res
} }
// Send request to API _, res.Err = c.Put(updateURL(c, stackName, stackID), reqBody, nil, nil)
_, res.Err = c.Request("PUT", updateURL(c, stackName, stackID), gophercloud.RequestOpts{
JSONBody: &reqBody,
OkCodes: []int{202},
})
return res return res
} }
// Delete deletes a stack based on the stack name and stack ID. // Delete deletes a stack based on the stack name and stack ID.
func Delete(c *gophercloud.ServiceClient, stackName, stackID string) DeleteResult { func Delete(c *gophercloud.ServiceClient, stackName, stackID string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = c.Delete(deleteURL(c, stackName, stackID), nil)
// Send request to API
_, res.Err = c.Request("DELETE", deleteURL(c, stackName, stackID), gophercloud.RequestOpts{
OkCodes: []int{204},
})
return res return res
} }
@@ -498,9 +475,7 @@ func Preview(c *gophercloud.ServiceClient, opts PreviewOptsBuilder) PreviewResul
} }
// Send request to API // Send request to API
_, res.Err = c.Request("POST", previewURL(c), gophercloud.RequestOpts{ _, res.Err = c.Post(previewURL(c), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
return res return res
@@ -510,9 +485,7 @@ func Preview(c *gophercloud.ServiceClient, opts PreviewOptsBuilder) PreviewResul
// resources intact, and returns data describing the stack and its resources. // resources intact, and returns data describing the stack and its resources.
func Abandon(c *gophercloud.ServiceClient, stackName, stackID string) AbandonResult { func Abandon(c *gophercloud.ServiceClient, stackName, stackID string) AbandonResult {
var res AbandonResult var res AbandonResult
_, res.Err = c.Delete(abandonURL(c, stackName, stackID), &gophercloud.RequestOpts{
// Send request to API
_, res.Err = c.Request("DELETE", abandonURL(c, stackName, stackID), gophercloud.RequestOpts{
JSONResponse: &res.Body, JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })

View File

@@ -2,6 +2,8 @@ package stacks
import ( import (
"encoding/json" "encoding/json"
"fmt"
"reflect"
"time" "time"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
@@ -73,6 +75,8 @@ type ListedStack struct {
// ExtractStacks extracts and returns a slice of ListedStack. It is used while iterating // ExtractStacks extracts and returns a slice of ListedStack. It is used while iterating
// over a stacks.List call. // over a stacks.List call.
func ExtractStacks(page pagination.Page) ([]ListedStack, error) { func ExtractStacks(page pagination.Page) ([]ListedStack, error) {
casted := page.(StackPage).Body
var res struct { var res struct {
Stacks []ListedStack `mapstructure:"stacks"` Stacks []ListedStack `mapstructure:"stacks"`
} }
@@ -82,7 +86,16 @@ func ExtractStacks(page pagination.Page) ([]ListedStack, error) {
return nil, err return nil, err
} }
rawStacks := (((page.(StackPage).Body).(map[string]interface{}))["stacks"]).([]interface{}) var rawStacks []interface{}
switch casted.(type) {
case map[string]interface{}:
rawStacks = casted.(map[string]interface{})["stacks"].([]interface{})
case map[string][]interface{}:
rawStacks = casted.(map[string][]interface{})["stacks"]
default:
return res.Stacks, fmt.Errorf("Unknown type: %v", reflect.TypeOf(casted))
}
for i := range rawStacks { for i := range rawStacks {
thisStack := (rawStacks[i]).(map[string]interface{}) thisStack := (rawStacks[i]).(map[string]interface{})

View File

@@ -11,7 +11,6 @@ func Get(c *gophercloud.ServiceClient, stackName, stackID string) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", getURL(c, stackName, stackID), gophercloud.RequestOpts{ _, res.Err = c.Request("GET", getURL(c, stackName, stackID), gophercloud.RequestOpts{
JSONResponse: &res.Body, JSONResponse: &res.Body,
OkCodes: []int{200},
}) })
return res return res
} }
@@ -52,9 +51,7 @@ func Validate(c *gophercloud.ServiceClient, opts ValidateOptsBuilder) ValidateRe
return res return res
} }
_, res.Err = c.Request("POST", validateURL(c), gophercloud.RequestOpts{ _, res.Err = c.Post(validateURL(c), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: reqBody,
JSONResponse: &res.Body,
OkCodes: []int{200}, OkCodes: []int{200},
}) })
return res return res

View File

@@ -11,7 +11,7 @@ import (
) )
// DefaultUserAgent is the default User-Agent string set in the request header. // DefaultUserAgent is the default User-Agent string set in the request header.
const DefaultUserAgent = "gophercloud/v1.0" const DefaultUserAgent = "gophercloud/1.0.0"
// UserAgent represents a User-Agent header. // UserAgent represents a User-Agent header.
type UserAgent struct { type UserAgent struct {
@@ -196,8 +196,12 @@ func (client *ProviderClient) Request(method, url string, options RequestOpts) (
} }
} }
// Validate the response code, if requested to do so. // Allow default OkCodes if none explicitly set
if options.OkCodes != nil { if options.OkCodes == nil {
options.OkCodes = defaultOkCodes(method)
}
// Validate the HTTP response status.
var ok bool var ok bool
for _, code := range options.OkCodes { for _, code := range options.OkCodes {
if resp.StatusCode == code { if resp.StatusCode == code {
@@ -216,7 +220,6 @@ func (client *ProviderClient) Request(method, url string, options RequestOpts) (
Body: body, Body: body,
} }
} }
}
// Parse the response body as JSON, if requested to do so. // Parse the response body as JSON, if requested to do so.
if options.JSONResponse != nil { if options.JSONResponse != nil {
@@ -226,3 +229,72 @@ func (client *ProviderClient) Request(method, url string, options RequestOpts) (
return resp, nil return resp, nil
} }
func defaultOkCodes(method string) []int {
switch {
case method == "GET":
return []int{200}
case method == "POST":
return []int{201, 202}
case method == "PUT":
return []int{201, 202}
case method == "DELETE":
return []int{202, 204}
}
return []int{}
}
func (client *ProviderClient) Get(url string, JSONResponse *interface{}, opts *RequestOpts) (*http.Response, error) {
if opts == nil {
opts = &RequestOpts{}
}
if JSONResponse != nil {
opts.JSONResponse = JSONResponse
}
return client.Request("GET", url, *opts)
}
func (client *ProviderClient) Post(url string, JSONBody interface{}, JSONResponse *interface{}, opts *RequestOpts) (*http.Response, error) {
if opts == nil {
opts = &RequestOpts{}
}
if v, ok := (JSONBody).(io.Reader); ok {
opts.RawBody = v
} else if JSONBody != nil {
opts.JSONBody = JSONBody
}
if JSONResponse != nil {
opts.JSONResponse = JSONResponse
}
return client.Request("POST", url, *opts)
}
func (client *ProviderClient) Put(url string, JSONBody interface{}, JSONResponse *interface{}, opts *RequestOpts) (*http.Response, error) {
if opts == nil {
opts = &RequestOpts{}
}
if v, ok := (JSONBody).(io.Reader); ok {
opts.RawBody = v
} else if JSONBody != nil {
opts.JSONBody = JSONBody
}
if JSONResponse != nil {
opts.JSONResponse = JSONResponse
}
return client.Request("PUT", url, *opts)
}
func (client *ProviderClient) Delete(url string, opts *RequestOpts) (*http.Response, error) {
if opts == nil {
opts = &RequestOpts{}
}
return client.Request("DELETE", url, *opts)
}

View File

@@ -18,18 +18,18 @@ func TestAuthenticatedHeaders(t *testing.T) {
func TestUserAgent(t *testing.T) { func TestUserAgent(t *testing.T) {
p := &ProviderClient{} p := &ProviderClient{}
p.UserAgent.Prepend("custom-user-agent/v2.4") p.UserAgent.Prepend("custom-user-agent/2.4.0")
expected := "custom-user-agent/v2.4 gophercloud/v1.0" expected := "custom-user-agent/2.4.0 gophercloud/1.0.0"
actual := p.UserAgent.Join() actual := p.UserAgent.Join()
th.CheckEquals(t, expected, actual) th.CheckEquals(t, expected, actual)
p.UserAgent.Prepend("another-custom-user-agent/v0.3", "a-third-ua/v5.9") p.UserAgent.Prepend("another-custom-user-agent/0.3.0", "a-third-ua/5.9.0")
expected = "another-custom-user-agent/v0.3 a-third-ua/v5.9 custom-user-agent/v2.4 gophercloud/v1.0" expected = "another-custom-user-agent/0.3.0 a-third-ua/5.9.0 custom-user-agent/2.4.0 gophercloud/1.0.0"
actual = p.UserAgent.Join() actual = p.UserAgent.Join()
th.CheckEquals(t, expected, actual) th.CheckEquals(t, expected, actual)
p.UserAgent = UserAgent{} p.UserAgent = UserAgent{}
expected = "gophercloud/v1.0" expected = "gophercloud/1.0.0"
actual = p.UserAgent.Join() actual = p.UserAgent.Join()
th.CheckEquals(t, expected, actual) th.CheckEquals(t, expected, actual)
} }

View File

@@ -202,3 +202,13 @@ func NewOrchestrationV1(client *gophercloud.ProviderClient, eo gophercloud.Endpo
} }
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
} }
// NewRackConnectV3 creates a ServiceClient that may be used to access the v3 RackConnect service.
func NewRackConnectV3(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
eo.ApplyDefaults("rax:rackconnect")
url, err := client.EndpointLocator(eo)
if err != nil {
return nil, err
}
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
}

View File

@@ -21,10 +21,7 @@ func List(c *gophercloud.ServiceClient) pagination.Pager {
// Get retrieves a specific network based on its unique ID. // Get retrieves a specific network based on its unique ID.
func Get(c *gophercloud.ServiceClient, id string) GetResult { func Get(c *gophercloud.ServiceClient, id string) GetResult {
var res GetResult var res GetResult
_, res.Err = c.Request("GET", getURL(c, id), gophercloud.RequestOpts{ _, res.Err = c.Get(getURL(c, id), &res.Body, nil)
JSONResponse: &res.Body,
OkCodes: []int{200},
})
return res return res
} }
@@ -78,9 +75,7 @@ func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
} }
// Send request to API // Send request to API
_, res.Err = c.Request("POST", createURL(c), gophercloud.RequestOpts{ _, res.Err = c.Post(createURL(c), reqBody, &res.Body, &gophercloud.RequestOpts{
JSONBody: &reqBody,
JSONResponse: &res.Body,
OkCodes: []int{200, 201, 202}, OkCodes: []int{200, 201, 202},
}) })
return res return res
@@ -89,8 +84,6 @@ func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
// Delete accepts a unique ID and deletes the network associated with it. // Delete accepts a unique ID and deletes the network associated with it.
func Delete(c *gophercloud.ServiceClient, networkID string) DeleteResult { func Delete(c *gophercloud.ServiceClient, networkID string) DeleteResult {
var res DeleteResult var res DeleteResult
_, res.Err = c.Request("DELETE", deleteURL(c, networkID), gophercloud.RequestOpts{ _, res.Err = c.Delete(deleteURL(c, networkID), nil)
OkCodes: []int{204},
})
return res return res
} }

Some files were not shown because too many files have changed in this diff Show More