Merge branch 'master' of github.com:GoogleCloudPlatform/kubernetes into add-charms
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -50,3 +50,6 @@ network_closure.sh
|
||||
.kubeconfig
|
||||
|
||||
.tags*
|
||||
|
||||
# Web UI
|
||||
www/master/node_modules/
|
||||
|
112
CHANGELOG.md
112
CHANGELOG.md
@@ -1,5 +1,117 @@
|
||||
# Changelog
|
||||
|
||||
## 0.15.0
|
||||
* Enables v1beta3 API and sets it to the default API version (#6098)
|
||||
* See the [v1beta3 conversion guide](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/api.md#v1beta3-conversion-tips)
|
||||
* Added multi-port Services (#6182)
|
||||
* New Getting Started Guides
|
||||
* Multi-node local startup guide (#6505)
|
||||
* JUJU (#5414)
|
||||
* Mesos on Google Cloud Platform (#5442)
|
||||
* Ansible Setup instructions (#6237)
|
||||
* Added a controller framework (#5270, #5473)
|
||||
* The Kubelet now listens on a secure HTTPS port (#6380)
|
||||
* Made kubectl errors more user-friendly (#6338)
|
||||
* The apiserver now supports client cert authentication (#6190)
|
||||
* The apiserver now limits the number of concurrent requests it processes (#6207)
|
||||
* Added rate limiting to pod deleting (#6355)
|
||||
* Implement Balanced Resource Allocation algorithm as a PriorityFunction in scheduler package (#6150)
|
||||
* Enabled log collection from master (#6396)
|
||||
* Added an api endpoint to pull logs from Pods (#6497)
|
||||
* Added latency metrics to scheduler (#6368)
|
||||
* Added latency metrics to REST client (#6409)
|
||||
* etcd now runs in a pod on the master (#6221)
|
||||
* nginx now runs in a container on the master (#6334)
|
||||
* Began creating Docker images for master components (#6326)
|
||||
* Updated GCE provider to work with gcloud 0.9.54 (#6270)
|
||||
* Updated AWS provider to fix Region vs Zone semantics (#6011)
|
||||
* Record event when image GC fails (#6091)
|
||||
* Add a QPS limiter to the kubernetes client (#6203)
|
||||
* Decrease the time it takes to run make release (#6196)
|
||||
* New volume support
|
||||
* Added iscsi volume plugin (#5506)
|
||||
* Added glusterfs volume plugin (#6174)
|
||||
* AWS EBS volume support (#5138)
|
||||
* Updated to heapster version to v0.10.0 (#6331)
|
||||
* Updated to etcd 2.0.9 (#6544)
|
||||
* Updated to Kibana to v1.2 (#6426)
|
||||
* Bug Fixes
|
||||
* Kube-proxy now updates iptables rules if a service's public IPs change (#6123)
|
||||
* Retry kube-addons creation if the initial creation fails (#6200)
|
||||
* Make kube-proxy more resiliant to running out of file descriptors (#6727)
|
||||
|
||||
## 0.14.2
|
||||
* Fix a regression in service port handling validation
|
||||
* Add a work around for etcd bugs in watch
|
||||
|
||||
## 0.14.1
|
||||
* Fixed an issue where containers with hostPort would sometimes go pending forever. (#6110)
|
||||
|
||||
## 0.14.0
|
||||
* Add HostNetworking container option to the API.
|
||||
* PersistentVolume API
|
||||
* NFS volume plugin fixed/re-added
|
||||
* Upgraded to etcd 2.0.5 on Salt configs
|
||||
* .kubeconfig changes
|
||||
* Kubelet now posts pod status to master, versus master polling.
|
||||
* All cluster add-on images are pulled from gcr.io
|
||||
|
||||
## 0.13.2
|
||||
* Fixes possible cluster bring-up flakiness on GCE/Salt based clusters
|
||||
|
||||
|
||||
## 0.12.2
|
||||
* #5348 - Health check the docker socket and Docker generally
|
||||
* #5395 - Garbage collect unknown containers
|
||||
|
||||
## 0.12.1
|
||||
* DockerCache doesn't get containers at startup (#5115)
|
||||
* Update version of kube2sky to 1.1 (#5127)
|
||||
* Monit health check kubelet and restart unhealthy one (#5120)
|
||||
|
||||
## 0.12.0
|
||||
* Hide the infrastructure pod from users
|
||||
* Configure scheduler via JSON
|
||||
* Improved object validation
|
||||
* Improved messages on scheduler failure
|
||||
* Improved messages on port conflicts
|
||||
* Move to thread-per-pod in the kubelet
|
||||
* Misc. kubectl improvements
|
||||
* Update etcd used by SkyDNS to 2.0.3
|
||||
* Fixes to GCE PD support
|
||||
* Improved support for secrets in the API
|
||||
* Improved OOM behavior
|
||||
|
||||
## 0.11
|
||||
* Secret API Resources
|
||||
* Better error handling in various places
|
||||
* Improved RackSpace support
|
||||
* Fix ```kubectl``` patch behavior
|
||||
* Health check failures fire events
|
||||
* Don't delete the pod infrastructure container on health check failures
|
||||
* Improvements to Pod Status detection and reporting
|
||||
* Reduce the size of scheduled pods in etcd
|
||||
* Fix some bugs in namespace clashing
|
||||
* More detailed info on failed image pulls
|
||||
* Remove pods from a failed node
|
||||
* Safe format and mount of GCE PDs
|
||||
* Make events more resilient to etcd watch failures
|
||||
* Upgrade to container-vm 01-29-2015
|
||||
|
||||
## 0.10
|
||||
* Improvements to swagger API documentation.
|
||||
* Upgrade container VM to 20150129
|
||||
* Start to move e2e tests to Ginkgo
|
||||
* Fix apiserver proxy path rewriting
|
||||
* Upgrade to etcd 2.0.0
|
||||
* Add a wordpress/mysql example
|
||||
* Improve responsiveness of the master when creating new pods
|
||||
* Improve api object validation in numerous small ways
|
||||
* Add support for IPC namespaces
|
||||
* Improve GCE PD support
|
||||
* Make replica controllers with node selectors work correctly
|
||||
* Lots of improvements to e2e tests (more to come)
|
||||
|
||||
## 0.9
|
||||
### Features
|
||||
- Various improvements to kubectl
|
||||
|
18
Godeps/Godeps.json
generated
18
Godeps/Godeps.json
generated
@@ -62,20 +62,10 @@
|
||||
"Comment": "v0.1-62-g8d75e11",
|
||||
"Rev": "8d75e11374a1928608c906fe745b538483e7aeb2"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/coreos/etcd/etcdserver/etcdhttp/httptypes",
|
||||
"Comment": "v2.0.4-288-g866a9d4",
|
||||
"Rev": "866a9d4e41401657ea44bf539b2c5561d6fdcd67"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/coreos/etcd/pkg/types",
|
||||
"Comment": "v2.0.4-288-g866a9d4",
|
||||
"Rev": "866a9d4e41401657ea44bf539b2c5561d6fdcd67"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/coreos/go-etcd/etcd",
|
||||
"Comment": "v0.4.6-8-g60e12ca",
|
||||
"Rev": "60e12cac3db8ffce00b576b4af0e7b0a968f1003"
|
||||
"Comment": "v2.0.0-3-g0424b5f",
|
||||
"Rev": "0424b5f86ef0ca57a5309c599f74bbb3e97ecd9d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/coreos/go-systemd/dbus",
|
||||
@@ -372,8 +362,8 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/rackspace/gophercloud",
|
||||
"Comment": "v1.0.0-490-g32d0a89",
|
||||
"Rev": "32d0a893a8ef70abe76dc5153e2925b39cbea7f7"
|
||||
"Comment": "v1.0.0-569-gf3ced00",
|
||||
"Rev": "f3ced00552c1c7d4a6184500af9062cfb4ff4463"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/russross/blackfriday",
|
||||
|
19
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/doc.go
generated
vendored
19
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/doc.go
generated
vendored
@@ -1,19 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/*
|
||||
Package httptypes defines how etcd's HTTP API entities are serialized to and deserialized from JSON.
|
||||
*/
|
||||
|
||||
package httptypes
|
49
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/errors.go
generated
vendored
49
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/errors.go
generated
vendored
@@ -1,49 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package httptypes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type HTTPError struct {
|
||||
Message string `json:"message"`
|
||||
// HTTP return code
|
||||
Code int `json:"-"`
|
||||
}
|
||||
|
||||
func (e HTTPError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
// TODO(xiangli): handle http write errors
|
||||
func (e HTTPError) WriteTo(w http.ResponseWriter) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(e.Code)
|
||||
b, err := json.Marshal(e)
|
||||
if err != nil {
|
||||
log.Panicf("marshal HTTPError should never fail: %v", err)
|
||||
}
|
||||
w.Write(b)
|
||||
}
|
||||
|
||||
func NewHTTPError(code int, m string) *HTTPError {
|
||||
return &HTTPError{
|
||||
Message: m,
|
||||
Code: code,
|
||||
}
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package httptypes
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHTTPErrorWriteTo(t *testing.T) {
|
||||
err := NewHTTPError(http.StatusBadRequest, "what a bad request you made!")
|
||||
rr := httptest.NewRecorder()
|
||||
err.WriteTo(rr)
|
||||
|
||||
wcode := http.StatusBadRequest
|
||||
wheader := http.Header(map[string][]string{
|
||||
"Content-Type": []string{"application/json"},
|
||||
})
|
||||
wbody := `{"message":"what a bad request you made!"}`
|
||||
|
||||
if wcode != rr.Code {
|
||||
t.Errorf("HTTP status code %d, want %d", rr.Code, wcode)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(wheader, rr.HeaderMap) {
|
||||
t.Errorf("HTTP headers %v, want %v", rr.HeaderMap, wheader)
|
||||
}
|
||||
|
||||
gbody := rr.Body.String()
|
||||
if wbody != gbody {
|
||||
t.Errorf("HTTP body %q, want %q", gbody, wbody)
|
||||
}
|
||||
}
|
67
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/member.go
generated
vendored
67
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/member.go
generated
vendored
@@ -1,67 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package httptypes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/coreos/etcd/pkg/types"
|
||||
)
|
||||
|
||||
type Member struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
PeerURLs []string `json:"peerURLs"`
|
||||
ClientURLs []string `json:"clientURLs"`
|
||||
}
|
||||
|
||||
type MemberCreateRequest struct {
|
||||
PeerURLs types.URLs
|
||||
}
|
||||
|
||||
type MemberUpdateRequest struct {
|
||||
MemberCreateRequest
|
||||
}
|
||||
|
||||
func (m *MemberCreateRequest) UnmarshalJSON(data []byte) error {
|
||||
s := struct {
|
||||
PeerURLs []string `json:"peerURLs"`
|
||||
}{}
|
||||
|
||||
err := json.Unmarshal(data, &s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
urls, err := types.NewURLs(s.PeerURLs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.PeerURLs = urls
|
||||
return nil
|
||||
}
|
||||
|
||||
type MemberCollection []Member
|
||||
|
||||
func (c *MemberCollection) MarshalJSON() ([]byte, error) {
|
||||
d := struct {
|
||||
Members []Member `json:"members"`
|
||||
}{
|
||||
Members: []Member(*c),
|
||||
}
|
||||
|
||||
return json.Marshal(d)
|
||||
}
|
135
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/member_test.go
generated
vendored
135
Godeps/_workspace/src/github.com/coreos/etcd/etcdserver/etcdhttp/httptypes/member_test.go
generated
vendored
@@ -1,135 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package httptypes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/coreos/etcd/pkg/types"
|
||||
)
|
||||
|
||||
func TestMemberUnmarshal(t *testing.T) {
|
||||
tests := []struct {
|
||||
body []byte
|
||||
wantMember Member
|
||||
wantError bool
|
||||
}{
|
||||
// no URLs, just check ID & Name
|
||||
{
|
||||
body: []byte(`{"id": "c", "name": "dungarees"}`),
|
||||
wantMember: Member{ID: "c", Name: "dungarees", PeerURLs: nil, ClientURLs: nil},
|
||||
},
|
||||
|
||||
// both client and peer URLs
|
||||
{
|
||||
body: []byte(`{"peerURLs": ["http://127.0.0.1:4001"], "clientURLs": ["http://127.0.0.1:4001"]}`),
|
||||
wantMember: Member{
|
||||
PeerURLs: []string{
|
||||
"http://127.0.0.1:4001",
|
||||
},
|
||||
ClientURLs: []string{
|
||||
"http://127.0.0.1:4001",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// multiple peer URLs
|
||||
{
|
||||
body: []byte(`{"peerURLs": ["http://127.0.0.1:4001", "https://example.com"]}`),
|
||||
wantMember: Member{
|
||||
PeerURLs: []string{
|
||||
"http://127.0.0.1:4001",
|
||||
"https://example.com",
|
||||
},
|
||||
ClientURLs: nil,
|
||||
},
|
||||
},
|
||||
|
||||
// multiple client URLs
|
||||
{
|
||||
body: []byte(`{"clientURLs": ["http://127.0.0.1:4001", "https://example.com"]}`),
|
||||
wantMember: Member{
|
||||
PeerURLs: nil,
|
||||
ClientURLs: []string{
|
||||
"http://127.0.0.1:4001",
|
||||
"https://example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// invalid JSON
|
||||
{
|
||||
body: []byte(`{"peerU`),
|
||||
wantError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
got := Member{}
|
||||
err := json.Unmarshal(tt.body, &got)
|
||||
if tt.wantError != (err != nil) {
|
||||
t.Errorf("#%d: want error %t, got %v", i, tt.wantError, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tt.wantMember, got) {
|
||||
t.Errorf("#%d: incorrect output: want=%#v, got=%#v", i, tt.wantMember, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMemberCreateRequestUnmarshal(t *testing.T) {
|
||||
body := []byte(`{"peerURLs": ["http://127.0.0.1:8081", "https://127.0.0.1:8080"]}`)
|
||||
want := MemberCreateRequest{
|
||||
PeerURLs: types.URLs([]url.URL{
|
||||
url.URL{Scheme: "http", Host: "127.0.0.1:8081"},
|
||||
url.URL{Scheme: "https", Host: "127.0.0.1:8080"},
|
||||
}),
|
||||
}
|
||||
|
||||
var req MemberCreateRequest
|
||||
if err := json.Unmarshal(body, &req); err != nil {
|
||||
t.Fatalf("Unmarshal returned unexpected err=%v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(want, req) {
|
||||
t.Fatalf("Failed to unmarshal MemberCreateRequest: want=%#v, got=%#v", want, req)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMemberCreateRequestUnmarshalFail(t *testing.T) {
|
||||
tests := [][]byte{
|
||||
// invalid JSON
|
||||
[]byte(``),
|
||||
[]byte(`{`),
|
||||
|
||||
// spot-check validation done in types.NewURLs
|
||||
[]byte(`{"peerURLs": "foo"}`),
|
||||
[]byte(`{"peerURLs": ["."]}`),
|
||||
[]byte(`{"peerURLs": []}`),
|
||||
[]byte(`{"peerURLs": ["http://127.0.0.1:4001/foo"]}`),
|
||||
[]byte(`{"peerURLs": ["http://127.0.0.1"]}`),
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
var req MemberCreateRequest
|
||||
if err := json.Unmarshal(tt, &req); err == nil {
|
||||
t.Errorf("#%d: expected err, got nil", i)
|
||||
}
|
||||
}
|
||||
}
|
41
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/id.go
generated
vendored
41
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/id.go
generated
vendored
@@ -1,41 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// ID represents a generic identifier which is canonically
|
||||
// stored as a uint64 but is typically represented as a
|
||||
// base-16 string for input/output
|
||||
type ID uint64
|
||||
|
||||
func (i ID) String() string {
|
||||
return strconv.FormatUint(uint64(i), 16)
|
||||
}
|
||||
|
||||
// IDFromString attempts to create an ID from a base-16 string.
|
||||
func IDFromString(s string) (ID, error) {
|
||||
i, err := strconv.ParseUint(s, 16, 64)
|
||||
return ID(i), err
|
||||
}
|
||||
|
||||
// IDSlice implements the sort interface
|
||||
type IDSlice []ID
|
||||
|
||||
func (p IDSlice) Len() int { return len(p) }
|
||||
func (p IDSlice) Less(i, j int) bool { return uint64(p[i]) < uint64(p[j]) }
|
||||
func (p IDSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
95
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/id_test.go
generated
vendored
95
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/id_test.go
generated
vendored
@@ -1,95 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIDString(t *testing.T) {
|
||||
tests := []struct {
|
||||
input ID
|
||||
want string
|
||||
}{
|
||||
{
|
||||
input: 12,
|
||||
want: "c",
|
||||
},
|
||||
{
|
||||
input: 4918257920282737594,
|
||||
want: "444129853c343bba",
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
got := tt.input.String()
|
||||
if tt.want != got {
|
||||
t.Errorf("#%d: ID.String failure: want=%v, got=%v", i, tt.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIDFromString(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
want ID
|
||||
}{
|
||||
{
|
||||
input: "17",
|
||||
want: 23,
|
||||
},
|
||||
{
|
||||
input: "612840dae127353",
|
||||
want: 437557308098245459,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
got, err := IDFromString(tt.input)
|
||||
if err != nil {
|
||||
t.Errorf("#%d: IDFromString failure: err=%v", i, err)
|
||||
continue
|
||||
}
|
||||
if tt.want != got {
|
||||
t.Errorf("#%d: IDFromString failure: want=%v, got=%v", i, tt.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIDFromStringFail(t *testing.T) {
|
||||
tests := []string{
|
||||
"",
|
||||
"XXX",
|
||||
"612840dae127353612840dae127353",
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
_, err := IDFromString(tt)
|
||||
if err == nil {
|
||||
t.Fatalf("#%d: IDFromString expected error, but err=nil", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIDSlice(t *testing.T) {
|
||||
g := []ID{10, 500, 5, 1, 100, 25}
|
||||
w := []ID{1, 5, 10, 25, 100, 500}
|
||||
sort.Sort(IDSlice(g))
|
||||
if !reflect.DeepEqual(g, w) {
|
||||
t.Errorf("slice after sort = %#v, want %#v", g, w)
|
||||
}
|
||||
}
|
178
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/set.go
generated
vendored
178
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/set.go
generated
vendored
@@ -1,178 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Set interface {
|
||||
Add(string)
|
||||
Remove(string)
|
||||
Contains(string) bool
|
||||
Equals(Set) bool
|
||||
Length() int
|
||||
Values() []string
|
||||
Copy() Set
|
||||
Sub(Set) Set
|
||||
}
|
||||
|
||||
func NewUnsafeSet(values ...string) *unsafeSet {
|
||||
set := &unsafeSet{make(map[string]struct{})}
|
||||
for _, v := range values {
|
||||
set.Add(v)
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
func NewThreadsafeSet(values ...string) *tsafeSet {
|
||||
us := NewUnsafeSet(values...)
|
||||
return &tsafeSet{us, sync.RWMutex{}}
|
||||
}
|
||||
|
||||
type unsafeSet struct {
|
||||
d map[string]struct{}
|
||||
}
|
||||
|
||||
// Add adds a new value to the set (no-op if the value is already present)
|
||||
func (us *unsafeSet) Add(value string) {
|
||||
us.d[value] = struct{}{}
|
||||
}
|
||||
|
||||
// Remove removes the given value from the set
|
||||
func (us *unsafeSet) Remove(value string) {
|
||||
delete(us.d, value)
|
||||
}
|
||||
|
||||
// Contains returns whether the set contains the given value
|
||||
func (us *unsafeSet) Contains(value string) (exists bool) {
|
||||
_, exists = us.d[value]
|
||||
return
|
||||
}
|
||||
|
||||
// ContainsAll returns whether the set contains all given values
|
||||
func (us *unsafeSet) ContainsAll(values []string) bool {
|
||||
for _, s := range values {
|
||||
if !us.Contains(s) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Equals returns whether the contents of two sets are identical
|
||||
func (us *unsafeSet) Equals(other Set) bool {
|
||||
v1 := sort.StringSlice(us.Values())
|
||||
v2 := sort.StringSlice(other.Values())
|
||||
v1.Sort()
|
||||
v2.Sort()
|
||||
return reflect.DeepEqual(v1, v2)
|
||||
}
|
||||
|
||||
// Length returns the number of elements in the set
|
||||
func (us *unsafeSet) Length() int {
|
||||
return len(us.d)
|
||||
}
|
||||
|
||||
// Values returns the values of the Set in an unspecified order.
|
||||
func (us *unsafeSet) Values() (values []string) {
|
||||
values = make([]string, 0)
|
||||
for val, _ := range us.d {
|
||||
values = append(values, val)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Copy creates a new Set containing the values of the first
|
||||
func (us *unsafeSet) Copy() Set {
|
||||
cp := NewUnsafeSet()
|
||||
for val, _ := range us.d {
|
||||
cp.Add(val)
|
||||
}
|
||||
|
||||
return cp
|
||||
}
|
||||
|
||||
// Sub removes all elements in other from the set
|
||||
func (us *unsafeSet) Sub(other Set) Set {
|
||||
oValues := other.Values()
|
||||
result := us.Copy().(*unsafeSet)
|
||||
|
||||
for _, val := range oValues {
|
||||
if _, ok := result.d[val]; !ok {
|
||||
continue
|
||||
}
|
||||
delete(result.d, val)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
type tsafeSet struct {
|
||||
us *unsafeSet
|
||||
m sync.RWMutex
|
||||
}
|
||||
|
||||
func (ts *tsafeSet) Add(value string) {
|
||||
ts.m.Lock()
|
||||
defer ts.m.Unlock()
|
||||
ts.us.Add(value)
|
||||
}
|
||||
|
||||
func (ts *tsafeSet) Remove(value string) {
|
||||
ts.m.Lock()
|
||||
defer ts.m.Unlock()
|
||||
ts.us.Remove(value)
|
||||
}
|
||||
|
||||
func (ts *tsafeSet) Contains(value string) (exists bool) {
|
||||
ts.m.RLock()
|
||||
defer ts.m.RUnlock()
|
||||
return ts.us.Contains(value)
|
||||
}
|
||||
|
||||
func (ts *tsafeSet) Equals(other Set) bool {
|
||||
ts.m.RLock()
|
||||
defer ts.m.RUnlock()
|
||||
return ts.us.Equals(other)
|
||||
}
|
||||
|
||||
func (ts *tsafeSet) Length() int {
|
||||
ts.m.RLock()
|
||||
defer ts.m.RUnlock()
|
||||
return ts.us.Length()
|
||||
}
|
||||
|
||||
func (ts *tsafeSet) Values() (values []string) {
|
||||
ts.m.RLock()
|
||||
defer ts.m.RUnlock()
|
||||
return ts.us.Values()
|
||||
}
|
||||
|
||||
func (ts *tsafeSet) Copy() Set {
|
||||
ts.m.RLock()
|
||||
defer ts.m.RUnlock()
|
||||
usResult := ts.us.Copy().(*unsafeSet)
|
||||
return &tsafeSet{usResult, sync.RWMutex{}}
|
||||
}
|
||||
|
||||
func (ts *tsafeSet) Sub(other Set) Set {
|
||||
ts.m.RLock()
|
||||
defer ts.m.RUnlock()
|
||||
usResult := ts.us.Sub(other).(*unsafeSet)
|
||||
return &tsafeSet{usResult, sync.RWMutex{}}
|
||||
}
|
186
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/set_test.go
generated
vendored
186
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/set_test.go
generated
vendored
@@ -1,186 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUnsafeSet(t *testing.T) {
|
||||
driveSetTests(t, NewUnsafeSet())
|
||||
}
|
||||
|
||||
func TestThreadsafeSet(t *testing.T) {
|
||||
driveSetTests(t, NewThreadsafeSet())
|
||||
}
|
||||
|
||||
// Check that two slices contents are equal; order is irrelevant
|
||||
func equal(a, b []string) bool {
|
||||
as := sort.StringSlice(a)
|
||||
bs := sort.StringSlice(b)
|
||||
as.Sort()
|
||||
bs.Sort()
|
||||
return reflect.DeepEqual(as, bs)
|
||||
}
|
||||
|
||||
func driveSetTests(t *testing.T, s Set) {
|
||||
// Verify operations on an empty set
|
||||
eValues := []string{}
|
||||
values := s.Values()
|
||||
if !reflect.DeepEqual(values, eValues) {
|
||||
t.Fatalf("Expect values=%v got %v", eValues, values)
|
||||
}
|
||||
if l := s.Length(); l != 0 {
|
||||
t.Fatalf("Expected length=0, got %d", l)
|
||||
}
|
||||
for _, v := range []string{"foo", "bar", "baz"} {
|
||||
if s.Contains(v) {
|
||||
t.Fatalf("Expect s.Contains(%q) to be fale, got true", v)
|
||||
}
|
||||
}
|
||||
|
||||
// Add three items, ensure they show up
|
||||
s.Add("foo")
|
||||
s.Add("bar")
|
||||
s.Add("baz")
|
||||
|
||||
eValues = []string{"foo", "bar", "baz"}
|
||||
values = s.Values()
|
||||
if !equal(values, eValues) {
|
||||
t.Fatalf("Expect values=%v got %v", eValues, values)
|
||||
}
|
||||
|
||||
for _, v := range eValues {
|
||||
if !s.Contains(v) {
|
||||
t.Fatalf("Expect s.Contains(%q) to be true, got false", v)
|
||||
}
|
||||
}
|
||||
|
||||
if l := s.Length(); l != 3 {
|
||||
t.Fatalf("Expected length=3, got %d", l)
|
||||
}
|
||||
|
||||
// Add the same item a second time, ensuring it is not duplicated
|
||||
s.Add("foo")
|
||||
|
||||
values = s.Values()
|
||||
if !equal(values, eValues) {
|
||||
t.Fatalf("Expect values=%v got %v", eValues, values)
|
||||
}
|
||||
if l := s.Length(); l != 3 {
|
||||
t.Fatalf("Expected length=3, got %d", l)
|
||||
}
|
||||
|
||||
// Remove all items, ensure they are gone
|
||||
s.Remove("foo")
|
||||
s.Remove("bar")
|
||||
s.Remove("baz")
|
||||
|
||||
eValues = []string{}
|
||||
values = s.Values()
|
||||
if !equal(values, eValues) {
|
||||
t.Fatalf("Expect values=%v got %v", eValues, values)
|
||||
}
|
||||
|
||||
if l := s.Length(); l != 0 {
|
||||
t.Fatalf("Expected length=0, got %d", l)
|
||||
}
|
||||
|
||||
// Create new copies of the set, and ensure they are unlinked to the
|
||||
// original Set by making modifications
|
||||
s.Add("foo")
|
||||
s.Add("bar")
|
||||
cp1 := s.Copy()
|
||||
cp2 := s.Copy()
|
||||
s.Remove("foo")
|
||||
cp3 := s.Copy()
|
||||
cp1.Add("baz")
|
||||
|
||||
for i, tt := range []struct {
|
||||
want []string
|
||||
got []string
|
||||
}{
|
||||
{[]string{"bar"}, s.Values()},
|
||||
{[]string{"foo", "bar", "baz"}, cp1.Values()},
|
||||
{[]string{"foo", "bar"}, cp2.Values()},
|
||||
{[]string{"bar"}, cp3.Values()},
|
||||
} {
|
||||
if !equal(tt.want, tt.got) {
|
||||
t.Fatalf("case %d: expect values=%v got %v", i, tt.want, tt.got)
|
||||
}
|
||||
}
|
||||
|
||||
for i, tt := range []struct {
|
||||
want bool
|
||||
got bool
|
||||
}{
|
||||
{true, s.Equals(cp3)},
|
||||
{true, cp3.Equals(s)},
|
||||
{false, s.Equals(cp2)},
|
||||
{false, s.Equals(cp1)},
|
||||
{false, cp1.Equals(s)},
|
||||
{false, cp2.Equals(s)},
|
||||
{false, cp2.Equals(cp1)},
|
||||
} {
|
||||
if tt.got != tt.want {
|
||||
t.Fatalf("case %d: want %t, got %t", i, tt.want, tt.got)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Subtract values from a Set, ensuring a new Set is created and
|
||||
// the original Sets are unmodified
|
||||
sub1 := cp1.Sub(s)
|
||||
sub2 := cp2.Sub(cp1)
|
||||
|
||||
for i, tt := range []struct {
|
||||
want []string
|
||||
got []string
|
||||
}{
|
||||
{[]string{"foo", "bar", "baz"}, cp1.Values()},
|
||||
{[]string{"foo", "bar"}, cp2.Values()},
|
||||
{[]string{"bar"}, s.Values()},
|
||||
{[]string{"foo", "baz"}, sub1.Values()},
|
||||
{[]string{}, sub2.Values()},
|
||||
} {
|
||||
if !equal(tt.want, tt.got) {
|
||||
t.Fatalf("case %d: expect values=%v got %v", i, tt.want, tt.got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnsafeSetContainsAll(t *testing.T) {
|
||||
vals := []string{"foo", "bar", "baz"}
|
||||
s := NewUnsafeSet(vals...)
|
||||
|
||||
tests := []struct {
|
||||
strs []string
|
||||
wcontain bool
|
||||
}{
|
||||
{[]string{}, true},
|
||||
{vals[:1], true},
|
||||
{vals[:2], true},
|
||||
{vals, true},
|
||||
{[]string{"cuz"}, false},
|
||||
{[]string{vals[0], "cuz"}, false},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
if g := s.ContainsAll(tt.strs); g != tt.wcontain {
|
||||
t.Errorf("#%d: ok = %v, want %v", i, g, tt.wcontain)
|
||||
}
|
||||
}
|
||||
}
|
22
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/slice.go
generated
vendored
22
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/slice.go
generated
vendored
@@ -1,22 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package types
|
||||
|
||||
// Uint64Slice implements sort interface
|
||||
type Uint64Slice []uint64
|
||||
|
||||
func (p Uint64Slice) Len() int { return len(p) }
|
||||
func (p Uint64Slice) Less(i, j int) bool { return p[i] < p[j] }
|
||||
func (p Uint64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
30
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/slice_test.go
generated
vendored
30
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/slice_test.go
generated
vendored
@@ -1,30 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUint64Slice(t *testing.T) {
|
||||
g := Uint64Slice{10, 500, 5, 1, 100, 25}
|
||||
w := Uint64Slice{1, 5, 10, 25, 100, 500}
|
||||
sort.Sort(g)
|
||||
if !reflect.DeepEqual(g, w) {
|
||||
t.Errorf("slice after sort = %#v, want %#v", g, w)
|
||||
}
|
||||
}
|
74
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/urls.go
generated
vendored
74
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/urls.go
generated
vendored
@@ -1,74 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type URLs []url.URL
|
||||
|
||||
func NewURLs(strs []string) (URLs, error) {
|
||||
all := make([]url.URL, len(strs))
|
||||
if len(all) == 0 {
|
||||
return nil, errors.New("no valid URLs given")
|
||||
}
|
||||
for i, in := range strs {
|
||||
in = strings.TrimSpace(in)
|
||||
u, err := url.Parse(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if u.Scheme != "http" && u.Scheme != "https" {
|
||||
return nil, fmt.Errorf("URL scheme must be http or https: %s", in)
|
||||
}
|
||||
if _, _, err := net.SplitHostPort(u.Host); err != nil {
|
||||
return nil, fmt.Errorf(`URL address does not have the form "host:port": %s`, in)
|
||||
}
|
||||
if u.Path != "" {
|
||||
return nil, fmt.Errorf("URL must not contain a path: %s", in)
|
||||
}
|
||||
all[i] = *u
|
||||
}
|
||||
us := URLs(all)
|
||||
us.Sort()
|
||||
|
||||
return us, nil
|
||||
}
|
||||
|
||||
func (us URLs) String() string {
|
||||
return strings.Join(us.StringSlice(), ",")
|
||||
}
|
||||
|
||||
func (us *URLs) Sort() {
|
||||
sort.Sort(us)
|
||||
}
|
||||
func (us URLs) Len() int { return len(us) }
|
||||
func (us URLs) Less(i, j int) bool { return us[i].String() < us[j].String() }
|
||||
func (us URLs) Swap(i, j int) { us[i], us[j] = us[j], us[i] }
|
||||
|
||||
func (us URLs) StringSlice() []string {
|
||||
out := make([]string, len(us))
|
||||
for i := range us {
|
||||
out[i] = us[i].String()
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
169
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/urls_test.go
generated
vendored
169
Godeps/_workspace/src/github.com/coreos/etcd/pkg/types/urls_test.go
generated
vendored
@@ -1,169 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/coreos/etcd/pkg/testutil"
|
||||
)
|
||||
|
||||
func TestNewURLs(t *testing.T) {
|
||||
tests := []struct {
|
||||
strs []string
|
||||
wurls URLs
|
||||
}{
|
||||
{
|
||||
[]string{"http://127.0.0.1:4001"},
|
||||
testutil.MustNewURLs(t, []string{"http://127.0.0.1:4001"}),
|
||||
},
|
||||
// it can trim space
|
||||
{
|
||||
[]string{" http://127.0.0.1:4001 "},
|
||||
testutil.MustNewURLs(t, []string{"http://127.0.0.1:4001"}),
|
||||
},
|
||||
// it does sort
|
||||
{
|
||||
[]string{
|
||||
"http://127.0.0.2:4001",
|
||||
"http://127.0.0.1:4001",
|
||||
},
|
||||
testutil.MustNewURLs(t, []string{
|
||||
"http://127.0.0.1:4001",
|
||||
"http://127.0.0.2:4001",
|
||||
}),
|
||||
},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
urls, _ := NewURLs(tt.strs)
|
||||
if !reflect.DeepEqual(urls, tt.wurls) {
|
||||
t.Errorf("#%d: urls = %+v, want %+v", i, urls, tt.wurls)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestURLsString(t *testing.T) {
|
||||
tests := []struct {
|
||||
us URLs
|
||||
wstr string
|
||||
}{
|
||||
{
|
||||
URLs{},
|
||||
"",
|
||||
},
|
||||
{
|
||||
testutil.MustNewURLs(t, []string{"http://127.0.0.1:4001"}),
|
||||
"http://127.0.0.1:4001",
|
||||
},
|
||||
{
|
||||
testutil.MustNewURLs(t, []string{
|
||||
"http://127.0.0.1:4001",
|
||||
"http://127.0.0.2:4001",
|
||||
}),
|
||||
"http://127.0.0.1:4001,http://127.0.0.2:4001",
|
||||
},
|
||||
{
|
||||
testutil.MustNewURLs(t, []string{
|
||||
"http://127.0.0.2:4001",
|
||||
"http://127.0.0.1:4001",
|
||||
}),
|
||||
"http://127.0.0.2:4001,http://127.0.0.1:4001",
|
||||
},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
g := tt.us.String()
|
||||
if g != tt.wstr {
|
||||
t.Errorf("#%d: string = %s, want %s", i, g, tt.wstr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestURLsSort(t *testing.T) {
|
||||
g := testutil.MustNewURLs(t, []string{
|
||||
"http://127.0.0.4:4001",
|
||||
"http://127.0.0.2:4001",
|
||||
"http://127.0.0.1:4001",
|
||||
"http://127.0.0.3:4001",
|
||||
})
|
||||
w := testutil.MustNewURLs(t, []string{
|
||||
"http://127.0.0.1:4001",
|
||||
"http://127.0.0.2:4001",
|
||||
"http://127.0.0.3:4001",
|
||||
"http://127.0.0.4:4001",
|
||||
})
|
||||
gurls := URLs(g)
|
||||
gurls.Sort()
|
||||
if !reflect.DeepEqual(g, w) {
|
||||
t.Errorf("URLs after sort = %#v, want %#v", g, w)
|
||||
}
|
||||
}
|
||||
|
||||
func TestURLsStringSlice(t *testing.T) {
|
||||
tests := []struct {
|
||||
us URLs
|
||||
wstr []string
|
||||
}{
|
||||
{
|
||||
URLs{},
|
||||
[]string{},
|
||||
},
|
||||
{
|
||||
testutil.MustNewURLs(t, []string{"http://127.0.0.1:4001"}),
|
||||
[]string{"http://127.0.0.1:4001"},
|
||||
},
|
||||
{
|
||||
testutil.MustNewURLs(t, []string{
|
||||
"http://127.0.0.1:4001",
|
||||
"http://127.0.0.2:4001",
|
||||
}),
|
||||
[]string{"http://127.0.0.1:4001", "http://127.0.0.2:4001"},
|
||||
},
|
||||
{
|
||||
testutil.MustNewURLs(t, []string{
|
||||
"http://127.0.0.2:4001",
|
||||
"http://127.0.0.1:4001",
|
||||
}),
|
||||
[]string{"http://127.0.0.2:4001", "http://127.0.0.1:4001"},
|
||||
},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
g := tt.us.StringSlice()
|
||||
if !reflect.DeepEqual(g, tt.wstr) {
|
||||
t.Errorf("#%d: string slice = %+v, want %+v", i, g, tt.wstr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewURLsFail(t *testing.T) {
|
||||
tests := [][]string{
|
||||
// no urls given
|
||||
{},
|
||||
// missing protocol scheme
|
||||
{"://127.0.0.1:4001"},
|
||||
// unsupported scheme
|
||||
{"mailto://127.0.0.1:4001"},
|
||||
// not conform to host:port
|
||||
{"http://127.0.0.1"},
|
||||
// contain a path
|
||||
{"http://127.0.0.1:4001/path"},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
_, err := NewURLs(tt)
|
||||
if err == nil {
|
||||
t.Errorf("#%d: err = nil, but error", i)
|
||||
}
|
||||
}
|
||||
}
|
75
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/client.go
generated
vendored
75
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/client.go
generated
vendored
@@ -15,8 +15,6 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/etcdserver/etcdhttp/httptypes"
|
||||
)
|
||||
|
||||
// See SetConsistency for how to use these constants.
|
||||
@@ -44,10 +42,17 @@ type Config struct {
|
||||
Consistency string `json:"consistency"`
|
||||
}
|
||||
|
||||
type credentials struct {
|
||||
username string
|
||||
password string
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
config Config `json:"config"`
|
||||
cluster *Cluster `json:"cluster"`
|
||||
httpClient *http.Client
|
||||
credentials *credentials
|
||||
transport *http.Transport
|
||||
persistence io.Writer
|
||||
cURLch chan string
|
||||
// CheckRetry can be used to control the policy for failed requests
|
||||
@@ -172,17 +177,27 @@ func NewClientFromReader(reader io.Reader) (*Client, error) {
|
||||
// Override the Client's HTTP Transport object
|
||||
func (c *Client) SetTransport(tr *http.Transport) {
|
||||
c.httpClient.Transport = tr
|
||||
c.transport = tr
|
||||
}
|
||||
|
||||
func (c *Client) SetCredentials(username, password string) {
|
||||
c.credentials = &credentials{username, password}
|
||||
}
|
||||
|
||||
func (c *Client) Close() {
|
||||
c.transport.DisableKeepAlives = true
|
||||
c.transport.CloseIdleConnections()
|
||||
}
|
||||
|
||||
// initHTTPClient initializes a HTTP client for etcd client
|
||||
func (c *Client) initHTTPClient() {
|
||||
tr := &http.Transport{
|
||||
c.transport = &http.Transport{
|
||||
Dial: c.dial,
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
}
|
||||
c.httpClient = &http.Client{Transport: tr}
|
||||
c.httpClient = &http.Client{Transport: c.transport}
|
||||
}
|
||||
|
||||
// initHTTPClient initializes a HTTPS client for etcd client
|
||||
@@ -305,31 +320,49 @@ func (c *Client) internalSyncCluster(machines []string) bool {
|
||||
continue
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
// try another machine in the cluster
|
||||
continue
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK { // fall-back to old endpoint
|
||||
httpPath := c.createHttpPath(machine, path.Join(version, "machines"))
|
||||
resp, err := c.httpClient.Get(httpPath)
|
||||
if err != nil {
|
||||
// try another machine in the cluster
|
||||
continue
|
||||
}
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
// try another machine in the cluster
|
||||
continue
|
||||
}
|
||||
// update Machines List
|
||||
c.cluster.updateFromStr(string(b))
|
||||
} else {
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
// try another machine in the cluster
|
||||
continue
|
||||
}
|
||||
|
||||
var mCollection httptypes.MemberCollection
|
||||
if err := json.Unmarshal(b, &mCollection); err != nil {
|
||||
// try another machine
|
||||
continue
|
||||
}
|
||||
var mCollection memberCollection
|
||||
if err := json.Unmarshal(b, &mCollection); err != nil {
|
||||
// try another machine
|
||||
continue
|
||||
}
|
||||
|
||||
urls := make([]string, 0)
|
||||
for _, m := range mCollection {
|
||||
urls = append(urls, m.ClientURLs...)
|
||||
}
|
||||
urls := make([]string, 0)
|
||||
for _, m := range mCollection {
|
||||
urls = append(urls, m.ClientURLs...)
|
||||
}
|
||||
|
||||
// update Machines List
|
||||
c.cluster.updateFromStr(strings.Join(urls, ","))
|
||||
// update Machines List
|
||||
c.cluster.updateFromStr(strings.Join(urls, ","))
|
||||
}
|
||||
|
||||
logger.Debug("sync.machines ", c.cluster.Machines)
|
||||
c.saveConfig()
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
12
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/client_test.go
generated
vendored
12
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/client_test.go
generated
vendored
@@ -94,3 +94,15 @@ func TestPersistence(t *testing.T) {
|
||||
t.Fatalf("The two configs should be equal!")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientRetry(t *testing.T) {
|
||||
c := NewClient([]string{"http://strange", "http://127.0.0.1:4001"})
|
||||
// use first endpoint as the picked url
|
||||
c.cluster.picked = 0
|
||||
if _, err := c.Set("foo", "bar", 5); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := c.Delete("foo", true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
3
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/cluster.go
generated
vendored
3
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/cluster.go
generated
vendored
@@ -30,5 +30,8 @@ func (cl *Cluster) pick() string { return cl.Machines[cl.picked] }
|
||||
|
||||
func (cl *Cluster) updateFromStr(machines string) {
|
||||
cl.Machines = strings.Split(machines, ",")
|
||||
for i := range cl.Machines {
|
||||
cl.Machines[i] = strings.TrimSpace(cl.Machines[i])
|
||||
}
|
||||
cl.picked = rand.Intn(len(cl.Machines))
|
||||
}
|
||||
|
30
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/member.go
generated
vendored
Normal file
30
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/member.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
package etcd
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type Member struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
PeerURLs []string `json:"peerURLs"`
|
||||
ClientURLs []string `json:"clientURLs"`
|
||||
}
|
||||
|
||||
type memberCollection []Member
|
||||
|
||||
func (c *memberCollection) UnmarshalJSON(data []byte) error {
|
||||
d := struct {
|
||||
Members []Member
|
||||
}{}
|
||||
|
||||
if err := json.Unmarshal(data, &d); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d.Members == nil {
|
||||
*c = make([]Member, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
*c = d.Members
|
||||
return nil
|
||||
}
|
71
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/member_test.go
generated
vendored
Normal file
71
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/member_test.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
package etcd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMemberCollectionUnmarshal(t *testing.T) {
|
||||
tests := []struct {
|
||||
body []byte
|
||||
want memberCollection
|
||||
}{
|
||||
{
|
||||
body: []byte(`{"members":[]}`),
|
||||
want: memberCollection([]Member{}),
|
||||
},
|
||||
{
|
||||
body: []byte(`{"members":[{"id":"2745e2525fce8fe","peerURLs":["http://127.0.0.1:7003"],"name":"node3","clientURLs":["http://127.0.0.1:4003"]},{"id":"42134f434382925","peerURLs":["http://127.0.0.1:2380","http://127.0.0.1:7001"],"name":"node1","clientURLs":["http://127.0.0.1:2379","http://127.0.0.1:4001"]},{"id":"94088180e21eb87b","peerURLs":["http://127.0.0.1:7002"],"name":"node2","clientURLs":["http://127.0.0.1:4002"]}]}`),
|
||||
want: memberCollection(
|
||||
[]Member{
|
||||
{
|
||||
ID: "2745e2525fce8fe",
|
||||
Name: "node3",
|
||||
PeerURLs: []string{
|
||||
"http://127.0.0.1:7003",
|
||||
},
|
||||
ClientURLs: []string{
|
||||
"http://127.0.0.1:4003",
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "42134f434382925",
|
||||
Name: "node1",
|
||||
PeerURLs: []string{
|
||||
"http://127.0.0.1:2380",
|
||||
"http://127.0.0.1:7001",
|
||||
},
|
||||
ClientURLs: []string{
|
||||
"http://127.0.0.1:2379",
|
||||
"http://127.0.0.1:4001",
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "94088180e21eb87b",
|
||||
Name: "node2",
|
||||
PeerURLs: []string{
|
||||
"http://127.0.0.1:7002",
|
||||
},
|
||||
ClientURLs: []string{
|
||||
"http://127.0.0.1:4002",
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
var got memberCollection
|
||||
err := json.Unmarshal(tt.body, &got)
|
||||
if err != nil {
|
||||
t.Errorf("#%d: unexpected error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tt.want, got) {
|
||||
t.Errorf("#%d: incorrect output: want=%#v, got=%#v", i, tt.want, got)
|
||||
}
|
||||
}
|
||||
}
|
38
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/requests.go
generated
vendored
38
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/requests.go
generated
vendored
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
@@ -189,7 +188,10 @@ func (c *Client) SendRequest(rr *RawRequest) (*RawResponse, error) {
|
||||
|
||||
logger.Debug("Connecting to etcd: attempt ", attempt+1, " for ", rr.RelativePath)
|
||||
|
||||
httpPath = c.getHttpPath(rr.RelativePath)
|
||||
// get httpPath if not set
|
||||
if httpPath == "" {
|
||||
httpPath = c.getHttpPath(rr.RelativePath)
|
||||
}
|
||||
|
||||
// Return a cURL command if curlChan is set
|
||||
if c.cURLch != nil {
|
||||
@@ -197,6 +199,9 @@ func (c *Client) SendRequest(rr *RawRequest) (*RawResponse, error) {
|
||||
for key, value := range rr.Values {
|
||||
command += fmt.Sprintf(" -d %s=%s", key, value[0])
|
||||
}
|
||||
if c.credentials != nil {
|
||||
command += fmt.Sprintf(" -u %s", c.credentials.username)
|
||||
}
|
||||
c.sendCURL(command)
|
||||
}
|
||||
|
||||
@@ -226,7 +231,13 @@ func (c *Client) SendRequest(rr *RawRequest) (*RawResponse, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.credentials != nil {
|
||||
req.SetBasicAuth(c.credentials.username, c.credentials.password)
|
||||
}
|
||||
|
||||
resp, err = c.httpClient.Do(req)
|
||||
// clear previous httpPath
|
||||
httpPath = ""
|
||||
defer func() {
|
||||
if resp != nil {
|
||||
resp.Body.Close()
|
||||
@@ -281,6 +292,19 @@ func (c *Client) SendRequest(rr *RawRequest) (*RawResponse, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusTemporaryRedirect {
|
||||
u, err := resp.Location()
|
||||
|
||||
if err != nil {
|
||||
logger.Warning(err)
|
||||
} else {
|
||||
// set httpPath for following redirection
|
||||
httpPath = u.String()
|
||||
}
|
||||
resp.Body.Close()
|
||||
continue
|
||||
}
|
||||
|
||||
if checkErr := checkRetry(c.cluster, numReqs, *resp,
|
||||
errors.New("Unexpected HTTP status code")); checkErr != nil {
|
||||
return nil, checkErr
|
||||
@@ -304,9 +328,8 @@ func DefaultCheckRetry(cluster *Cluster, numReqs int, lastResp http.Response,
|
||||
err error) error {
|
||||
|
||||
if isEmptyResponse(lastResp) {
|
||||
if !isConnectionError(err) {
|
||||
return err
|
||||
}
|
||||
// always retry if it failed to get response from one machine
|
||||
return nil
|
||||
} else if !shouldRetry(lastResp) {
|
||||
body := []byte("nil")
|
||||
if lastResp.Body != nil {
|
||||
@@ -333,11 +356,6 @@ func DefaultCheckRetry(cluster *Cluster, numReqs int, lastResp http.Response,
|
||||
|
||||
func isEmptyResponse(r http.Response) bool { return r.StatusCode == 0 }
|
||||
|
||||
func isConnectionError(err error) bool {
|
||||
_, ok := err.(*net.OpError)
|
||||
return ok
|
||||
}
|
||||
|
||||
// shouldRetry returns whether the reponse deserves retry.
|
||||
func shouldRetry(r http.Response) bool {
|
||||
// TODO: only retry when the cluster is in leader election
|
||||
|
22
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/requests_test.go
generated
vendored
Normal file
22
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/requests_test.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package etcd
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestKeyToPath(t *testing.T) {
|
||||
tests := []struct {
|
||||
key string
|
||||
wpath string
|
||||
}{
|
||||
{"", "keys/"},
|
||||
{"foo", "keys/foo"},
|
||||
{"foo/bar", "keys/foo/bar"},
|
||||
{"%z", "keys/%25z"},
|
||||
{"/", "keys/"},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
path := keyToPath(tt.key)
|
||||
if path != tt.wpath {
|
||||
t.Errorf("#%d: path = %s, want %s", i, path, tt.wpath)
|
||||
}
|
||||
}
|
||||
}
|
5
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/version.go
generated
vendored
5
Godeps/_workspace/src/github.com/coreos/go-etcd/etcd/version.go
generated
vendored
@@ -1,3 +1,6 @@
|
||||
package etcd
|
||||
|
||||
const version = "v2"
|
||||
const (
|
||||
version = "v2"
|
||||
packageVersion = "v2.0.0+git"
|
||||
)
|
||||
|
2
Godeps/_workspace/src/github.com/rackspace/gophercloud/.travis.yml
generated
vendored
2
Godeps/_workspace/src/github.com/rackspace/gophercloud/.travis.yml
generated
vendored
@@ -9,7 +9,7 @@ go:
|
||||
- tip
|
||||
script: script/cibuild
|
||||
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/mattn/goveralls
|
||||
- export PATH=$PATH:$HOME/gopath/bin/
|
||||
|
2
Godeps/_workspace/src/github.com/rackspace/gophercloud/CONTRIBUTING.md
generated
vendored
2
Godeps/_workspace/src/github.com/rackspace/gophercloud/CONTRIBUTING.md
generated
vendored
@@ -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
|
||||
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
|
||||
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
|
||||
submit an issue on our [bug tracker](/issues). Things you might like to tell us
|
||||
are:
|
||||
|
7
Godeps/_workspace/src/github.com/rackspace/gophercloud/README.md
generated
vendored
7
Godeps/_workspace/src/github.com/rackspace/gophercloud/README.md
generated
vendored
@@ -25,7 +25,7 @@ export GOPATH=$HOME/go
|
||||
```
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
[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!
|
||||
|
||||
## Help and feedback
|
||||
|
||||
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
|
||||
[sdk-support@rackspace.com](mailto:sdk-support@rackspace.com).
|
||||
to submit an issue to our [bug tracker](/issues) or [contact us directly](https://developer.rackspace.com/support/).
|
||||
|
2
Godeps/_workspace/src/github.com/rackspace/gophercloud/UPGRADING.md
generated
vendored
2
Godeps/_workspace/src/github.com/rackspace/gophercloud/UPGRADING.md
generated
vendored
@@ -8,7 +8,7 @@ extensible, maintainable and easy-to-use.
|
||||
Below we've compiled upgrade instructions for the various services that
|
||||
existed before. If you have a specific issue that is not addressed below,
|
||||
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)
|
||||
* [Servers](#servers)
|
||||
|
@@ -56,6 +56,9 @@ type ComputeChoices struct {
|
||||
// FlavorIDResize contains the ID of a different flavor available on the same OpenStack installation, that is distinct
|
||||
// from FlavorID.
|
||||
FlavorIDResize string
|
||||
|
||||
// NetworkName is the name of a network to launch the instance on.
|
||||
NetworkName string
|
||||
}
|
||||
|
||||
// ComputeChoicesFromEnv populates a ComputeChoices struct from environment variables.
|
||||
@@ -64,6 +67,7 @@ func ComputeChoicesFromEnv() (*ComputeChoices, error) {
|
||||
imageID := os.Getenv("OS_IMAGE_ID")
|
||||
flavorID := os.Getenv("OS_FLAVOR_ID")
|
||||
flavorIDResize := os.Getenv("OS_FLAVOR_ID_RESIZE")
|
||||
networkName := os.Getenv("OS_NETWORK_NAME")
|
||||
|
||||
missing := make([]string, 0, 3)
|
||||
if imageID == "" {
|
||||
@@ -75,6 +79,9 @@ func ComputeChoicesFromEnv() (*ComputeChoices, error) {
|
||||
if flavorIDResize == "" {
|
||||
missing = append(missing, "OS_FLAVOR_ID_RESIZE")
|
||||
}
|
||||
if networkName == "" {
|
||||
networkName = "public"
|
||||
}
|
||||
|
||||
notDistinct := ""
|
||||
if flavorID == flavorIDResize {
|
||||
@@ -93,5 +100,5 @@ func ComputeChoicesFromEnv() (*ComputeChoices, error) {
|
||||
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
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
|
||||
th "github.com/rackspace/gophercloud/testhelper"
|
||||
|
||||
"code.google.com/p/go.crypto/ssh"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
const keyName = "gophercloud_test_key_pair"
|
||||
|
58
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/servergroup_test.go
generated
vendored
Normal file
58
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/servergroup_test.go
generated
vendored
Normal 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)
|
||||
}
|
||||
}
|
@@ -57,7 +57,6 @@ func networkingClient() (*gophercloud.ServiceClient, error) {
|
||||
}
|
||||
|
||||
return openstack.NewNetworkV2(provider, gophercloud.EndpointOpts{
|
||||
Name: "neutron",
|
||||
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)
|
||||
}
|
||||
|
||||
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) {
|
||||
networks, err := networks.ExtractNetworks(page)
|
||||
if err != nil {
|
||||
@@ -138,6 +140,32 @@ func TestCreateDestroyServer(t *testing.T) {
|
||||
if err = waitForStatus(client, server, "ACTIVE"); err != nil {
|
||||
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) {
|
||||
|
109
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/tenantnetworks_test.go
generated
vendored
Normal file
109
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/openstack/compute/v2/tenantnetworks_test.go
generated
vendored
Normal 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)
|
||||
}
|
165
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/networking/v2/security_test.go
generated
vendored
Normal file
165
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/networking/v2/security_test.go
generated
vendored
Normal 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)
|
||||
}
|
36
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/rackconnect/v3/cloudnetworks_test.go
generated
vendored
Normal file
36
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/rackconnect/v3/cloudnetworks_test.go
generated
vendored
Normal 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)
|
||||
}
|
26
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/rackconnect/v3/common.go
generated
vendored
Normal file
26
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/rackconnect/v3/common.go
generated
vendored
Normal 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
|
||||
}
|
71
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/rackconnect/v3/lbpools_test.go
generated
vendored
Normal file
71
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/rackconnect/v3/lbpools_test.go
generated
vendored
Normal 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)
|
||||
}
|
45
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/rackconnect/v3/publicips_test.go
generated
vendored
Normal file
45
Godeps/_workspace/src/github.com/rackspace/gophercloud/acceptance/rackspace/rackconnect/v3/publicips_test.go
generated
vendored
Normal 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)
|
||||
}
|
@@ -16,9 +16,6 @@ func List(c *gophercloud.ServiceClient) pagination.Pager {
|
||||
// type from the result, call the Extract method on the GetResult.
|
||||
func Get(client *gophercloud.ServiceClient, v string) GetResult {
|
||||
var res GetResult
|
||||
_, res.Err = client.Request("GET", getURL(client, v), gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
JSONResponse: &res.Body,
|
||||
})
|
||||
_, res.Err = client.Get(getURL(client, v), &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
@@ -67,10 +67,8 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
|
||||
return res
|
||||
}
|
||||
|
||||
_, res.Err = client.Request("POST", createURL(client), gophercloud.RequestOpts{
|
||||
OkCodes: []int{200, 201},
|
||||
JSONBody: &reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
_, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200, 201},
|
||||
})
|
||||
return res
|
||||
}
|
||||
@@ -78,9 +76,7 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
|
||||
// Delete will delete the existing Snapshot with the provided ID.
|
||||
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
|
||||
var res DeleteResult
|
||||
_, res.Err = client.Request("DELETE", deleteURL(client, id), gophercloud.RequestOpts{
|
||||
OkCodes: []int{202, 204},
|
||||
})
|
||||
_, res.Err = client.Delete(deleteURL(client, id), nil)
|
||||
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.
|
||||
func Get(client *gophercloud.ServiceClient, id string) GetResult {
|
||||
var res GetResult
|
||||
_, res.Err = client.Request("GET", getURL(client, id), gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
JSONResponse: &res.Body,
|
||||
})
|
||||
_, res.Err = client.Get(getURL(client, id), &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -173,10 +166,8 @@ func UpdateMetadata(client *gophercloud.ServiceClient, id string, opts UpdateMet
|
||||
return res
|
||||
}
|
||||
|
||||
_, res.Err = client.Request("PUT", updateMetadataURL(client, id), gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
JSONBody: &reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
_, res.Err = client.Put(updateMetadataURL(client, id), reqBody, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
@@ -83,10 +83,8 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
|
||||
return res
|
||||
}
|
||||
|
||||
_, res.Err = client.Request("POST", createURL(client), gophercloud.RequestOpts{
|
||||
OkCodes: []int{200, 201},
|
||||
JSONBody: &reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
_, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200, 201},
|
||||
})
|
||||
return res
|
||||
}
|
||||
@@ -94,9 +92,7 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
|
||||
// Delete will delete the existing Volume with the provided ID.
|
||||
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
|
||||
var res DeleteResult
|
||||
_, res.Err = client.Request("DELETE", deleteURL(client, id), gophercloud.RequestOpts{
|
||||
OkCodes: []int{202, 204},
|
||||
})
|
||||
_, res.Err = client.Delete(deleteURL(client, id), nil)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -104,10 +100,7 @@ func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
|
||||
// from the response, call the Extract method on the GetResult.
|
||||
func Get(client *gophercloud.ServiceClient, id string) GetResult {
|
||||
var res GetResult
|
||||
_, res.Err = client.Request("GET", getURL(client, id), gophercloud.RequestOpts{
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
_, res.Err = client.Get(getURL(client, id), &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -203,10 +196,8 @@ func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder
|
||||
return res
|
||||
}
|
||||
|
||||
_, res.Err = client.Request("PUT", updateURL(client, id), gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
JSONBody: &reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
_, res.Err = client.Put(updateURL(client, id), reqBody, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
@@ -44,11 +44,8 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
|
||||
return res
|
||||
}
|
||||
|
||||
_, res.Err = client.Request("POST", createURL(client), gophercloud.RequestOpts{
|
||||
MoreHeaders: client.AuthenticatedHeaders(),
|
||||
OkCodes: []int{200, 201},
|
||||
JSONBody: &reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
_, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200, 201},
|
||||
})
|
||||
return res
|
||||
}
|
||||
@@ -56,10 +53,7 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
|
||||
// Delete will delete the volume type with the provided ID.
|
||||
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
|
||||
var res DeleteResult
|
||||
_, res.Err = client.Request("DELETE", deleteURL(client, id), gophercloud.RequestOpts{
|
||||
MoreHeaders: client.AuthenticatedHeaders(),
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
_, res.Err = client.Delete(deleteURL(client, id), nil)
|
||||
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.
|
||||
func Get(client *gophercloud.ServiceClient, id string) GetResult {
|
||||
var res GetResult
|
||||
_, err := client.Request("GET", getURL(client, id), gophercloud.RequestOpts{
|
||||
MoreHeaders: client.AuthenticatedHeaders(),
|
||||
OkCodes: []int{200},
|
||||
JSONResponse: &res.Body,
|
||||
})
|
||||
_, err := client.Get(getURL(client, id), &res.Body, nil)
|
||||
res.Err = err
|
||||
return res
|
||||
}
|
||||
|
@@ -6,17 +6,14 @@ import "github.com/rackspace/gophercloud"
|
||||
// entire API.
|
||||
func Get(c *gophercloud.ServiceClient) GetResult {
|
||||
var res GetResult
|
||||
_, res.Err = c.Request("GET", getURL(c), gophercloud.RequestOpts{
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
_, res.Err = c.Get(getURL(c), &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
// Ping retrieves a ping to the server.
|
||||
func Ping(c *gophercloud.ServiceClient) 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},
|
||||
MoreHeaders: map[string]string{"Accept": ""},
|
||||
})
|
||||
|
@@ -17,18 +17,18 @@ func TestGetHomeDocument(t *testing.T) {
|
||||
|
||||
expected := HomeDocument{
|
||||
"rel/cdn": map[string]interface{}{
|
||||
"href-template": "services{?marker,limit}",
|
||||
"href-vars": map[string]interface{}{
|
||||
"marker": "param/marker",
|
||||
"limit": "param/limit",
|
||||
},
|
||||
"hints": map[string]interface{}{
|
||||
"allow": []string{"GET"},
|
||||
"formats": map[string]interface{}{
|
||||
"application/json": map[string]interface{}{},
|
||||
},
|
||||
},
|
||||
},
|
||||
"href-template": "services{?marker,limit}",
|
||||
"href-vars": map[string]interface{}{
|
||||
"marker": "param/marker",
|
||||
"limit": "param/limit",
|
||||
},
|
||||
"hints": map[string]interface{}{
|
||||
"allow": []string{"GET"},
|
||||
"formats": map[string]interface{}{
|
||||
"application/json": map[string]interface{}{},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
th.CheckDeepEquals(t, expected, *actual)
|
||||
}
|
||||
|
@@ -1,24 +1,24 @@
|
||||
package flavors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
th "github.com/rackspace/gophercloud/testhelper"
|
||||
fake "github.com/rackspace/gophercloud/testhelper/client"
|
||||
th "github.com/rackspace/gophercloud/testhelper"
|
||||
fake "github.com/rackspace/gophercloud/testhelper/client"
|
||||
)
|
||||
|
||||
// HandleListCDNFlavorsSuccessfully creates an HTTP handler at `/flavors` on the test handler mux
|
||||
// that responds with a `List` response.
|
||||
func HandleListCDNFlavorsSuccessfully(t *testing.T) {
|
||||
th.Mux.HandleFunc("/flavors", func(w http.ResponseWriter, r *http.Request) {
|
||||
th.TestMethod(t, r, "GET")
|
||||
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||
th.Mux.HandleFunc("/flavors", func(w http.ResponseWriter, r *http.Request) {
|
||||
th.TestMethod(t, r, "GET")
|
||||
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprintf(w, `
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprintf(w, `
|
||||
{
|
||||
"flavors": [
|
||||
{
|
||||
@@ -44,19 +44,19 @@ func HandleListCDNFlavorsSuccessfully(t *testing.T) {
|
||||
]
|
||||
}
|
||||
`)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// HandleGetCDNFlavorSuccessfully creates an HTTP handler at `/flavors/{id}` on the test handler mux
|
||||
// that responds with a `Get` response.
|
||||
func HandleGetCDNFlavorSuccessfully(t *testing.T) {
|
||||
th.Mux.HandleFunc("/flavors/asia", func(w http.ResponseWriter, r *http.Request) {
|
||||
th.TestMethod(t, r, "GET")
|
||||
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||
th.Mux.HandleFunc("/flavors/asia", func(w http.ResponseWriter, r *http.Request) {
|
||||
th.TestMethod(t, r, "GET")
|
||||
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprintf(w, `
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
fmt.Fprintf(w, `
|
||||
{
|
||||
"id" : "asia",
|
||||
"providers" : [
|
||||
@@ -78,5 +78,5 @@ func HandleGetCDNFlavorSuccessfully(t *testing.T) {
|
||||
]
|
||||
}
|
||||
`)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@@ -17,9 +17,6 @@ func List(c *gophercloud.ServiceClient) pagination.Pager {
|
||||
// Get retrieves a specific flavor based on its unique ID.
|
||||
func Get(c *gophercloud.ServiceClient, id string) GetResult {
|
||||
var res GetResult
|
||||
_, res.Err = c.Request("GET", getURL(c, id), gophercloud.RequestOpts{
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
_, res.Err = c.Get(getURL(c, id), &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
@@ -1,90 +1,89 @@
|
||||
package flavors
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"testing"
|
||||
|
||||
"github.com/rackspace/gophercloud"
|
||||
"github.com/rackspace/gophercloud/pagination"
|
||||
th "github.com/rackspace/gophercloud/testhelper"
|
||||
fake "github.com/rackspace/gophercloud/testhelper/client"
|
||||
"github.com/rackspace/gophercloud"
|
||||
"github.com/rackspace/gophercloud/pagination"
|
||||
th "github.com/rackspace/gophercloud/testhelper"
|
||||
fake "github.com/rackspace/gophercloud/testhelper/client"
|
||||
)
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
th.SetupHTTP()
|
||||
defer th.TeardownHTTP()
|
||||
th.SetupHTTP()
|
||||
defer th.TeardownHTTP()
|
||||
|
||||
HandleListCDNFlavorsSuccessfully(t)
|
||||
HandleListCDNFlavorsSuccessfully(t)
|
||||
|
||||
count := 0
|
||||
count := 0
|
||||
|
||||
err := List(fake.ServiceClient()).EachPage(func(page pagination.Page) (bool, error) {
|
||||
count++
|
||||
actual, err := ExtractFlavors(page)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to extract flavors: %v", err)
|
||||
return false, err
|
||||
}
|
||||
err := List(fake.ServiceClient()).EachPage(func(page pagination.Page) (bool, error) {
|
||||
count++
|
||||
actual, err := ExtractFlavors(page)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to extract flavors: %v", err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
expected := []Flavor{
|
||||
Flavor{
|
||||
ID: "europe",
|
||||
Providers: []Provider{
|
||||
Provider{
|
||||
Provider: "Fastly",
|
||||
Links: []gophercloud.Link{
|
||||
gophercloud.Link{
|
||||
Href: "http://www.fastly.com",
|
||||
Rel: "provider_url",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Links: []gophercloud.Link{
|
||||
gophercloud.Link{
|
||||
Href: "https://www.poppycdn.io/v1.0/flavors/europe",
|
||||
Rel: "self",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
expected := []Flavor{
|
||||
Flavor{
|
||||
ID: "europe",
|
||||
Providers: []Provider{
|
||||
Provider{
|
||||
Provider: "Fastly",
|
||||
Links: []gophercloud.Link{
|
||||
gophercloud.Link{
|
||||
Href: "http://www.fastly.com",
|
||||
Rel: "provider_url",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Links: []gophercloud.Link{
|
||||
gophercloud.Link{
|
||||
Href: "https://www.poppycdn.io/v1.0/flavors/europe",
|
||||
Rel: "self",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
th.CheckDeepEquals(t, expected, actual)
|
||||
th.CheckDeepEquals(t, expected, actual)
|
||||
|
||||
return true, nil
|
||||
})
|
||||
th.AssertNoErr(t, err)
|
||||
th.CheckEquals(t, 1, count)
|
||||
return true, nil
|
||||
})
|
||||
th.AssertNoErr(t, err)
|
||||
th.CheckEquals(t, 1, count)
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
th.SetupHTTP()
|
||||
defer th.TeardownHTTP()
|
||||
th.SetupHTTP()
|
||||
defer th.TeardownHTTP()
|
||||
|
||||
HandleGetCDNFlavorSuccessfully(t)
|
||||
HandleGetCDNFlavorSuccessfully(t)
|
||||
|
||||
expected := &Flavor{
|
||||
ID: "asia",
|
||||
Providers: []Provider{
|
||||
Provider{
|
||||
Provider: "ChinaCache",
|
||||
Links: []gophercloud.Link{
|
||||
gophercloud.Link{
|
||||
Href: "http://www.chinacache.com",
|
||||
Rel: "provider_url",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Links: []gophercloud.Link{
|
||||
gophercloud.Link{
|
||||
Href: "https://www.poppycdn.io/v1.0/flavors/asia",
|
||||
Rel: "self",
|
||||
},
|
||||
},
|
||||
}
|
||||
expected := &Flavor{
|
||||
ID: "asia",
|
||||
Providers: []Provider{
|
||||
Provider{
|
||||
Provider: "ChinaCache",
|
||||
Links: []gophercloud.Link{
|
||||
gophercloud.Link{
|
||||
Href: "http://www.chinacache.com",
|
||||
Rel: "provider_url",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Links: []gophercloud.Link{
|
||||
gophercloud.Link{
|
||||
Href: "https://www.poppycdn.io/v1.0/flavors/asia",
|
||||
Rel: "self",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
actual, err := Get(fake.ServiceClient(), "asia").Extract()
|
||||
th.AssertNoErr(t, err)
|
||||
th.AssertDeepEquals(t, expected, actual)
|
||||
actual, err := Get(fake.ServiceClient(), "asia").Extract()
|
||||
th.AssertNoErr(t, err)
|
||||
th.AssertDeepEquals(t, expected, actual)
|
||||
}
|
||||
|
@@ -1,19 +1,19 @@
|
||||
package serviceassets
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
th "github.com/rackspace/gophercloud/testhelper"
|
||||
fake "github.com/rackspace/gophercloud/testhelper/client"
|
||||
th "github.com/rackspace/gophercloud/testhelper"
|
||||
fake "github.com/rackspace/gophercloud/testhelper/client"
|
||||
)
|
||||
|
||||
// HandleDeleteCDNAssetSuccessfully creates an HTTP handler at `/services/{id}/assets` on the test handler mux
|
||||
// that responds with a `Delete` response.
|
||||
func HandleDeleteCDNAssetSuccessfully(t *testing.T) {
|
||||
th.Mux.HandleFunc("/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0/assets", func(w http.ResponseWriter, r *http.Request) {
|
||||
th.TestMethod(t, r, "DELETE")
|
||||
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
})
|
||||
th.Mux.HandleFunc("/services/96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0/assets", func(w http.ResponseWriter, r *http.Request) {
|
||||
th.TestMethod(t, r, "DELETE")
|
||||
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
})
|
||||
}
|
||||
|
@@ -43,8 +43,6 @@ func Delete(c *gophercloud.ServiceClient, idOrURL string, opts DeleteOptsBuilder
|
||||
}
|
||||
|
||||
var res DeleteResult
|
||||
_, res.Err = c.Request("DELETE", url, gophercloud.RequestOpts{
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
_, res.Err = c.Delete(url, nil)
|
||||
return res
|
||||
}
|
||||
|
@@ -1,18 +1,18 @@
|
||||
package serviceassets
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"testing"
|
||||
|
||||
th "github.com/rackspace/gophercloud/testhelper"
|
||||
fake "github.com/rackspace/gophercloud/testhelper/client"
|
||||
th "github.com/rackspace/gophercloud/testhelper"
|
||||
fake "github.com/rackspace/gophercloud/testhelper/client"
|
||||
)
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
th.SetupHTTP()
|
||||
defer th.TeardownHTTP()
|
||||
th.SetupHTTP()
|
||||
defer th.TeardownHTTP()
|
||||
|
||||
HandleDeleteCDNAssetSuccessfully(t)
|
||||
HandleDeleteCDNAssetSuccessfully(t)
|
||||
|
||||
err := Delete(fake.ServiceClient(), "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0", nil).ExtractErr()
|
||||
th.AssertNoErr(t, err)
|
||||
err := Delete(fake.ServiceClient(), "96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0", nil).ExtractErr()
|
||||
th.AssertNoErr(t, err)
|
||||
}
|
||||
|
@@ -177,10 +177,7 @@ func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
|
||||
}
|
||||
|
||||
// Send request to API
|
||||
resp, err := c.Request("POST", createURL(c), gophercloud.RequestOpts{
|
||||
JSONBody: &reqBody,
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
resp, err := c.Post(createURL(c), &reqBody, nil, nil)
|
||||
res.Header = resp.Header
|
||||
res.Err = err
|
||||
return res
|
||||
@@ -199,10 +196,7 @@ func Get(c *gophercloud.ServiceClient, idOrURL string) GetResult {
|
||||
}
|
||||
|
||||
var res GetResult
|
||||
_, res.Err = c.Request("GET", url, gophercloud.RequestOpts{
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
_, res.Err = c.Get(url, &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -379,8 +373,6 @@ func Delete(c *gophercloud.ServiceClient, idOrURL string) DeleteResult {
|
||||
}
|
||||
|
||||
var res DeleteResult
|
||||
_, res.Err = c.Request("DELETE", url, gophercloud.RequestOpts{
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
_, res.Err = c.Delete(url, nil)
|
||||
return res
|
||||
}
|
||||
|
31
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/client.go
generated
vendored
31
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/client.go
generated
vendored
@@ -109,6 +109,7 @@ func v2auth(client *gophercloud.ProviderClient, endpoint string, options gopherc
|
||||
|
||||
if options.AllowReauth {
|
||||
client.ReauthFunc = func() error {
|
||||
client.TokenID = ""
|
||||
return AuthenticateV2(client, options)
|
||||
}
|
||||
}
|
||||
@@ -132,10 +133,36 @@ func v3auth(client *gophercloud.ProviderClient, endpoint string, options gopherc
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
catalog, err := result.ExtractServiceCatalog()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client.TokenID = token.ID
|
||||
|
||||
if options.AllowReauth {
|
||||
@@ -144,7 +171,7 @@ func v3auth(client *gophercloud.ProviderClient, endpoint string, options gopherc
|
||||
}
|
||||
}
|
||||
client.EndpointLocator = func(opts gophercloud.EndpointOpts) (string, error) {
|
||||
return V3EndpointURL(v3Client, opts)
|
||||
return V3EndpointURL(catalog, opts)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@@ -8,10 +8,7 @@ import (
|
||||
// Get retrieves information for a specific extension using its alias.
|
||||
func Get(c *gophercloud.ServiceClient, alias string) GetResult {
|
||||
var res GetResult
|
||||
_, res.Err = c.Request("GET", ExtensionURL(c, alias), gophercloud.RequestOpts{
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
_, res.Err = c.Get(ExtensionURL(c, alias), &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
|
@@ -99,10 +99,8 @@ func Create(client *gophercloud.ServiceClient, opts servers.CreateOptsBuilder) s
|
||||
return res
|
||||
}
|
||||
|
||||
_, res.Err = client.Request("POST", createURL(client), gophercloud.RequestOpts{
|
||||
JSONBody: reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200, 202},
|
||||
_, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200, 202},
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
@@ -73,10 +73,8 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
|
||||
return result
|
||||
}
|
||||
|
||||
_, result.Err = client.Request("POST", rootURL(client), gophercloud.RequestOpts{
|
||||
JSONResponse: &result.Body,
|
||||
JSONBody: &reqBody,
|
||||
OkCodes: []int{200},
|
||||
_, result.Err = client.Post(rootURL(client), reqBody, &result.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
|
||||
return result
|
||||
@@ -85,22 +83,13 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
|
||||
// Get will return details for a particular default rule.
|
||||
func Get(client *gophercloud.ServiceClient, id string) GetResult {
|
||||
var result GetResult
|
||||
|
||||
_, result.Err = client.Request("GET", resourceURL(client, id), gophercloud.RequestOpts{
|
||||
JSONResponse: &result.Body,
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
|
||||
_, result.Err = client.Get(resourceURL(client, id), &result.Body, nil)
|
||||
return result
|
||||
}
|
||||
|
||||
// Delete will permanently delete a default rule from the project.
|
||||
func Delete(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
|
||||
var result gophercloud.ErrResult
|
||||
|
||||
_, result.Err = client.Request("DELETE", resourceURL(client, id), gophercloud.RequestOpts{
|
||||
OkCodes: []int{204},
|
||||
})
|
||||
|
||||
_, result.Err = client.Delete(resourceURL(client, id), nil)
|
||||
return result
|
||||
}
|
||||
|
@@ -45,10 +45,8 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
|
||||
return res
|
||||
}
|
||||
|
||||
_, res.Err = client.Request("POST", createURL(client), gophercloud.RequestOpts{
|
||||
JSONBody: reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
_, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return res
|
||||
}
|
||||
@@ -56,19 +54,14 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
|
||||
// Get returns data about a previously created FloatingIP.
|
||||
func Get(client *gophercloud.ServiceClient, id string) GetResult {
|
||||
var res GetResult
|
||||
_, res.Err = client.Request("GET", getURL(client, id), gophercloud.RequestOpts{
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
_, res.Err = client.Get(getURL(client, id), &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
// Delete requests the deletion of a previous allocated FloatingIP.
|
||||
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
|
||||
var res DeleteResult
|
||||
_, res.Err = client.Request("DELETE", deleteURL(client, id), gophercloud.RequestOpts{
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
_, res.Err = client.Delete(deleteURL(client, id), nil)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -82,10 +75,7 @@ func Associate(client *gophercloud.ServiceClient, serverId, fip string) Associat
|
||||
addFloatingIp["address"] = fip
|
||||
reqBody := map[string]interface{}{"addFloatingIp": addFloatingIp}
|
||||
|
||||
_, res.Err = client.Request("POST", associateURL(client, serverId), gophercloud.RequestOpts{
|
||||
JSONBody: reqBody,
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
_, res.Err = client.Post(associateURL(client, serverId), reqBody, nil, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -97,9 +87,6 @@ func Disassociate(client *gophercloud.ServiceClient, serverId, fip string) Disas
|
||||
removeFloatingIp["address"] = fip
|
||||
reqBody := map[string]interface{}{"removeFloatingIp": removeFloatingIp}
|
||||
|
||||
_, res.Err = client.Request("POST", disassociateURL(client, serverId), gophercloud.RequestOpts{
|
||||
JSONBody: reqBody,
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
_, res.Err = client.Post(disassociateURL(client, serverId), reqBody, nil, nil)
|
||||
return res
|
||||
}
|
||||
|
@@ -81,10 +81,8 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
|
||||
return res
|
||||
}
|
||||
|
||||
_, res.Err = client.Request("POST", createURL(client), gophercloud.RequestOpts{
|
||||
JSONBody: reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
_, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return res
|
||||
}
|
||||
@@ -92,18 +90,13 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
|
||||
// Get returns public data about a previously uploaded KeyPair.
|
||||
func Get(client *gophercloud.ServiceClient, name string) GetResult {
|
||||
var res GetResult
|
||||
_, res.Err = client.Request("GET", getURL(client, name), gophercloud.RequestOpts{
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
_, res.Err = client.Get(getURL(client, name), &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
// Delete requests the deletion of a previous stored KeyPair from the server.
|
||||
func Delete(client *gophercloud.ServiceClient, name string) DeleteResult {
|
||||
var res DeleteResult
|
||||
_, res.Err = client.Request("DELETE", deleteURL(client, name), gophercloud.RequestOpts{
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
_, res.Err = client.Delete(deleteURL(client, name), nil)
|
||||
return res
|
||||
}
|
||||
|
@@ -78,10 +78,8 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
|
||||
return result
|
||||
}
|
||||
|
||||
_, result.Err = client.Request("POST", rootURL(client), gophercloud.RequestOpts{
|
||||
JSONResponse: &result.Body,
|
||||
JSONBody: &reqBody,
|
||||
OkCodes: []int{200},
|
||||
_, result.Err = client.Post(rootURL(client), reqBody, &result.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
|
||||
return result
|
||||
@@ -123,10 +121,8 @@ func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder
|
||||
return result
|
||||
}
|
||||
|
||||
_, result.Err = client.Request("PUT", resourceURL(client, id), gophercloud.RequestOpts{
|
||||
JSONResponse: &result.Body,
|
||||
JSONBody: &reqBody,
|
||||
OkCodes: []int{200},
|
||||
_, result.Err = client.Put(resourceURL(client, id), reqBody, &result.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
|
||||
return result
|
||||
@@ -135,23 +131,14 @@ func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder
|
||||
// Get will return details for a particular security group.
|
||||
func Get(client *gophercloud.ServiceClient, id string) GetResult {
|
||||
var result GetResult
|
||||
|
||||
_, result.Err = client.Request("GET", resourceURL(client, id), gophercloud.RequestOpts{
|
||||
JSONResponse: &result.Body,
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
|
||||
_, result.Err = client.Get(resourceURL(client, id), &result.Body, nil)
|
||||
return result
|
||||
}
|
||||
|
||||
// Delete will permanently delete a security group from the project.
|
||||
func Delete(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
|
||||
var result gophercloud.ErrResult
|
||||
|
||||
_, result.Err = client.Request("DELETE", resourceURL(client, id), gophercloud.RequestOpts{
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
|
||||
_, result.Err = client.Delete(resourceURL(client, id), nil)
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -234,10 +221,8 @@ func CreateRule(client *gophercloud.ServiceClient, opts CreateRuleOptsBuilder) C
|
||||
return result
|
||||
}
|
||||
|
||||
_, result.Err = client.Request("POST", rootRuleURL(client), gophercloud.RequestOpts{
|
||||
JSONResponse: &result.Body,
|
||||
JSONBody: &reqBody,
|
||||
OkCodes: []int{200},
|
||||
_, result.Err = client.Post(rootRuleURL(client), reqBody, &result.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
|
||||
return result
|
||||
@@ -246,11 +231,7 @@ func CreateRule(client *gophercloud.ServiceClient, opts CreateRuleOptsBuilder) C
|
||||
// DeleteRule will permanently delete a rule from a security group.
|
||||
func DeleteRule(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
|
||||
var result gophercloud.ErrResult
|
||||
|
||||
_, result.Err = client.Request("DELETE", resourceRuleURL(client, id), gophercloud.RequestOpts{
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
|
||||
_, result.Err = client.Delete(resourceRuleURL(client, id), nil)
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -264,25 +245,13 @@ func actionMap(prefix, groupName string) map[string]map[string]string {
|
||||
// rules of the group on the server.
|
||||
func AddServerToGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
|
||||
var result gophercloud.ErrResult
|
||||
|
||||
_, result.Err = client.Request("POST", serverActionURL(client, serverID), gophercloud.RequestOpts{
|
||||
JSONResponse: &result.Body,
|
||||
JSONBody: actionMap("add", groupName),
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
|
||||
_, result.Err = client.Post(serverActionURL(client, serverID), actionMap("add", groupName), &result.Body, nil)
|
||||
return result
|
||||
}
|
||||
|
||||
// RemoveServerFromGroup will disassociate a server from a security group.
|
||||
func RemoveServerFromGroup(client *gophercloud.ServiceClient, serverID, groupName string) gophercloud.ErrResult {
|
||||
var result gophercloud.ErrResult
|
||||
|
||||
_, result.Err = client.Request("POST", serverActionURL(client, serverID), gophercloud.RequestOpts{
|
||||
JSONResponse: &result.Body,
|
||||
JSONBody: actionMap("remove", groupName),
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
|
||||
_, result.Err = client.Post(serverActionURL(client, serverID), actionMap("remove", groupName), &result.Body, nil)
|
||||
return result
|
||||
}
|
||||
|
2
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/servergroups/doc.go
generated
vendored
Normal file
2
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/servergroups/doc.go
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package servergroups provides the ability to manage server groups
|
||||
package servergroups
|
161
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/servergroups/fixtures.go
generated
vendored
Normal file
161
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/servergroups/fixtures.go
generated
vendored
Normal 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)
|
||||
})
|
||||
}
|
77
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/servergroups/requests.go
generated
vendored
Normal file
77
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/servergroups/requests.go
generated
vendored
Normal 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
|
||||
}
|
59
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/servergroups/requests_test.go
generated
vendored
Normal file
59
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/servergroups/requests_test.go
generated
vendored
Normal 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)
|
||||
}
|
87
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/servergroups/results.go
generated
vendored
Normal file
87
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/servergroups/results.go
generated
vendored
Normal 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
|
||||
}
|
25
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/servergroups/urls.go
generated
vendored
Normal file
25
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/servergroups/urls.go
generated
vendored
Normal 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)
|
||||
}
|
42
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/servergroups/urls_test.go
generated
vendored
Normal file
42
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/servergroups/urls_test.go
generated
vendored
Normal 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))
|
||||
}
|
@@ -9,27 +9,15 @@ func actionURL(client *gophercloud.ServiceClient, id string) string {
|
||||
// Start is the operation responsible for starting a Compute server.
|
||||
func Start(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
|
||||
var res gophercloud.ErrResult
|
||||
|
||||
reqBody := map[string]interface{}{"os-start": nil}
|
||||
|
||||
_, res.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{
|
||||
JSONBody: reqBody,
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
|
||||
_, res.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
// Stop is the operation responsible for stopping a Compute server.
|
||||
func Stop(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
|
||||
var res gophercloud.ErrResult
|
||||
|
||||
reqBody := map[string]interface{}{"os-stop": nil}
|
||||
|
||||
_, res.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{
|
||||
JSONBody: reqBody,
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
|
||||
_, res.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
|
||||
return res
|
||||
}
|
||||
|
2
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks/doc.go
generated
vendored
Normal file
2
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks/doc.go
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package tenantnetworks provides the ability for tenants to see information about the networks they have access to
|
||||
package tenantnetworks
|
84
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks/fixtures.go
generated
vendored
Normal file
84
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks/fixtures.go
generated
vendored
Normal 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)
|
||||
})
|
||||
}
|
22
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks/requests.go
generated
vendored
Normal file
22
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks/requests.go
generated
vendored
Normal 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
|
||||
}
|
37
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks/requests_test.go
generated
vendored
Normal file
37
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks/requests_test.go
generated
vendored
Normal 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)
|
||||
}
|
68
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks/results.go
generated
vendored
Normal file
68
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks/results.go
generated
vendored
Normal 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
|
||||
}
|
17
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks/urls.go
generated
vendored
Normal file
17
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks/urls.go
generated
vendored
Normal 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)
|
||||
}
|
25
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks/urls_test.go
generated
vendored
Normal file
25
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks/urls_test.go
generated
vendored
Normal 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))
|
||||
}
|
@@ -54,10 +54,8 @@ func Create(client *gophercloud.ServiceClient, serverId string, opts CreateOptsB
|
||||
return res
|
||||
}
|
||||
|
||||
_, res.Err = client.Request("POST", createURL(client, serverId), gophercloud.RequestOpts{
|
||||
JSONBody: reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
_, res.Err = client.Post(createURL(client, serverId), reqBody, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return res
|
||||
}
|
||||
@@ -65,18 +63,13 @@ func Create(client *gophercloud.ServiceClient, serverId string, opts CreateOptsB
|
||||
// Get returns public data about a previously created VolumeAttachment.
|
||||
func Get(client *gophercloud.ServiceClient, serverId, aId string) GetResult {
|
||||
var res GetResult
|
||||
_, res.Err = client.Request("GET", getURL(client, serverId, aId), gophercloud.RequestOpts{
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
_, res.Err = client.Get(getURL(client, serverId, aId), &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
// Delete requests the deletion of a previous stored VolumeAttachment from the server.
|
||||
func Delete(client *gophercloud.ServiceClient, serverId, aId string) DeleteResult {
|
||||
var res DeleteResult
|
||||
_, res.Err = client.Request("DELETE", deleteURL(client, serverId, aId), gophercloud.RequestOpts{
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
_, res.Err = client.Delete(deleteURL(client, serverId, aId), nil)
|
||||
return res
|
||||
}
|
||||
|
@@ -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.
|
||||
// Use ExtractFlavor to convert its result into a Flavor.
|
||||
func Get(client *gophercloud.ServiceClient, id string) GetResult {
|
||||
var gr GetResult
|
||||
_, gr.Err = client.Request("GET", getURL(client, id), gophercloud.RequestOpts{
|
||||
JSONResponse: &gr.Body,
|
||||
})
|
||||
return gr
|
||||
var res GetResult
|
||||
_, res.Err = client.Get(getURL(client, id), &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
@@ -60,9 +60,13 @@ func ListDetail(client *gophercloud.ServiceClient, opts ListOptsBuilder) paginat
|
||||
// Use ExtractImage() to interpret the result as an openstack Image.
|
||||
func Get(client *gophercloud.ServiceClient, id string) GetResult {
|
||||
var result GetResult
|
||||
_, result.Err = client.Request("GET", getURL(client, id), gophercloud.RequestOpts{
|
||||
JSONResponse: &result.Body,
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
_, result.Err = client.Get(getURL(client, id), &result.Body, nil)
|
||||
return result
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
@@ -173,3 +173,19 @@ func TestNextPageURL(t *testing.T) {
|
||||
th.AssertNoErr(t, err)
|
||||
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)
|
||||
}
|
||||
|
@@ -11,6 +11,11 @@ type GetResult struct {
|
||||
gophercloud.Result
|
||||
}
|
||||
|
||||
// DeleteResult represents the result of an image.Delete operation.
|
||||
type DeleteResult struct {
|
||||
gophercloud.ErrResult
|
||||
}
|
||||
|
||||
// Extract interprets a GetResult as an Image.
|
||||
func (gr GetResult) Extract() (*Image, error) {
|
||||
if gr.Err != nil {
|
||||
|
@@ -9,3 +9,7 @@ func listDetailURL(client *gophercloud.ServiceClient) string {
|
||||
func getURL(client *gophercloud.ServiceClient, id string) string {
|
||||
return client.ServiceURL("images", id)
|
||||
}
|
||||
|
||||
func deleteURL(client *gophercloud.ServiceClient, id string) string {
|
||||
return client.ServiceURL("images", id)
|
||||
}
|
||||
|
@@ -567,3 +567,98 @@ func HandleMetadataUpdateSuccessfully(t *testing.T) {
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -14,7 +14,6 @@ import (
|
||||
type ListOptsBuilder interface {
|
||||
ToServerListQuery() (string, error)
|
||||
}
|
||||
|
||||
// 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 server attributes you want to see returned. Marker and Limit are used
|
||||
@@ -216,29 +215,22 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
|
||||
return res
|
||||
}
|
||||
|
||||
_, res.Err = client.Request("POST", listURL(client), gophercloud.RequestOpts{
|
||||
JSONResponse: &res.Body,
|
||||
JSONBody: reqBody,
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
_, res.Err = client.Post(listURL(client), reqBody, &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
// Delete requests that a server previously provisioned be removed from your account.
|
||||
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
|
||||
var res DeleteResult
|
||||
_, res.Err = client.Request("DELETE", deleteURL(client, id), gophercloud.RequestOpts{
|
||||
OkCodes: []int{204},
|
||||
})
|
||||
_, res.Err = client.Delete(deleteURL(client, id), nil)
|
||||
return res
|
||||
}
|
||||
|
||||
// Get requests details on a single server, by ID.
|
||||
func Get(client *gophercloud.ServiceClient, id string) GetResult {
|
||||
var result GetResult
|
||||
_, result.Err = client.Request("GET", getURL(client, id), gophercloud.RequestOpts{
|
||||
JSONResponse: &result.Body,
|
||||
OkCodes: []int{200, 203},
|
||||
_, result.Err = client.Get(getURL(client, id), &result.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200, 203},
|
||||
})
|
||||
return result
|
||||
}
|
||||
@@ -280,9 +272,9 @@ func (opts UpdateOpts) ToServerUpdateMap() map[string]interface{} {
|
||||
// Update requests that various attributes of the indicated server be changed.
|
||||
func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
|
||||
var result UpdateResult
|
||||
_, result.Err = client.Request("PUT", updateURL(client, id), gophercloud.RequestOpts{
|
||||
JSONResponse: &result.Body,
|
||||
JSONBody: opts.ToServerUpdateMap(),
|
||||
reqBody := opts.ToServerUpdateMap()
|
||||
_, result.Err = client.Put(updateURL(client, id), reqBody, &result.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return result
|
||||
}
|
||||
@@ -298,12 +290,7 @@ func ChangeAdminPassword(client *gophercloud.ServiceClient, id, newPassword stri
|
||||
req.ChangePassword.AdminPass = newPassword
|
||||
|
||||
var res ActionResult
|
||||
|
||||
_, res.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{
|
||||
JSONBody: req,
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
|
||||
_, res.Err = client.Post(actionURL(client, id), req, nil, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -367,15 +354,13 @@ func Reboot(client *gophercloud.ServiceClient, id string, how RebootMethod) Acti
|
||||
return res
|
||||
}
|
||||
|
||||
_, res.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{
|
||||
JSONBody: struct {
|
||||
C map[string]string `json:"reboot"`
|
||||
}{
|
||||
map[string]string{"type": string(how)},
|
||||
},
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
reqBody := struct {
|
||||
C map[string]string `json:"reboot"`
|
||||
}{
|
||||
map[string]string{"type": string(how)},
|
||||
}
|
||||
|
||||
_, res.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -468,12 +453,7 @@ func Rebuild(client *gophercloud.ServiceClient, id string, opts RebuildOptsBuild
|
||||
return result
|
||||
}
|
||||
|
||||
_, result.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{
|
||||
JSONBody: &reqBody,
|
||||
JSONResponse: &result.Body,
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
|
||||
_, result.Err = client.Post(actionURL(client, id), reqBody, &result.Body, nil)
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -514,11 +494,7 @@ func Resize(client *gophercloud.ServiceClient, id string, opts ResizeOptsBuilder
|
||||
return res
|
||||
}
|
||||
|
||||
_, res.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{
|
||||
JSONBody: reqBody,
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
|
||||
_, res.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -527,11 +503,10 @@ func Resize(client *gophercloud.ServiceClient, id string, opts ResizeOptsBuilder
|
||||
func ConfirmResize(client *gophercloud.ServiceClient, id string) ActionResult {
|
||||
var res ActionResult
|
||||
|
||||
_, res.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{
|
||||
JSONBody: map[string]interface{}{"confirmResize": nil},
|
||||
OkCodes: []int{204},
|
||||
reqBody := map[string]interface{}{"confirmResize": nil}
|
||||
_, res.Err = client.Post(actionURL(client, id), reqBody, nil, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{201, 202, 204},
|
||||
})
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -539,12 +514,8 @@ func ConfirmResize(client *gophercloud.ServiceClient, id string) ActionResult {
|
||||
// See Resize() for more details.
|
||||
func RevertResize(client *gophercloud.ServiceClient, id string) ActionResult {
|
||||
var res ActionResult
|
||||
|
||||
_, res.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{
|
||||
JSONBody: map[string]interface{}{"revertResize": nil},
|
||||
OkCodes: []int{202},
|
||||
})
|
||||
|
||||
reqBody := map[string]interface{}{"revertResize": nil}
|
||||
_, res.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -586,10 +557,8 @@ func Rescue(client *gophercloud.ServiceClient, id string, opts RescueOptsBuilder
|
||||
return result
|
||||
}
|
||||
|
||||
_, result.Err = client.Request("POST", actionURL(client, id), gophercloud.RequestOpts{
|
||||
JSONResponse: &result.Body,
|
||||
JSONBody: &reqBody,
|
||||
OkCodes: []int{200},
|
||||
_, result.Err = client.Post(actionURL(client, id), reqBody, &result.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
|
||||
return result
|
||||
@@ -625,9 +594,8 @@ func ResetMetadata(client *gophercloud.ServiceClient, id string, opts ResetMetad
|
||||
res.Err = err
|
||||
return res
|
||||
}
|
||||
_, res.Err = client.Request("PUT", metadataURL(client, id), gophercloud.RequestOpts{
|
||||
JSONBody: metadata,
|
||||
JSONResponse: &res.Body,
|
||||
_, res.Err = client.Put(metadataURL(client, id), metadata, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
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.
|
||||
func Metadata(client *gophercloud.ServiceClient, id string) GetMetadataResult {
|
||||
var res GetMetadataResult
|
||||
_, res.Err = client.Request("GET", metadataURL(client, id), gophercloud.RequestOpts{
|
||||
JSONResponse: &res.Body,
|
||||
})
|
||||
_, res.Err = client.Get(metadataURL(client, id), &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -657,9 +623,8 @@ func UpdateMetadata(client *gophercloud.ServiceClient, id string, opts UpdateMet
|
||||
res.Err = err
|
||||
return res
|
||||
}
|
||||
_, res.Err = client.Request("POST", metadataURL(client, id), gophercloud.RequestOpts{
|
||||
JSONBody: metadata,
|
||||
JSONResponse: &res.Body,
|
||||
_, res.Err = client.Post(metadataURL(client, id), metadata, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return res
|
||||
}
|
||||
@@ -695,9 +660,8 @@ func CreateMetadatum(client *gophercloud.ServiceClient, id string, opts Metadatu
|
||||
return res
|
||||
}
|
||||
|
||||
_, res.Err = client.Request("PUT", metadatumURL(client, id, key), gophercloud.RequestOpts{
|
||||
JSONBody: metadatum,
|
||||
JSONResponse: &res.Body,
|
||||
_, res.Err = client.Put(metadatumURL(client, id, key), metadatum, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
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.
|
||||
func DeleteMetadatum(client *gophercloud.ServiceClient, id, key string) 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,
|
||||
})
|
||||
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
|
||||
}
|
||||
|
@@ -277,3 +277,60 @@ func TestUpdateMetadata(t *testing.T) {
|
||||
th.AssertNoErr(t, err)
|
||||
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)
|
||||
}
|
||||
|
@@ -2,6 +2,9 @@ package servers
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"fmt"
|
||||
"path"
|
||||
"net/url"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/rackspace/gophercloud"
|
||||
@@ -74,6 +77,28 @@ type RescueResult struct {
|
||||
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.
|
||||
func (r RescueResult) Extract() (string, error) {
|
||||
if r.Err != nil {
|
||||
@@ -194,7 +219,6 @@ func ExtractServers(page pagination.Page) ([]Server, error) {
|
||||
|
||||
err = decoder.Decode(casted)
|
||||
|
||||
//err := mapstructure.Decode(casted, &response)
|
||||
return response.Servers, err
|
||||
}
|
||||
|
||||
@@ -272,3 +296,77 @@ func toMapFromString(from reflect.Kind, to reflect.Kind, data interface{}) (inte
|
||||
}
|
||||
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
|
||||
}
|
||||
|
@@ -37,3 +37,11 @@ func metadatumURL(client *gophercloud.ServiceClient, id, key string) string {
|
||||
func metadataURL(client *gophercloud.ServiceClient, id string) string {
|
||||
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)
|
||||
}
|
||||
|
87
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/endpoint_location.go
generated
vendored
87
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/endpoint_location.go
generated
vendored
@@ -5,9 +5,7 @@ import (
|
||||
|
||||
"github.com/rackspace/gophercloud"
|
||||
tokens2 "github.com/rackspace/gophercloud/openstack/identity/v2/tokens"
|
||||
endpoints3 "github.com/rackspace/gophercloud/openstack/identity/v3/endpoints"
|
||||
services3 "github.com/rackspace/gophercloud/openstack/identity/v3/services"
|
||||
"github.com/rackspace/gophercloud/pagination"
|
||||
tokens3 "github.com/rackspace/gophercloud/openstack/identity/v3/tokens"
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// V3EndpointURL discovers the endpoint URL for a specific service using multiple calls against
|
||||
// an identity v3 service endpoint. The specified EndpointOpts are used to identify a unique,
|
||||
// V3EndpointURL discovers the endpoint URL for a specific service from a Catalog acquired
|
||||
// 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
|
||||
// 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
|
||||
// deployment.
|
||||
func V3EndpointURL(v3Client *gophercloud.ServiceClient, opts gophercloud.EndpointOpts) (string, error) {
|
||||
// Discover the service we're interested in.
|
||||
var services = make([]services3.Service, 0, 1)
|
||||
servicePager := services3.List(v3Client, services3.ListOpts{ServiceType: opts.Type})
|
||||
err := servicePager.EachPage(func(page pagination.Page) (bool, error) {
|
||||
part, err := services3.ExtractServices(page)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, service := range part {
|
||||
if service.Name == opts.Name {
|
||||
services = append(services, service)
|
||||
func V3EndpointURL(catalog *tokens3.ServiceCatalog, opts gophercloud.EndpointOpts) (string, error) {
|
||||
// Extract Endpoints from the catalog entries that match the requested Type, Interface,
|
||||
// Name if provided, and Region if provided.
|
||||
var endpoints = make([]tokens3.Endpoint, 0, 1)
|
||||
for _, entry := range catalog.Entries {
|
||||
if (entry.Type == opts.Type) && (opts.Name == "" || entry.Name == opts.Name) {
|
||||
for _, endpoint := range entry.Endpoints {
|
||||
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)) &&
|
||||
(opts.Region == "" || endpoint.Region == opts.Region) {
|
||||
endpoints = append(endpoints, endpoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(endpoints) == 0 {
|
||||
return "", gophercloud.ErrEndpointNotFound
|
||||
}
|
||||
// Report an error if the options were ambiguous.
|
||||
if len(endpoints) > 1 {
|
||||
return "", fmt.Errorf("Discovered %d matching endpoints: %#v", len(endpoints), endpoints)
|
||||
}
|
||||
endpoint := endpoints[0]
|
||||
|
||||
return gophercloud.NormalizeURL(endpoint.URL), nil
|
||||
// Extract the URL from the matching Endpoint.
|
||||
for _, endpoint := range endpoints {
|
||||
return gophercloud.NormalizeURL(endpoint.URL), nil
|
||||
}
|
||||
|
||||
// Report an error if there were no matching endpoints.
|
||||
return "", gophercloud.ErrEndpointNotFound
|
||||
}
|
||||
|
217
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/endpoint_location_test.go
generated
vendored
217
Godeps/_workspace/src/github.com/rackspace/gophercloud/openstack/endpoint_location_test.go
generated
vendored
@@ -1,15 +1,13 @@
|
||||
package openstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/rackspace/gophercloud"
|
||||
tokens2 "github.com/rackspace/gophercloud/openstack/identity/v2/tokens"
|
||||
tokens3 "github.com/rackspace/gophercloud/openstack/identity/v3/tokens"
|
||||
th "github.com/rackspace/gophercloud/testhelper"
|
||||
fake "github.com/rackspace/gophercloud/testhelper/client"
|
||||
)
|
||||
|
||||
// Service catalog fixtures take too much vertical space!
|
||||
@@ -107,119 +105,124 @@ func TestV2EndpointBadAvailability(t *testing.T) {
|
||||
Region: "same",
|
||||
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) {
|
||||
// Mock the service query.
|
||||
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
|
||||
var catalog3 = tokens3.ServiceCatalog{
|
||||
Entries: []tokens3.CatalogEntry{
|
||||
tokens3.CatalogEntry{
|
||||
Type: "same",
|
||||
Name: "same",
|
||||
Endpoints: []tokens3.Endpoint{
|
||||
tokens3.Endpoint{
|
||||
ID: "1",
|
||||
Region: "same",
|
||||
Interface: "public",
|
||||
URL: "https://public.correct.com/",
|
||||
},
|
||||
"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
|
||||
}
|
||||
}
|
||||
`)
|
||||
})
|
||||
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",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestV3EndpointExact(t *testing.T) {
|
||||
th.SetupHTTP()
|
||||
defer th.TeardownHTTP()
|
||||
setupV3Responses(t)
|
||||
expectedURLs := map[gophercloud.Availability]string{
|
||||
gophercloud.AvailabilityPublic: "https://public.correct.com/",
|
||||
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",
|
||||
Name: "same",
|
||||
Region: "same",
|
||||
Availability: availability,
|
||||
})
|
||||
th.AssertNoErr(t, err)
|
||||
th.CheckEquals(t, expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestV3EndpointNone(t *testing.T) {
|
||||
_, err := V3EndpointURL(&catalog3, gophercloud.EndpointOpts{
|
||||
Type: "nope",
|
||||
Availability: gophercloud.AvailabilityPublic,
|
||||
})
|
||||
th.CheckEquals(t, gophercloud.ErrEndpointNotFound, err)
|
||||
}
|
||||
|
||||
func TestV3EndpointMultiple(t *testing.T) {
|
||||
_, err := V3EndpointURL(&catalog3, gophercloud.EndpointOpts{
|
||||
Type: "same",
|
||||
Region: "same",
|
||||
Availability: gophercloud.AvailabilityPublic,
|
||||
})
|
||||
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: gophercloud.AvailabilityPublic,
|
||||
Availability: "wat",
|
||||
})
|
||||
th.AssertNoErr(t, err)
|
||||
th.CheckEquals(t, actual, "https://correct:9000/")
|
||||
}
|
||||
|
||||
func TestV3EndpointNoService(t *testing.T) {
|
||||
th.SetupHTTP()
|
||||
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",
|
||||
Name: "same",
|
||||
Region: "same",
|
||||
Availability: gophercloud.AvailabilityPublic,
|
||||
})
|
||||
th.CheckEquals(t, gophercloud.ErrServiceNotFound, err)
|
||||
th.CheckEquals(t, "Unexpected availability in endpoint query: wat", err.Error())
|
||||
}
|
||||
|
@@ -19,11 +19,7 @@ func List(client *gophercloud.ServiceClient) pagination.Pager {
|
||||
// ID is a required argument.
|
||||
func AddUserRole(client *gophercloud.ServiceClient, tenantID, userID, roleID string) UserRoleResult {
|
||||
var result UserRoleResult
|
||||
|
||||
_, result.Err = client.Request("PUT", userRoleURL(client, tenantID, userID, roleID), gophercloud.RequestOpts{
|
||||
OkCodes: []int{200, 201},
|
||||
})
|
||||
|
||||
_, result.Err = client.Put(userRoleURL(client, tenantID, userID, roleID), nil, nil, nil)
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -32,10 +28,6 @@ func AddUserRole(client *gophercloud.ServiceClient, tenantID, userID, roleID str
|
||||
// tenant ID is a required argument.
|
||||
func DeleteUserRole(client *gophercloud.ServiceClient, tenantID, userID, roleID string) UserRoleResult {
|
||||
var result UserRoleResult
|
||||
|
||||
_, result.Err = client.Request("DELETE", userRoleURL(client, tenantID, userID, roleID), gophercloud.RequestOpts{
|
||||
OkCodes: []int{204},
|
||||
})
|
||||
|
||||
_, result.Err = client.Delete(userRoleURL(client, tenantID, userID, roleID), nil)
|
||||
return result
|
||||
}
|
||||
|
@@ -75,10 +75,8 @@ func Create(client *gophercloud.ServiceClient, auth AuthOptionsBuilder) CreateRe
|
||||
}
|
||||
|
||||
var result CreateResult
|
||||
_, result.Err = client.Request("POST", CreateURL(client), gophercloud.RequestOpts{
|
||||
JSONBody: &request,
|
||||
JSONResponse: &result.Body,
|
||||
OkCodes: []int{200, 203},
|
||||
_, result.Err = client.Post(CreateURL(client), request, &result.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200, 203},
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
@@ -90,10 +90,8 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
|
||||
return res
|
||||
}
|
||||
|
||||
_, res.Err = client.Request("POST", rootURL(client), gophercloud.RequestOpts{
|
||||
JSONResponse: &res.Body,
|
||||
JSONBody: reqBody,
|
||||
OkCodes: []int{200, 201},
|
||||
_, res.Err = client.Post(rootURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200, 201},
|
||||
})
|
||||
|
||||
return res
|
||||
@@ -102,12 +100,7 @@ func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateRes
|
||||
// Get requests details on a single user, either by ID.
|
||||
func Get(client *gophercloud.ServiceClient, id string) GetResult {
|
||||
var result GetResult
|
||||
|
||||
_, result.Err = client.Request("GET", ResourceURL(client, id), gophercloud.RequestOpts{
|
||||
JSONResponse: &result.Body,
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
|
||||
_, result.Err = client.Get(ResourceURL(client, id), &result.Body, nil)
|
||||
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.
|
||||
func Update(client *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) UpdateResult {
|
||||
var result UpdateResult
|
||||
|
||||
_, result.Err = client.Request("PUT", ResourceURL(client, id), gophercloud.RequestOpts{
|
||||
JSONResponse: &result.Body,
|
||||
JSONBody: opts.ToUserUpdateMap(),
|
||||
OkCodes: []int{200},
|
||||
reqBody := opts.ToUserUpdateMap()
|
||||
_, result.Err = client.Put(ResourceURL(client, id), reqBody, &result.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Delete is the operation responsible for permanently deleting an API user.
|
||||
func Delete(client *gophercloud.ServiceClient, id string) DeleteResult {
|
||||
var result DeleteResult
|
||||
|
||||
_, result.Err = client.Request("DELETE", ResourceURL(client, id), gophercloud.RequestOpts{
|
||||
OkCodes: []int{204},
|
||||
})
|
||||
|
||||
_, result.Err = client.Delete(ResourceURL(client, id), nil)
|
||||
return result
|
||||
}
|
||||
|
||||
|
@@ -56,11 +56,7 @@ func Create(client *gophercloud.ServiceClient, opts EndpointOpts) CreateResult {
|
||||
reqBody.Endpoint.Region = gophercloud.MaybeString(opts.Region)
|
||||
|
||||
var result CreateResult
|
||||
_, result.Err = client.Request("POST", listURL(client), gophercloud.RequestOpts{
|
||||
JSONBody: &reqBody,
|
||||
JSONResponse: &result.Body,
|
||||
OkCodes: []int{201},
|
||||
})
|
||||
_, result.Err = client.Post(listURL(client), reqBody, &result.Body, nil)
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -122,8 +118,6 @@ func Update(client *gophercloud.ServiceClient, endpointID string, opts EndpointO
|
||||
// Delete removes an endpoint from the service catalog.
|
||||
func Delete(client *gophercloud.ServiceClient, endpointID string) DeleteResult {
|
||||
var res DeleteResult
|
||||
_, res.Err = client.Request("DELETE", endpointURL(client, endpointID), gophercloud.RequestOpts{
|
||||
OkCodes: []int{204},
|
||||
})
|
||||
_, res.Err = client.Delete(endpointURL(client, endpointID), nil)
|
||||
return res
|
||||
}
|
||||
|
@@ -18,11 +18,7 @@ func Create(client *gophercloud.ServiceClient, serviceType string) CreateResult
|
||||
req := request{Type: serviceType}
|
||||
|
||||
var result CreateResult
|
||||
_, result.Err = client.Request("POST", listURL(client), gophercloud.RequestOpts{
|
||||
JSONBody: &req,
|
||||
JSONResponse: &result.Body,
|
||||
OkCodes: []int{201},
|
||||
})
|
||||
_, result.Err = client.Post(listURL(client), req, &result.Body, nil)
|
||||
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.
|
||||
func Get(client *gophercloud.ServiceClient, serviceID string) GetResult {
|
||||
var result GetResult
|
||||
_, result.Err = client.Request("GET", serviceURL(client, serviceID), gophercloud.RequestOpts{
|
||||
JSONResponse: &result.Body,
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
_, result.Err = client.Get(serviceURL(client, serviceID), &result.Body, nil)
|
||||
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.
|
||||
func Delete(client *gophercloud.ServiceClient, serviceID string) DeleteResult {
|
||||
var res DeleteResult
|
||||
_, res.Err = client.Request("DELETE", serviceURL(client, serviceID), gophercloud.RequestOpts{
|
||||
OkCodes: []int{204},
|
||||
})
|
||||
_, res.Err = client.Delete(serviceURL(client, serviceID), nil)
|
||||
return res
|
||||
}
|
||||
|
@@ -235,11 +235,7 @@ func Create(c *gophercloud.ServiceClient, options gophercloud.AuthOptions, scope
|
||||
|
||||
var result CreateResult
|
||||
var response *http.Response
|
||||
response, result.Err = c.Request("POST", tokenURL(c), gophercloud.RequestOpts{
|
||||
JSONBody: &req,
|
||||
JSONResponse: &result.Body,
|
||||
OkCodes: []int{201},
|
||||
})
|
||||
response, result.Err = c.Post(tokenURL(c), req, &result.Body, nil)
|
||||
if result.Err != nil {
|
||||
return result
|
||||
}
|
||||
@@ -251,10 +247,9 @@ func Create(c *gophercloud.ServiceClient, options gophercloud.AuthOptions, scope
|
||||
func Get(c *gophercloud.ServiceClient, token string) GetResult {
|
||||
var result GetResult
|
||||
var response *http.Response
|
||||
response, result.Err = c.Request("GET", tokenURL(c), gophercloud.RequestOpts{
|
||||
MoreHeaders: subjectTokenHeaders(c, token),
|
||||
JSONResponse: &result.Body,
|
||||
OkCodes: []int{200, 203},
|
||||
response, result.Err = c.Get(tokenURL(c), &result.Body, &gophercloud.RequestOpts{
|
||||
MoreHeaders: subjectTokenHeaders(c, token),
|
||||
OkCodes: []int{200, 203},
|
||||
})
|
||||
if result.Err != nil {
|
||||
return result
|
||||
@@ -279,9 +274,8 @@ func Validate(c *gophercloud.ServiceClient, token string) (bool, error) {
|
||||
// Revoke immediately makes specified token invalid.
|
||||
func Revoke(c *gophercloud.ServiceClient, token string) 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),
|
||||
OkCodes: []int{204},
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
@@ -7,13 +7,58 @@ import (
|
||||
"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.
|
||||
type commonResult struct {
|
||||
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) {
|
||||
return r.ExtractToken()
|
||||
}
|
||||
|
||||
// ExtractToken interprets a commonResult as a Token.
|
||||
func (r commonResult) ExtractToken() (*Token, error) {
|
||||
if r.Err != nil {
|
||||
return nil, r.Err
|
||||
}
|
||||
@@ -40,7 +85,28 @@ func (r commonResult) Extract() (*Token, error) {
|
||||
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 {
|
||||
commonResult
|
||||
}
|
||||
|
@@ -1,6 +1,10 @@
|
||||
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
|
||||
// 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.
|
||||
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()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -68,7 +68,7 @@ func ExtractUpdate(r networks.UpdateResult) (*NetworkExternal, error) {
|
||||
}
|
||||
|
||||
// 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.
|
||||
func ExtractList(page pagination.Page) ([]NetworkExternal, error) {
|
||||
var resp struct {
|
||||
|
@@ -139,21 +139,14 @@ func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
|
||||
return res
|
||||
}
|
||||
|
||||
_, res.Err = c.Request("POST", rootURL(c), gophercloud.RequestOpts{
|
||||
JSONBody: &reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{201},
|
||||
})
|
||||
_, res.Err = c.Post(rootURL(c), reqBody, &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
// Get retrieves a particular firewall based on its unique ID.
|
||||
func Get(c *gophercloud.ServiceClient, id string) GetResult {
|
||||
var res GetResult
|
||||
_, res.Err = c.Request("GET", resourceURL(c, id), gophercloud.RequestOpts{
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
_, res.Err = c.Get(resourceURL(c, id), &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -209,10 +202,8 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) Upd
|
||||
}
|
||||
|
||||
// Send request to API
|
||||
_, res.Err = c.Request("PUT", resourceURL(c, id), gophercloud.RequestOpts{
|
||||
JSONBody: &reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
_, res.Err = c.Put(resourceURL(c, id), reqBody, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
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.
|
||||
func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
|
||||
var res DeleteResult
|
||||
_, res.Err = c.Request("DELETE", resourceURL(c, id), gophercloud.RequestOpts{
|
||||
OkCodes: []int{204},
|
||||
})
|
||||
_, res.Err = c.Delete(resourceURL(c, id), nil)
|
||||
return res
|
||||
}
|
||||
|
@@ -128,21 +128,14 @@ func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
|
||||
return res
|
||||
}
|
||||
|
||||
_, res.Err = c.Request("POST", rootURL(c), gophercloud.RequestOpts{
|
||||
JSONBody: &reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{201},
|
||||
})
|
||||
_, res.Err = c.Post(rootURL(c), reqBody, &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
// Get retrieves a particular firewall policy based on its unique ID.
|
||||
func Get(c *gophercloud.ServiceClient, id string) GetResult {
|
||||
var res GetResult
|
||||
_, res.Err = c.Request("GET", resourceURL(c, id), gophercloud.RequestOpts{
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
_, res.Err = c.Get(resourceURL(c, id), &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -198,10 +191,8 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) Upd
|
||||
}
|
||||
|
||||
// Send request to API
|
||||
_, res.Err = c.Request("PUT", resourceURL(c, id), gophercloud.RequestOpts{
|
||||
JSONBody: &reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
_, res.Err = c.Put(resourceURL(c, id), reqBody, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
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.
|
||||
func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
|
||||
var res DeleteResult
|
||||
_, res.Err = c.Request("DELETE", resourceURL(c, id), gophercloud.RequestOpts{
|
||||
OkCodes: []int{204},
|
||||
})
|
||||
_, res.Err = c.Delete(resourceURL(c, id), nil)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -230,10 +219,8 @@ func InsertRule(c *gophercloud.ServiceClient, policyID, ruleID, beforeID, afterI
|
||||
|
||||
// Send request to API
|
||||
var res commonResult
|
||||
_, res.Err = c.Request("PUT", insertURL(c, policyID), gophercloud.RequestOpts{
|
||||
JSONBody: &reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
_, res.Err = c.Put(insertURL(c, policyID), reqBody, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return res.Err
|
||||
}
|
||||
@@ -249,10 +236,8 @@ func RemoveRule(c *gophercloud.ServiceClient, policyID, ruleID string) error {
|
||||
|
||||
// Send request to API
|
||||
var res commonResult
|
||||
_, res.Err = c.Request("PUT", removeURL(c, policyID), gophercloud.RequestOpts{
|
||||
JSONBody: &reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
_, res.Err = c.Put(removeURL(c, policyID), reqBody, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
return res.Err
|
||||
}
|
||||
|
@@ -163,21 +163,14 @@ func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult {
|
||||
return res
|
||||
}
|
||||
|
||||
_, res.Err = c.Request("POST", rootURL(c), gophercloud.RequestOpts{
|
||||
JSONBody: &reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{201},
|
||||
})
|
||||
_, res.Err = c.Post(rootURL(c), reqBody, &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
// Get retrieves a particular firewall rule based on its unique ID.
|
||||
func Get(c *gophercloud.ServiceClient, id string) GetResult {
|
||||
var res GetResult
|
||||
_, res.Err = c.Request("GET", resourceURL(c, id), gophercloud.RequestOpts{
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
_, res.Err = c.Get(resourceURL(c, id), &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -277,10 +270,8 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) Upd
|
||||
}
|
||||
|
||||
// Send request to API
|
||||
_, res.Err = c.Request("PUT", resourceURL(c, id), gophercloud.RequestOpts{
|
||||
JSONBody: &reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
_, res.Err = c.Put(resourceURL(c, id), reqBody, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
|
||||
return res
|
||||
@@ -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.
|
||||
func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
|
||||
var res DeleteResult
|
||||
_, res.Err = c.Request("DELETE", resourceURL(c, id), gophercloud.RequestOpts{
|
||||
OkCodes: []int{204},
|
||||
})
|
||||
_, res.Err = c.Delete(resourceURL(c, id), nil)
|
||||
return res
|
||||
}
|
||||
|
@@ -107,23 +107,14 @@ func Create(c *gophercloud.ServiceClient, opts CreateOpts) CreateResult {
|
||||
TenantID: opts.TenantID,
|
||||
}}
|
||||
|
||||
// Send request to API
|
||||
_, res.Err = c.Request("POST", rootURL(c), gophercloud.RequestOpts{
|
||||
JSONBody: &reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{201},
|
||||
})
|
||||
|
||||
_, res.Err = c.Post(rootURL(c), reqBody, &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
// Get retrieves a particular floating IP resource based on its unique ID.
|
||||
func Get(c *gophercloud.ServiceClient, id string) GetResult {
|
||||
var res GetResult
|
||||
_, res.Err = c.Request("GET", resourceURL(c, id), gophercloud.RequestOpts{
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
_, res.Err = c.Get(resourceURL(c, id), &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -159,10 +150,8 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResu
|
||||
|
||||
// Send request to API
|
||||
var res UpdateResult
|
||||
_, res.Err = c.Request("PUT", resourceURL(c, id), gophercloud.RequestOpts{
|
||||
JSONBody: &reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
_, res.Err = c.Put(resourceURL(c, id), reqBody, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
|
||||
return res
|
||||
@@ -173,8 +162,6 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResu
|
||||
// internal ports.
|
||||
func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
|
||||
var res DeleteResult
|
||||
_, res.Err = c.Request("DELETE", resourceURL(c, id), gophercloud.RequestOpts{
|
||||
OkCodes: []int{204},
|
||||
})
|
||||
_, res.Err = c.Delete(resourceURL(c, id), nil)
|
||||
return res
|
||||
}
|
||||
|
@@ -81,21 +81,14 @@ func Create(c *gophercloud.ServiceClient, opts CreateOpts) CreateResult {
|
||||
}
|
||||
|
||||
var res CreateResult
|
||||
_, res.Err = c.Request("POST", rootURL(c), gophercloud.RequestOpts{
|
||||
JSONBody: &reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{201},
|
||||
})
|
||||
_, res.Err = c.Post(rootURL(c), reqBody, &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
// Get retrieves a particular router based on its unique ID.
|
||||
func Get(c *gophercloud.ServiceClient, id string) GetResult {
|
||||
var res GetResult
|
||||
_, res.Err = c.Request("GET", resourceURL(c, id), gophercloud.RequestOpts{
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
_, res.Err = c.Get(resourceURL(c, id), &res.Body, nil)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -133,10 +126,8 @@ func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResu
|
||||
|
||||
// Send request to API
|
||||
var res UpdateResult
|
||||
_, res.Err = c.Request("PUT", resourceURL(c, id), gophercloud.RequestOpts{
|
||||
JSONBody: &reqBody,
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
_, res.Err = c.Put(resourceURL(c, id), reqBody, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
|
||||
return res
|
||||
@@ -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.
|
||||
func Delete(c *gophercloud.ServiceClient, id string) DeleteResult {
|
||||
var res DeleteResult
|
||||
_, res.Err = c.Request("DELETE", resourceURL(c, id), gophercloud.RequestOpts{
|
||||
OkCodes: []int{204},
|
||||
})
|
||||
_, res.Err = c.Delete(resourceURL(c, id), nil)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -197,10 +186,8 @@ func AddInterface(c *gophercloud.ServiceClient, id string, opts InterfaceOpts) I
|
||||
|
||||
body := request{SubnetID: opts.SubnetID, PortID: opts.PortID}
|
||||
|
||||
_, res.Err = c.Request("PUT", addInterfaceURL(c, id), gophercloud.RequestOpts{
|
||||
JSONBody: &body,
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
_, res.Err = c.Put(addInterfaceURL(c, id), body, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
|
||||
return res
|
||||
@@ -229,10 +216,8 @@ func RemoveInterface(c *gophercloud.ServiceClient, id string, opts InterfaceOpts
|
||||
|
||||
body := request{SubnetID: opts.SubnetID, PortID: opts.PortID}
|
||||
|
||||
_, res.Err = c.Request("PUT", removeInterfaceURL(c, id), gophercloud.RequestOpts{
|
||||
JSONBody: &body,
|
||||
JSONResponse: &res.Body,
|
||||
OkCodes: []int{200},
|
||||
_, res.Err = c.Put(removeInterfaceURL(c, id), body, &res.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200},
|
||||
})
|
||||
|
||||
return res
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user