-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #142 from mhilton/012-add-websocket-handlers
Add websocket endpoint The endpoint doesn't do much yet, it just returns a "no such model" error.
- Loading branch information
Showing
5 changed files
with
179 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// Copyright 2016 Canonical Ltd. | ||
|
||
// Package jujuapi implements API endpoints for the juju API. | ||
package jujuapi | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/juju/httprequest" | ||
"github.com/julienschmidt/httprouter" | ||
|
||
"github.com/CanonicalLtd/jem/internal/jem" | ||
"github.com/CanonicalLtd/jem/internal/jemserver" | ||
) | ||
|
||
func NewAPIHandler(jp *jem.Pool, sp jemserver.Params) ([]httprequest.Handler, error) { | ||
return []httprequest.Handler{ | ||
newWebSocketHandler(jp), | ||
}, nil | ||
} | ||
|
||
func newWebSocketHandler(jp *jem.Pool) httprequest.Handler { | ||
return httprequest.Handler{ | ||
Method: "GET", | ||
Path: "/model/:modeluuid/api", | ||
Handle: func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { | ||
j := jp.JEM() | ||
defer j.Close() | ||
wsServer := newWSServer(j, p.ByName("modeluuid")) | ||
wsServer.ServeHTTP(w, r) | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// Copyright 2015 Canonical Ltd. | ||
|
||
package jujuapi_test | ||
|
||
import ( | ||
"testing" | ||
|
||
jujutesting "github.com/juju/juju/testing" | ||
) | ||
|
||
func TestPackage(t *testing.T) { | ||
jujutesting.MgoTestPackage(t) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// Copyright 2016 Canonical Ltd. | ||
|
||
package jujuapi | ||
|
||
import ( | ||
"github.com/juju/juju/apiserver/common" | ||
"github.com/juju/juju/apiserver/observer" | ||
"github.com/juju/juju/rpc" | ||
"github.com/juju/juju/rpc/jsoncodec" | ||
"github.com/juju/juju/rpc/rpcreflect" | ||
"golang.org/x/net/websocket" | ||
|
||
"github.com/CanonicalLtd/jem/internal/jem" | ||
) | ||
|
||
// newWSServer creates a new websocket server suitible for handling the api for modelUUID. | ||
func newWSServer(jem *jem.JEM, modelUUID string) websocket.Server { | ||
hnd := wsHandler{ | ||
jem: jem, | ||
modelUUID: modelUUID, | ||
} | ||
return websocket.Server{ | ||
Handler: hnd.handle, | ||
} | ||
} | ||
|
||
// wsHandler is a handler for a particular websocket connection. | ||
type wsHandler struct { | ||
jem *jem.JEM | ||
modelUUID string | ||
} | ||
|
||
// handle handles the connection. | ||
func (h *wsHandler) handle(wsConn *websocket.Conn) { | ||
codec := jsoncodec.NewWebsocket(wsConn) | ||
conn := rpc.NewConn(codec, observer.None()) | ||
|
||
// TODO(mhilton) serve something useful on this connection. | ||
err := common.UnknownModelError(h.modelUUID) | ||
conn.ServeFinder(&errRoot{err}, serverError) | ||
conn.Start() | ||
select { | ||
case <-conn.Dead(): | ||
} | ||
conn.Close() | ||
} | ||
|
||
func serverError(err error) error { | ||
if err := common.ServerError(err); err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
// errRoot implements the API that a client first sees | ||
// when connecting to the API. It exposes the same API as initialRoot, except | ||
// it returns the requested error when the client makes any request. | ||
type errRoot struct { | ||
err error | ||
} | ||
|
||
// FindMethod conforms to the same API as initialRoot, but we'll always return (nil, err) | ||
func (r *errRoot) FindMethod(rootName string, version int, methodName string) (rpcreflect.MethodCaller, error) { | ||
return nil, r.err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// Copyright 2016 Canonical Ltd. | ||
|
||
package jujuapi_test | ||
|
||
import ( | ||
"bytes" | ||
"encoding/pem" | ||
"net/http/httptest" | ||
"net/url" | ||
|
||
"github.com/juju/juju/api" | ||
jc "github.com/juju/testing/checkers" | ||
gc "gopkg.in/check.v1" | ||
"gopkg.in/juju/names.v2" | ||
|
||
"github.com/CanonicalLtd/jem/internal/apitest" | ||
) | ||
|
||
type websocketSuite struct { | ||
apitest.Suite | ||
wsServer *httptest.Server | ||
connection api.Connection | ||
} | ||
|
||
var _ = gc.Suite(&websocketSuite{}) | ||
|
||
func (s *websocketSuite) SetUpTest(c *gc.C) { | ||
s.Suite.SetUpTest(c) | ||
s.wsServer = httptest.NewTLSServer(s.JEMSrv) | ||
} | ||
|
||
func (s *websocketSuite) TearDownTest(c *gc.C) { | ||
s.wsServer.Close() | ||
s.Suite.TearDownTest(c) | ||
} | ||
|
||
func (s *websocketSuite) TestUnknownModel(c *gc.C) { | ||
conn := s.open(c, &api.Info{ | ||
ModelTag: names.NewModelTag("00000000-0000-0000-0000-000000000000"), | ||
SkipLogin: true, | ||
}) | ||
defer conn.Close() | ||
err := conn.Login(names.NewUserTag("test-user"), "", "", nil) | ||
c.Assert(err, gc.ErrorMatches, `unknown model: "00000000-0000-0000-0000-000000000000" \(not found\)`) | ||
} | ||
|
||
func (s *websocketSuite) open(c *gc.C, info *api.Info) api.Connection { | ||
inf := *info | ||
u, err := url.Parse(s.wsServer.URL) | ||
c.Assert(err, jc.ErrorIsNil) | ||
inf.Addrs = []string{ | ||
u.Host, | ||
} | ||
w := new(bytes.Buffer) | ||
err = pem.Encode(w, &pem.Block{ | ||
Type: "CERTIFICATE", | ||
Bytes: s.wsServer.TLS.Certificates[0].Certificate[0], | ||
}) | ||
c.Assert(err, jc.ErrorIsNil) | ||
inf.CACert = w.String() | ||
conn, err := api.Open(&inf, api.DialOpts{ | ||
InsecureSkipVerify: true, | ||
}) | ||
c.Assert(err, jc.ErrorIsNil) | ||
return conn | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters