OLD | NEW |
1 package api | 1 package api |
2 | 2 |
3 import ( | 3 import ( |
4 "code.google.com/p/go.net/websocket" | 4 "code.google.com/p/go.net/websocket" |
| 5 "crypto/tls" |
| 6 "crypto/x509" |
5 "errors" | 7 "errors" |
6 "fmt" | 8 "fmt" |
| 9 "launchpad.net/juju-core/cert" |
7 ) | 10 ) |
8 | 11 |
9 type State struct { | 12 type State struct { |
10 conn *websocket.Conn | 13 conn *websocket.Conn |
11 } | 14 } |
12 | 15 |
| 16 // Info encapsulates information about a server holding juju state and |
| 17 // can be used to make a connection to it. |
13 type Info struct { | 18 type Info struct { |
| 19 // Addr holds the address of the state server. |
14 Addr string | 20 Addr string |
| 21 |
| 22 // CACert holds the CA certificate that will be used |
| 23 // to validate the state server's certificate, in PEM format. |
| 24 CACert []byte |
15 } | 25 } |
16 | 26 |
17 func Open(info *Info) (*State, error) { | 27 func Open(info *Info) (*State, error) { |
18 » conn, err := websocket.Dial("ws://"+info.Addr+"/", "", "http://localhost
/") | 28 » // TODO what does "origin" really mean, and is localhost always ok? |
| 29 » cfg, err := websocket.NewConfig("wss://"+info.Addr+"/", "http://localhos
t/") |
19 if err != nil { | 30 if err != nil { |
20 return nil, err | 31 return nil, err |
21 } | 32 } |
| 33 pool := x509.NewCertPool() |
| 34 xcert, err := cert.ParseCert(info.CACert) |
| 35 if err != nil { |
| 36 return nil, err |
| 37 } |
| 38 pool.AddCert(xcert) |
| 39 cfg.TlsConfig = &tls.Config{ |
| 40 RootCAs: pool, |
| 41 ServerName: "anything", |
| 42 } |
| 43 conn, err := websocket.DialConfig(cfg) |
| 44 if err != nil { |
| 45 return nil, err |
| 46 } |
22 return &State{ | 47 return &State{ |
23 conn: conn, | 48 conn: conn, |
24 }, nil | 49 }, nil |
25 } | 50 } |
26 | 51 |
27 func (s *State) Close() error { | 52 func (s *State) Close() error { |
28 return s.conn.Close() | 53 return s.conn.Close() |
29 } | 54 } |
30 | 55 |
31 // Request is a placeholder for an arbitrary operation in the state API. | 56 // Request is a placeholder for an arbitrary operation in the state API. |
32 // Currently it simply returns the instance id of the machine with the | 57 // Currently it simply returns the instance id of the machine with the |
33 // id given by the request. | 58 // id given by the request. |
34 func (s *State) Request(req string) (string, error) { | 59 func (s *State) Request(req string) (string, error) { |
35 err := websocket.JSON.Send(s.conn, rpcRequest{req}) | 60 err := websocket.JSON.Send(s.conn, rpcRequest{req}) |
36 if err != nil { | 61 if err != nil { |
37 return "", fmt.Errorf("cannot send request: %v", err) | 62 return "", fmt.Errorf("cannot send request: %v", err) |
38 } | 63 } |
39 var resp rpcResponse | 64 var resp rpcResponse |
40 err = websocket.JSON.Receive(s.conn, &resp) | 65 err = websocket.JSON.Receive(s.conn, &resp) |
41 if err != nil { | 66 if err != nil { |
42 return "", fmt.Errorf("cannot receive response: %v", err) | 67 return "", fmt.Errorf("cannot receive response: %v", err) |
43 } | 68 } |
44 if resp.Error != "" { | 69 if resp.Error != "" { |
45 return "", errors.New(resp.Error) | 70 return "", errors.New(resp.Error) |
46 } | 71 } |
47 return resp.Response, nil | 72 return resp.Response, nil |
48 } | 73 } |
OLD | NEW |