Skip to content

Commit 8d28646

Browse files
authored
Merge pull request #1586 from dougm/rest-session
vapi: return info with current session query
2 parents 1777a85 + ca3763e commit 8d28646

File tree

3 files changed

+93
-15
lines changed

3 files changed

+93
-15
lines changed

vapi/rest/client.go

+31-4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"io/ioutil"
2626
"net/http"
2727
"net/url"
28+
"time"
2829

2930
"github.com/vmware/govmomi/vapi/internal"
3031
"github.com/vmware/govmomi/vim25"
@@ -36,6 +37,13 @@ type Client struct {
3637
*soap.Client
3738
}
3839

40+
// Session information
41+
type Session struct {
42+
User string `json:"user"`
43+
Created time.Time `json:"created_time"`
44+
LastAccessed time.Time `json:"last_accessed_time"`
45+
}
46+
3947
// LocalizableMessage represents a localizable error
4048
type LocalizableMessage struct {
4149
Args []string `json:"args,omitempty"`
@@ -64,6 +72,14 @@ func (c *Client) WithSigner(ctx context.Context, s Signer) context.Context {
6472
return context.WithValue(ctx, signerContext{}, s)
6573
}
6674

75+
type statusError struct {
76+
res *http.Response
77+
}
78+
79+
func (e *statusError) Error() string {
80+
return fmt.Sprintf("%s %s: %s", e.res.Request.Method, e.res.Request.URL, e.res.Status)
81+
}
82+
6783
// Do sends the http.Request, decoding resBody if provided.
6884
func (c *Client) Do(ctx context.Context, req *http.Request, resBody interface{}) error {
6985
switch req.Method {
@@ -90,7 +106,7 @@ func (c *Client) Do(ctx context.Context, req *http.Request, resBody interface{})
90106
}
91107
return fmt.Errorf("%s: %s", res.Status, bytes.TrimSpace(detail))
92108
default:
93-
return fmt.Errorf("%s %s: %s", req.Method, req.URL, res.Status)
109+
return &statusError{res}
94110
}
95111

96112
if resBody == nil {
@@ -129,10 +145,21 @@ func (c *Client) LoginByToken(ctx context.Context) error {
129145
return c.Login(ctx, nil)
130146
}
131147

132-
// Get returns an error if the current session is invalid.
133-
func (c *Client) Get(ctx context.Context) error {
148+
// Session returns the user's current session.
149+
// Nil is returned if the session is not authenticated.
150+
func (c *Client) Session(ctx context.Context) (*Session, error) {
151+
var s Session
134152
req := internal.URL(c, internal.SessionPath).WithAction("get").Request(http.MethodPost)
135-
return c.Do(ctx, req, nil)
153+
err := c.Do(ctx, req, &s)
154+
if err != nil {
155+
if e, ok := err.(*statusError); ok {
156+
if e.res.StatusCode == http.StatusUnauthorized {
157+
return nil, nil
158+
}
159+
}
160+
return nil, err
161+
}
162+
return &s, nil
136163
}
137164

138165
// Logout deletes the current session.

vapi/rest/client_test.go

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
Copyright (c) 2019 VMware, Inc. All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package rest_test
18+
19+
import (
20+
"context"
21+
"testing"
22+
23+
"github.com/vmware/govmomi/simulator"
24+
"github.com/vmware/govmomi/vapi/rest"
25+
"github.com/vmware/govmomi/vim25"
26+
27+
_ "github.com/vmware/govmomi/vapi/simulator"
28+
)
29+
30+
func TestSession(t *testing.T) {
31+
simulator.Test(func(ctx context.Context, vc *vim25.Client) {
32+
c := rest.NewClient(vc)
33+
34+
session, err := c.Session(ctx)
35+
if err != nil {
36+
t.Fatal(err)
37+
}
38+
39+
if session != nil {
40+
t.Fatal("expected nil session")
41+
}
42+
43+
err = c.Login(ctx, simulator.DefaultLogin)
44+
if err != nil {
45+
t.Fatal(err)
46+
}
47+
48+
session, err = c.Session(ctx)
49+
if err != nil {
50+
t.Fatal(err)
51+
}
52+
53+
if session == nil {
54+
t.Fatal("expected non-nil session")
55+
}
56+
})
57+
}

vapi/simulator/simulator.go

+5-11
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,6 @@ import (
5252
vim "github.com/vmware/govmomi/vim25/types"
5353
)
5454

55-
type session struct {
56-
User string `json:"user"`
57-
Created time.Time `json:"created_time"`
58-
LastAccessed time.Time `json:"last_accessed_time"`
59-
}
60-
6155
type item struct {
6256
*library.Item
6357
File []library.File
@@ -87,7 +81,7 @@ type handler struct {
8781
Category map[string]*tags.Category
8882
Tag map[string]*tags.Tag
8983
Association map[string]map[internal.AssociatedObject]bool
90-
Session map[string]*session
84+
Session map[string]*rest.Session
9185
Library map[string]content
9286
Update map[string]update
9387
Download map[string]download
@@ -110,7 +104,7 @@ func New(u *url.URL, settings []vim.BaseOptionValue) (string, http.Handler) {
110104
Category: make(map[string]*tags.Category),
111105
Tag: make(map[string]*tags.Tag),
112106
Association: make(map[string]map[internal.AssociatedObject]bool),
113-
Session: make(map[string]*session),
107+
Session: make(map[string]*rest.Session),
114108
Library: make(map[string]content),
115109
Update: make(map[string]update),
116110
Download: make(map[string]download),
@@ -332,8 +326,8 @@ func (s *handler) session(w http.ResponseWriter, r *http.Request) {
332326
switch r.Method {
333327
case http.MethodPost:
334328
if s.action(r) != "" {
335-
if _, ok := s.Session[id]; ok {
336-
s.ok(w)
329+
if session, ok := s.Session[id]; ok {
330+
s.ok(w, session)
337331
} else {
338332
w.WriteHeader(http.StatusUnauthorized)
339333
}
@@ -346,7 +340,7 @@ func (s *handler) session(w http.ResponseWriter, r *http.Request) {
346340
}
347341
id = uuid.New().String()
348342
now := time.Now()
349-
s.Session[id] = &session{user, now, now}
343+
s.Session[id] = &rest.Session{User: user, Created: now, LastAccessed: now}
350344
http.SetCookie(w, &http.Cookie{
351345
Name: internal.SessionCookieName,
352346
Value: id,

0 commit comments

Comments
 (0)