change all time fields to have type time.Time (#190)
* add Volume.Unmarshal
* add volumetenants.VolumeExt.Unmarshal
* create servers.Server time.Time fields
* json.Unmarshal can correctly handle time.RFC3339 (Server time fields)
* add v3 Token UnmarshalJSON method
* check for empty string when unmarshaling time
* add Member UnmarshalJSON
* v3 tokens.Token ExtractInto
* v3 trust.Trust UnmarshalJSON
* time.Time fields swift response objects
* time.Time fields for orchestration response objects
* time.Time fields for shared file systems response objects
* if we don't use pointers for the custom time fields, we don't need to check if they're nil
* style guide fixes: 'r' for receiver, 's' for struct
* remove unnecessary pointers from UnmarshalJSON methods
diff --git a/openstack/compute/v2/servers/results.go b/openstack/compute/v2/servers/results.go
index a23923a..c121a6b 100644
--- a/openstack/compute/v2/servers/results.go
+++ b/openstack/compute/v2/servers/results.go
@@ -7,6 +7,7 @@
"fmt"
"net/url"
"path"
+ "time"
"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/pagination"
@@ -101,12 +102,12 @@
}
// 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
+func (r CreateImageResult) ExtractImageID() (string, error) {
+ if r.Err != nil {
+ return "", r.Err
}
// Get the image id from the header
- u, err := url.ParseRequestURI(res.Header.Get("Location"))
+ u, err := url.ParseRequestURI(r.Header.Get("Location"))
if err != nil {
return "", err
}
@@ -137,26 +138,27 @@
// Name contains the human-readable name for the server.
Name string `json:"name"`
// Updated and Created contain ISO-8601 timestamps of when the state of the server last changed, and when it was created.
- Updated string
- Created string
- HostID string
+ Updated time.Time `json:"updated"`
+ Created time.Time `json:"created"`
+ HostID string `json:"hostid"`
// Status contains the current operational status of the server, such as IN_PROGRESS or ACTIVE.
- Status string
+ Status string `json:"status"`
// Progress ranges from 0..100.
// A request made against the server completes only once Progress reaches 100.
- Progress int
+ Progress int `json:"progress"`
// AccessIPv4 and AccessIPv6 contain the IP addresses of the server, suitable for remote access for administration.
- AccessIPv4, AccessIPv6 string
+ AccessIPv4 string `json:"accessIPv4"`
+ AccessIPv6 string `json:"accessIPv6"`
// Image refers to a JSON object, which itself indicates the OS image used to deploy the server.
- Image map[string]interface{}
+ Image map[string]interface{} `json:"-"`
// Flavor refers to a JSON object, which itself indicates the hardware configuration of the deployed server.
- Flavor map[string]interface{}
+ Flavor map[string]interface{} `json:"flavor"`
// Addresses includes a list of all IP addresses assigned to the server, keyed by pool.
- Addresses map[string]interface{}
+ Addresses map[string]interface{} `json:"addresses"`
// Metadata includes a list of all user-specified key-value pairs attached to the server.
- Metadata map[string]string
+ Metadata map[string]string `json:"metadata"`
// Links includes HTTP references to the itself, useful for passing along to other APIs that might want a server reference.
- Links []interface{}
+ Links []interface{} `json:"links"`
// KeyName indicates which public key was injected into the server on launch.
KeyName string `json:"key_name"`
// AdminPass will generally be empty (""). However, it will contain the administrative password chosen when provisioning a new server without a set AdminPass setting in the first place.
@@ -166,30 +168,30 @@
SecurityGroups []map[string]interface{} `json:"security_groups"`
}
-func (s *Server) UnmarshalJSON(b []byte) error {
+func (r *Server) UnmarshalJSON(b []byte) error {
type tmp Server
- var server *struct {
+ var s struct {
tmp
- Image interface{}
+ Image interface{} `json:"image"`
}
- err := json.Unmarshal(b, &server)
+ err := json.Unmarshal(b, &s)
if err != nil {
return err
}
- *s = Server(server.tmp)
+ *r = Server(s.tmp)
- switch t := server.Image.(type) {
+ switch t := s.Image.(type) {
case map[string]interface{}:
- s.Image = t
+ r.Image = t
case string:
switch t {
case "":
- s.Image = nil
+ r.Image = nil
}
}
- return nil
+ return err
}
// ServerPage abstracts the raw results of making a List() request against the API.
@@ -200,17 +202,17 @@
}
// IsEmpty returns true if a page contains no Server results.
-func (page ServerPage) IsEmpty() (bool, error) {
- servers, err := ExtractServers(page)
- return len(servers) == 0, err
+func (r ServerPage) IsEmpty() (bool, error) {
+ s, err := ExtractServers(r)
+ return len(s) == 0, err
}
// NextPageURL uses the response's embedded link reference to navigate to the next page of results.
-func (page ServerPage) NextPageURL() (string, error) {
+func (r ServerPage) NextPageURL() (string, error) {
var s struct {
Links []gophercloud.Link `json:"servers_links"`
}
- err := page.ExtractInto(&s)
+ err := r.ExtractInto(&s)
if err != nil {
return "", err
}
diff --git a/openstack/compute/v2/servers/testing/fixtures.go b/openstack/compute/v2/servers/testing/fixtures.go
index adedb46..40d5ed2 100644
--- a/openstack/compute/v2/servers/testing/fixtures.go
+++ b/openstack/compute/v2/servers/testing/fixtures.go
@@ -4,6 +4,7 @@
"fmt"
"net/http"
"testing"
+ "time"
"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
@@ -304,10 +305,12 @@
`
var (
+ herpTimeCreated, _ = time.Parse(time.RFC3339, "2014-09-25T13:10:02Z")
+ herpTimeUpdated, _ = time.Parse(time.RFC3339, "2014-09-25T13:10:10Z")
// ServerHerp is a Server struct that should correspond to the first result in ServerListBody.
ServerHerp = servers.Server{
Status: "ACTIVE",
- Updated: "2014-09-25T13:10:10Z",
+ Updated: herpTimeUpdated,
HostID: "29d3c8c896a45aa4c34e52247875d7fefc3d94bbcc9f622b5d204362",
Addresses: map[string]interface{}{
"private": []interface{}{
@@ -350,7 +353,7 @@
ID: "ef079b0c-e610-4dfb-b1aa-b49f07ac48e5",
UserID: "9349aff8be7545ac9d2f1d00999a23cd",
Name: "herp",
- Created: "2014-09-25T13:10:02Z",
+ Created: herpTimeCreated,
TenantID: "fcad67a6189847c4aecfa3c81a05783b",
Metadata: map[string]string{},
SecurityGroups: []map[string]interface{}{
@@ -360,10 +363,12 @@
},
}
+ derpTimeCreated, _ = time.Parse(time.RFC3339, "2014-09-25T13:04:41Z")
+ derpTimeUpdated, _ = time.Parse(time.RFC3339, "2014-09-25T13:04:49Z")
// ServerDerp is a Server struct that should correspond to the second server in ServerListBody.
ServerDerp = servers.Server{
Status: "ACTIVE",
- Updated: "2014-09-25T13:04:49Z",
+ Updated: derpTimeUpdated,
HostID: "29d3c8c896a45aa4c34e52247875d7fefc3d94bbcc9f622b5d204362",
Addresses: map[string]interface{}{
"private": []interface{}{
@@ -406,7 +411,7 @@
ID: "9e5476bd-a4ec-4653-93d6-72c93aa682ba",
UserID: "9349aff8be7545ac9d2f1d00999a23cd",
Name: "derp",
- Created: "2014-09-25T13:04:41Z",
+ Created: derpTimeCreated,
TenantID: "fcad67a6189847c4aecfa3c81a05783b",
Metadata: map[string]string{},
SecurityGroups: []map[string]interface{}{
@@ -416,10 +421,12 @@
},
}
+ merpTimeCreated, _ = time.Parse(time.RFC3339, "2014-09-25T13:04:41Z")
+ merpTimeUpdated, _ = time.Parse(time.RFC3339, "2014-09-25T13:04:49Z")
// ServerMerp is a Server struct that should correspond to the second server in ServerListBody.
ServerMerp = servers.Server{
Status: "ACTIVE",
- Updated: "2014-09-25T13:04:49Z",
+ Updated: merpTimeUpdated,
HostID: "29d3c8c896a45aa4c34e52247875d7fefc3d94bbcc9f622b5d204362",
Addresses: map[string]interface{}{
"private": []interface{}{
@@ -454,7 +461,7 @@
ID: "9e5476bd-a4ec-4653-93d6-72c93aa682bb",
UserID: "9349aff8be7545ac9d2f1d00999a23cd",
Name: "merp",
- Created: "2014-09-25T13:04:41Z",
+ Created: merpTimeCreated,
TenantID: "fcad67a6189847c4aecfa3c81a05783b",
Metadata: map[string]string{},
SecurityGroups: []map[string]interface{}{