Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 // Copyright 2013 Canonical Ltd. | 1 // Copyright 2013 Canonical Ltd. |
2 // Licensed under the AGPLv3, see LICENCE file for details. | 2 // Licensed under the AGPLv3, see LICENCE file for details. |
3 | 3 |
4 package api | 4 package api |
5 | 5 |
6 import ( | 6 import ( |
7 "encoding/base64" | 7 "encoding/base64" |
8 "encoding/json" | 8 "encoding/json" |
9 "fmt" | 9 "fmt" |
10 "io/ioutil" | 10 "io/ioutil" |
11 "net/http" | 11 "net/http" |
12 "net/url" | 12 "net/url" |
13 "os" | 13 "os" |
14 "time" | 14 "time" |
15 | 15 |
16 "code.google.com/p/go.net/websocket" | 16 "code.google.com/p/go.net/websocket" |
17 | 17 |
18 "launchpad.net/juju-core/charm" | 18 "launchpad.net/juju-core/charm" |
19 "launchpad.net/juju-core/constraints" | 19 "launchpad.net/juju-core/constraints" |
20 "launchpad.net/juju-core/instance" | 20 "launchpad.net/juju-core/instance" |
21 "launchpad.net/juju-core/juju/osenv" | |
22 "launchpad.net/juju-core/state/api/params" | 21 "launchpad.net/juju-core/state/api/params" |
23 "launchpad.net/juju-core/utils" | 22 "launchpad.net/juju-core/utils" |
24 "launchpad.net/juju-core/version" | 23 "launchpad.net/juju-core/version" |
25 ) | 24 ) |
26 | 25 |
27 // Client represents the client-accessible part of the state. | 26 // Client represents the client-accessible part of the state. |
28 type Client struct { | 27 type Client struct { |
29 st *State | 28 st *State |
30 } | 29 } |
31 | 30 |
(...skipping 489 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
521 } | 520 } |
522 | 521 |
523 // WatchDebugLog returns a ClientDebugLog reading the debug log message. | 522 // WatchDebugLog returns a ClientDebugLog reading the debug log message. |
524 // The filter allows to grep wanted lines out of the output, e.g. | 523 // The filter allows to grep wanted lines out of the output, e.g. |
525 // machines or units. The watching is started the given number of | 524 // machines or units. The watching is started the given number of |
526 // matching lines back in history. | 525 // matching lines back in history. |
527 func (c *Client) WatchDebugLog(lines int, filter string) (*ClientDebugLog, error ) { | 526 func (c *Client) WatchDebugLog(lines int, filter string) (*ClientDebugLog, error ) { |
528 cfg := c.st.websocketConfig | 527 cfg := c.st.websocketConfig |
529 // Prepare URL. | 528 // Prepare URL. |
530 attrs := url.Values{ | 529 attrs := url.Values{ |
531 » » "juju-home": {osenv.JujuHomeDir()}, | 530 » » "lines": {fmt.Sprintf("%d", lines)}, |
rog
2014/01/31 15:59:11
This doesn't seem quite right. Why are we sending
mue
2014/01/31 17:32:37
Sure there may be a way to change environ. But the
| |
532 » » "lines": {fmt.Sprintf("%d", lines)}, | 531 » » "filter": {filter}, |
533 » » "filter": {filter}, | |
534 } | 532 } |
535 cfg.Location = &url.URL{ | 533 cfg.Location = &url.URL{ |
536 Scheme: "wss", | 534 Scheme: "wss", |
537 Host: c.st.serverHostPort, | 535 Host: c.st.serverHostPort, |
538 Path: "/log", | 536 Path: "/log", |
539 RawQuery: attrs.Encode(), | 537 RawQuery: attrs.Encode(), |
540 } | 538 } |
541 cfg.Header = make(http.Header) | 539 cfg.Header = make(http.Header) |
542 setBasicAuth(cfg.Header, c.st.tag, c.st.password) | 540 setBasicAuth(cfg.Header, c.st.tag, c.st.password) |
543 | 541 |
544 wsConn, err := websocket.DialConfig(&cfg) | 542 wsConn, err := websocket.DialConfig(&cfg) |
545 if err != nil { | 543 if err != nil { |
546 return nil, err | 544 return nil, err |
547 } | 545 } |
548 return &ClientDebugLog{wsConn}, nil | 546 return &ClientDebugLog{wsConn}, nil |
549 } | 547 } |
550 | 548 |
551 // ClientDebugLog represents a stream of debug log messages. | 549 // ClientDebugLog represents a stream of debug log messages. |
552 type ClientDebugLog struct { | 550 type ClientDebugLog struct { |
553 wsConn *websocket.Conn | 551 wsConn *websocket.Conn |
554 } | 552 } |
555 | 553 |
556 // Close closes the log. | 554 // Close closes the log. |
557 func (c *ClientDebugLog) Close() error { | 555 func (c *ClientDebugLog) Close() error { |
558 return c.wsConn.Close() | 556 return c.wsConn.Close() |
559 } | 557 } |
560 | 558 |
561 // SetFilter sets the entity tags that apply to the filter. | 559 // SetFilter sets the filter regular expression. This |
dimitern
2014/01/31 17:02:29
s/the entity tags that apply to the filter/the fil
mue
2014/01/31 17:32:37
Will change.
mue
2014/02/02 20:11:54
Done.
| |
562 // This setting will not take place immediately - messages | 560 // setting will not take place immediately - messages |
563 // already in the pipeline will still be received. | 561 // already in the pipeline will still be received. |
564 func (c *ClientDebugLog) SetFilter(filter string) error { | 562 func (c *ClientDebugLog) SetFilter(filter string) error { |
565 » req := params.EntityLogRequest{Filter: filter} | 563 » req := params.DebugLogRequest{Filter: filter} |
566 if err := websocket.JSON.Send(c.wsConn, &req); err != nil { | 564 if err := websocket.JSON.Send(c.wsConn, &req); err != nil { |
567 return err | 565 return err |
568 } | 566 } |
569 return nil | 567 return nil |
570 } | 568 } |
571 | 569 |
572 // Read implements io.Reader.Read. | 570 // Read implements io.Reader.Read. |
573 func (c *ClientDebugLog) Read(buf []byte) (int, error) { | 571 func (c *ClientDebugLog) Read(buf []byte) (int, error) { |
574 return c.wsConn.Read(buf) | 572 return c.wsConn.Read(buf) |
575 } | 573 } |
576 | 574 |
577 // setBasicAuth sets the basic authentication of the passed header. | 575 // setBasicAuth creates an Authorization header for HTTP Basic |
dimitern
2014/01/31 17:02:29
// setBasicAuth creates an Authorization header fo
mue
2014/01/31 17:32:37
Please discuss with Roger. It's based on his draft
dimitern
2014/01/31 17:57:09
I'm just suggesting a more appropriate description
mue
2014/02/02 20:11:54
Done.
| |
576 // Authentication, using the given username and password. | |
578 func setBasicAuth(h http.Header, username, password string) { | 577 func setBasicAuth(h http.Header, username, password string) { |
579 h.Set("Authorization", "Basic "+basicAuth(username, password)) | 578 h.Set("Authorization", "Basic "+basicAuth(username, password)) |
580 } | 579 } |
581 | 580 |
582 // basicAuth is copied from net/http. | 581 // basicAuth is copied from net/http. |
583 // See 2 (end of page 4) http://www.ietf.org/rfc/rfc2617.txt | 582 // See 2 (end of page 4) http://www.ietf.org/rfc/rfc2617.txt |
584 // "To receive authorization, the client sends the userid and password, | 583 // "To receive authorization, the client sends the userid and password, |
585 // separated by a single colon (":") character, within a base64 | 584 // separated by a single colon (":") character, within a base64 |
586 // encoded string in the credentials." | 585 // encoded string in the credentials." |
587 // It is not meant to be urlencoded. | 586 // It is not meant to be urlencoded. |
588 func basicAuth(username, password string) string { | 587 func basicAuth(username, password string) string { |
589 auth := username + ":" + password | 588 auth := username + ":" + password |
590 return base64.StdEncoding.EncodeToString([]byte(auth)) | 589 return base64.StdEncoding.EncodeToString([]byte(auth)) |
591 } | 590 } |
LEFT | RIGHT |