Merge pull request #484 from pratikmallya/fix_gc_client
[rfr]Make client return error on JSON decoding error
diff --git a/openstack/networking/v2/extensions/security/groups/requests.go b/openstack/networking/v2/extensions/security/groups/requests.go
index b55fb5d..2712ac1 100644
--- a/openstack/networking/v2/extensions/security/groups/requests.go
+++ b/openstack/networking/v2/extensions/security/groups/requests.go
@@ -45,6 +45,9 @@
// Required. Human-readable name for the VIP. Does not have to be unique.
Name string
+ // Required for admins. Indicates the owner of the VIP.
+ TenantID string
+
// Optional. Describes the security group.
Description string
}
@@ -62,6 +65,7 @@
type secgroup struct {
Name string `json:"name"`
+ TenantID string `json:"tenant_id,omitempty"`
Description string `json:"description,omitempty"`
}
@@ -71,6 +75,7 @@
reqBody := request{SecGroup: secgroup{
Name: opts.Name,
+ TenantID: opts.TenantID,
Description: opts.Description,
}}
diff --git a/openstack/networking/v2/extensions/security/rules/requests.go b/openstack/networking/v2/extensions/security/rules/requests.go
index 0b2d10b..a80ceb3 100644
--- a/openstack/networking/v2/extensions/security/rules/requests.go
+++ b/openstack/networking/v2/extensions/security/rules/requests.go
@@ -99,6 +99,9 @@
// attribute matches the specified IP prefix as the source IP address of the
// IP packet.
RemoteIPPrefix string
+
+ // Required for admins. Indicates the owner of the VIP.
+ TenantID string
}
// Create is an operation which provisions a new security group with default
@@ -133,6 +136,7 @@
Protocol string `json:"protocol,omitempty"`
RemoteGroupID string `json:"remote_group_id,omitempty"`
RemoteIPPrefix string `json:"remote_ip_prefix,omitempty"`
+ TenantID string `json:"tenant_id,omitempty"`
}
type request struct {
@@ -148,6 +152,7 @@
Protocol: opts.Protocol,
RemoteGroupID: opts.RemoteGroupID,
RemoteIPPrefix: opts.RemoteIPPrefix,
+ TenantID: opts.TenantID,
}}
_, res.Err = c.Post(rootURL(c), reqBody, &res.Body, nil)
diff --git a/openstack/networking/v2/subnets/requests.go b/openstack/networking/v2/subnets/requests.go
index 2368bf5..6cde048 100644
--- a/openstack/networking/v2/subnets/requests.go
+++ b/openstack/networking/v2/subnets/requests.go
@@ -202,10 +202,10 @@
if opts.GatewayIP != "" {
s["gateway_ip"] = opts.GatewayIP
}
- if len(opts.DNSNameservers) != 0 {
+ if opts.DNSNameservers != nil {
s["dns_nameservers"] = opts.DNSNameservers
}
- if len(opts.HostRoutes) != 0 {
+ if opts.HostRoutes != nil {
s["host_routes"] = opts.HostRoutes
}
diff --git a/openstack/networking/v2/subnets/results.go b/openstack/networking/v2/subnets/results.go
index 1910f17..77b956a 100644
--- a/openstack/networking/v2/subnets/results.go
+++ b/openstack/networking/v2/subnets/results.go
@@ -55,8 +55,8 @@
// HostRoute represents a route that should be used by devices with IPs from
// a subnet (not including local subnet route).
type HostRoute struct {
- DestinationCIDR string `json:"destination"`
- NextHop string `json:"nexthop"`
+ DestinationCIDR string `mapstructure:"destination" json:"destination"`
+ NextHop string `mapstructure:"nexthop" json:"nexthop"`
}
// Subnet represents a subnet. See package documentation for a top-level
diff --git a/openstack/networking/v2/subnets/results_test.go b/openstack/networking/v2/subnets/results_test.go
new file mode 100644
index 0000000..d404838
--- /dev/null
+++ b/openstack/networking/v2/subnets/results_test.go
@@ -0,0 +1,54 @@
+package subnets
+
+import (
+ "encoding/json"
+ "github.com/rackspace/gophercloud"
+ th "github.com/rackspace/gophercloud/testhelper"
+ "testing"
+)
+
+func TestHostRoute(t *testing.T) {
+ sejson := []byte(`
+ {"subnet": {
+ "name": "test-subnet",
+ "enable_dhcp": false,
+ "network_id": "3e66c41e-cbbd-4019-9aab-740b7e4150a0",
+ "tenant_id": "f86e123198cf42d19c8854c5f80c2f06",
+ "dns_nameservers": [],
+ "gateway_ip": "172.16.0.1",
+ "ipv6_ra_mode": null,
+ "allocation_pools": [
+ {
+ "start": "172.16.0.2",
+ "end": "172.16.255.254"
+ }
+ ],
+ "host_routes": [
+ {
+ "destination": "172.20.1.0/24",
+ "nexthop": "172.16.0.2"
+ }
+ ],
+ "ip_version": 4,
+ "ipv6_address_mode": null,
+ "cidr": "172.16.0.0/16",
+ "id": "6dcaa873-7115-41af-9ef5-915f73636e43",
+ "subnetpool_id": null
+ }}
+`)
+
+ var dejson interface{}
+ err := json.Unmarshal(sejson, &dejson)
+ if err != nil {
+ t.Fatalf("%s", err)
+ }
+
+ resp := commonResult{gophercloud.Result{Body: dejson}}
+ subnet, err := resp.Extract()
+ if err != nil {
+ t.Fatalf("%s", err)
+ }
+ route := subnet.HostRoutes[0]
+ th.AssertEquals(t, route.NextHop, "172.16.0.2")
+ th.AssertEquals(t, route.DestinationCIDR, "172.20.1.0/24")
+}
diff --git a/openstack/orchestration/v1/stackevents/fixtures.go b/openstack/orchestration/v1/stackevents/fixtures.go
index 016ae00..235787a 100644
--- a/openstack/orchestration/v1/stackevents/fixtures.go
+++ b/openstack/orchestration/v1/stackevents/fixtures.go
@@ -67,7 +67,7 @@
"events": [
{
"resource_name": "hello_world",
- "event_time": "2015-02-05T21:33:11Z",
+ "event_time": "2015-02-05T21:33:11",
"links": [
{
"href": "http://166.78.160.107:8004/v1/98606384f58d4ad0b3db7d0d779549ac/stacks/postman_stack/5f57cff9-93fc-424e-9f78-df0515e7f48b/resources/hello_world/events/06feb26f-9298-4a9b-8749-9d770e5d577a",
@@ -90,7 +90,7 @@
},
{
"resource_name": "hello_world",
- "event_time": "2015-02-05T21:33:27Z",
+ "event_time": "2015-02-05T21:33:27",
"links": [
{
"href": "http://166.78.160.107:8004/v1/98606384f58d4ad0b3db7d0d779549ac/stacks/postman_stack/5f57cff9-93fc-424e-9f78-df0515e7f48b/resources/hello_world/events/93940999-7d40-44ae-8de4-19624e7b8d18",
@@ -184,7 +184,7 @@
"events": [
{
"resource_name": "hello_world",
- "event_time": "2015-02-05T21:33:11Z",
+ "event_time": "2015-02-05T21:33:11",
"links": [
{
"href": "http://166.78.160.107:8004/v1/98606384f58d4ad0b3db7d0d779549ac/stacks/postman_stack/5f57cff9-93fc-424e-9f78-df0515e7f48b/resources/hello_world/events/06feb26f-9298-4a9b-8749-9d770e5d577a",
@@ -207,7 +207,7 @@
},
{
"resource_name": "hello_world",
- "event_time": "2015-02-05T21:33:27Z",
+ "event_time": "2015-02-05T21:33:27",
"links": [
{
"href": "http://166.78.160.107:8004/v1/98606384f58d4ad0b3db7d0d779549ac/stacks/postman_stack/5f57cff9-93fc-424e-9f78-df0515e7f48b/resources/hello_world/events/93940999-7d40-44ae-8de4-19624e7b8d18",
@@ -309,7 +309,7 @@
"events": [
{
"resource_name": "hello_world",
- "event_time": "2015-02-05T21:33:11Z",
+ "event_time": "2015-02-05T21:33:11",
"links": [
{
"href": "http://166.78.160.107:8004/v1/98606384f58d4ad0b3db7d0d779549ac/stacks/postman_stack/5f57cff9-93fc-424e-9f78-df0515e7f48b/resources/hello_world/events/06feb26f-9298-4a9b-8749-9d770e5d577a",
@@ -332,7 +332,7 @@
},
{
"resource_name": "hello_world",
- "event_time": "2015-02-05T21:33:27Z",
+ "event_time": "2015-02-05T21:33:27",
"links": [
{
"href": "http://166.78.160.107:8004/v1/98606384f58d4ad0b3db7d0d779549ac/stacks/postman_stack/5f57cff9-93fc-424e-9f78-df0515e7f48b/resources/hello_world/events/93940999-7d40-44ae-8de4-19624e7b8d18",
@@ -408,7 +408,7 @@
{
"event":{
"resource_name": "hello_world",
- "event_time": "2015-02-05T21:33:27Z",
+ "event_time": "2015-02-05T21:33:27",
"links": [
{
"href": "http://166.78.160.107:8004/v1/98606384f58d4ad0b3db7d0d779549ac/stacks/postman_stack/5f57cff9-93fc-424e-9f78-df0515e7f48b/resources/hello_world/events/93940999-7d40-44ae-8de4-19624e7b8d18",
diff --git a/openstack/orchestration/v1/stackevents/results.go b/openstack/orchestration/v1/stackevents/results.go
index 3c8f1da..cf9e240 100644
--- a/openstack/orchestration/v1/stackevents/results.go
+++ b/openstack/orchestration/v1/stackevents/results.go
@@ -57,7 +57,7 @@
for i, eventRaw := range events {
event := eventRaw.(map[string]interface{})
if date, ok := event["event_time"]; ok && date != nil {
- t, err := time.Parse(time.RFC3339, date.(string))
+ t, err := time.Parse(gophercloud.STACK_TIME_FMT, date.(string))
if err != nil {
return nil, err
}
@@ -121,7 +121,7 @@
for i, eventRaw := range events {
event := eventRaw.(map[string]interface{})
if date, ok := event["event_time"]; ok && date != nil {
- t, err := time.Parse(time.RFC3339, date.(string))
+ t, err := time.Parse(gophercloud.STACK_TIME_FMT, date.(string))
if err != nil {
return nil, err
}
@@ -161,7 +161,7 @@
event := r.Body.(map[string]interface{})["event"].(map[string]interface{})
if date, ok := event["event_time"]; ok && date != nil {
- t, err := time.Parse(time.RFC3339, date.(string))
+ t, err := time.Parse(gophercloud.STACK_TIME_FMT, date.(string))
if err != nil {
return nil, err
}
diff --git a/openstack/orchestration/v1/stackresources/fixtures.go b/openstack/orchestration/v1/stackresources/fixtures.go
index 0b930f4..c3c3d3f 100644
--- a/openstack/orchestration/v1/stackresources/fixtures.go
+++ b/openstack/orchestration/v1/stackresources/fixtures.go
@@ -53,7 +53,7 @@
],
"logical_resource_id": "hello_world",
"resource_status_reason": "state changed",
- "updated_time": "2015-02-05T21:33:11Z",
+ "updated_time": "2015-02-05T21:33:11",
"required_by": [],
"resource_status": "CREATE_IN_PROGRESS",
"physical_resource_id": "49181cd6-169a-4130-9455-31185bbfc5bf",
@@ -117,7 +117,7 @@
],
"logical_resource_id": "hello_world",
"resource_status_reason": "state changed",
- "updated_time": "2015-02-05T21:33:11Z",
+ "updated_time": "2015-02-05T21:33:11",
"required_by": [],
"resource_status": "CREATE_IN_PROGRESS",
"physical_resource_id": "49181cd6-169a-4130-9455-31185bbfc5bf",
@@ -188,7 +188,7 @@
],
"logical_resource_id": "wordpress_instance",
"resource_status": "CREATE_COMPLETE",
- "updated_time": "2014-12-10T18:34:35Z",
+ "updated_time": "2014-12-10T18:34:35",
"required_by": [],
"resource_status_reason": "state changed",
"physical_resource_id": "00e3a2fe-c65d-403c-9483-4db9930dd194",
diff --git a/openstack/orchestration/v1/stackresources/results.go b/openstack/orchestration/v1/stackresources/results.go
index ea84db5..df79d58 100644
--- a/openstack/orchestration/v1/stackresources/results.go
+++ b/openstack/orchestration/v1/stackresources/results.go
@@ -48,7 +48,7 @@
for i, resourceRaw := range resources {
resource := resourceRaw.(map[string]interface{})
if date, ok := resource["updated_time"]; ok && date != nil {
- t, err := time.Parse(time.RFC3339, date.(string))
+ t, err := time.Parse(gophercloud.STACK_TIME_FMT, date.(string))
if err != nil {
return nil, err
}
@@ -109,7 +109,7 @@
for i, resourceRaw := range resources {
resource := resourceRaw.(map[string]interface{})
if date, ok := resource["updated_time"]; ok && date != nil {
- t, err := time.Parse(time.RFC3339, date.(string))
+ t, err := time.Parse(gophercloud.STACK_TIME_FMT, date.(string))
if err != nil {
return nil, err
}
@@ -143,7 +143,7 @@
resource := r.Body.(map[string]interface{})["resource"].(map[string]interface{})
if date, ok := resource["updated_time"]; ok && date != nil {
- t, err := time.Parse(time.RFC3339, date.(string))
+ t, err := time.Parse(gophercloud.STACK_TIME_FMT, date.(string))
if err != nil {
return nil, err
}
diff --git a/openstack/orchestration/v1/stacks/fixtures.go b/openstack/orchestration/v1/stacks/fixtures.go
index 6d3e959..3a621da 100644
--- a/openstack/orchestration/v1/stacks/fixtures.go
+++ b/openstack/orchestration/v1/stacks/fixtures.go
@@ -95,7 +95,7 @@
],
"stack_status_reason": "Stack CREATE completed successfully",
"stack_name": "postman_stack",
- "creation_time": "2015-02-03T20:07:39Z",
+ "creation_time": "2015-02-03T20:07:39",
"updated_time": null,
"stack_status": "CREATE_COMPLETE",
"id": "16ef0584-4458-41eb-87c8-0dc8d5f66c87"
@@ -110,8 +110,8 @@
],
"stack_status_reason": "Stack successfully updated",
"stack_name": "gophercloud-test-stack-2",
- "creation_time": "2014-12-11T17:39:16Z",
- "updated_time": "2014-12-11T17:40:37Z",
+ "creation_time": "2014-12-11T17:39:16",
+ "updated_time": "2014-12-11T17:40:37",
"stack_status": "UPDATE_COMPLETE",
"id": "db6977b2-27aa-4775-9ae7-6213212d4ada"
}
@@ -181,7 +181,7 @@
"stack_status_reason": "Stack CREATE completed successfully",
"stack_name": "postman_stack",
"outputs": [],
- "creation_time": "2015-02-03T20:07:39Z",
+ "creation_time": "2015-02-03T20:07:39",
"links": [
{
"href": "http://166.76.160.117:8004/v1/98606384f58d4ad0b3db7d0d779549ac/stacks/postman_stack/16ef0584-4458-41eb-87c8-0dc8d5f66c87",
diff --git a/openstack/orchestration/v1/stacks/results.go b/openstack/orchestration/v1/stacks/results.go
index 04d3f8e..dca06e4 100644
--- a/openstack/orchestration/v1/stacks/results.go
+++ b/openstack/orchestration/v1/stacks/results.go
@@ -100,7 +100,7 @@
thisStack := (rawStacks[i]).(map[string]interface{})
if t, ok := thisStack["creation_time"].(string); ok && t != "" {
- creationTime, err := time.Parse(time.RFC3339, t)
+ creationTime, err := time.Parse(gophercloud.STACK_TIME_FMT, t)
if err != nil {
return res.Stacks, err
}
@@ -108,7 +108,7 @@
}
if t, ok := thisStack["updated_time"].(string); ok && t != "" {
- updatedTime, err := time.Parse(time.RFC3339, t)
+ updatedTime, err := time.Parse(gophercloud.STACK_TIME_FMT, t)
if err != nil {
return res.Stacks, err
}
@@ -170,7 +170,7 @@
b := r.Body.(map[string]interface{})["stack"].(map[string]interface{})
if date, ok := b["creation_time"]; ok && date != nil {
- t, err := time.Parse(time.RFC3339, date.(string))
+ t, err := time.Parse(gophercloud.STACK_TIME_FMT, date.(string))
if err != nil {
return nil, err
}
@@ -178,7 +178,7 @@
}
if date, ok := b["updated_time"]; ok && date != nil {
- t, err := time.Parse(time.RFC3339, date.(string))
+ t, err := time.Parse(gophercloud.STACK_TIME_FMT, date.(string))
if err != nil {
return nil, err
}
@@ -249,7 +249,7 @@
b := r.Body.(map[string]interface{})["stack"].(map[string]interface{})
if date, ok := b["creation_time"]; ok && date != nil {
- t, err := time.Parse(time.RFC3339, date.(string))
+ t, err := time.Parse(gophercloud.STACK_TIME_FMT, date.(string))
if err != nil {
return nil, err
}
@@ -257,7 +257,7 @@
}
if date, ok := b["updated_time"]; ok && date != nil {
- t, err := time.Parse(time.RFC3339, date.(string))
+ t, err := time.Parse(gophercloud.STACK_TIME_FMT, date.(string))
if err != nil {
return nil, err
}
diff --git a/results.go b/results.go
index 7c86ce4..27fd1b6 100644
--- a/results.go
+++ b/results.go
@@ -113,6 +113,9 @@
// RFC3339Milli describes a common time format used by some API responses.
const RFC3339Milli = "2006-01-02T15:04:05.999999Z"
+// Time format used in cloud orchestration
+const STACK_TIME_FMT = "2006-01-02T15:04:05"
+
/*
Link is an internal type to be used in packages of collection resources that are
paginated in a certain way.