Beispiel #1
0
func dialLogsinkAPI(apiInfo *api.Info) (*websocket.Conn, error) {
	// TODO(mjs) Most of this should be extracted to be shared for
	// connections to both /log (debuglog) and /logsink.
	header := utils.BasicAuthHeader(apiInfo.Tag.String(), apiInfo.Password)
	header.Set("X-Juju-Nonce", apiInfo.Nonce)
	conn, err := api.Connect(apiInfo, "/logsink", header, api.DialOpts{})
	if err != nil {
		return nil, errors.Annotate(err, "failed to connect to logsink API")
	}

	// Read the initial error and translate to a real error.
	// Read up to the first new line character. We can't use bufio here as it
	// reads too much from the reader.
	line := make([]byte, 4096)
	n, err := conn.Read(line)
	if err != nil {
		return nil, errors.Annotate(err, "unable to read initial response")
	}
	line = line[0:n]

	var errResult params.ErrorResult
	err = json.Unmarshal(line, &errResult)
	if err != nil {
		return nil, errors.Annotate(err, "unable to unmarshal initial response")
	}
	if errResult.Error != nil {
		return nil, errors.Annotatef(err, "initial server error")
	}

	return conn, nil
}
Beispiel #2
0
func (s *apiclientSuite) TestConnectToEnvWithPathTail(c *gc.C) {
	info := s.APIInfo(c)
	conn, err := api.Connect(info, "/log", nil, api.DialOpts{})
	c.Assert(err, jc.ErrorIsNil)
	defer conn.Close()
	assertConnAddrForEnv(c, conn, info.Addrs[0], s.State.EnvironUUID(), "/log")
}
Beispiel #3
0
func (s *apiclientSuite) TestConnectToRoot(c *gc.C) {
	info := s.APIInfo(c)
	info.EnvironTag = names.NewEnvironTag("")
	conn, err := api.Connect(info, "", nil, api.DialOpts{})
	c.Assert(err, jc.ErrorIsNil)
	defer conn.Close()
	assertConnAddrForRoot(c, conn, info.Addrs[0])
}
Beispiel #4
0
func (s *apiclientSuite) TestConnectMultiple(c *gc.C) {
	// Create a socket that proxies to the API server.
	info := s.APIInfo(c)
	serverAddr := info.Addrs[0]
	server, err := net.Dial("tcp", serverAddr)
	c.Assert(err, jc.ErrorIsNil)
	defer server.Close()
	listener, err := net.Listen("tcp", "127.0.0.1:0")
	c.Assert(err, jc.ErrorIsNil)
	defer listener.Close()
	go func() {
		for {
			client, err := listener.Accept()
			if err != nil {
				return
			}
			go io.Copy(client, server)
			go io.Copy(server, client)
		}
	}()

	// Check that we can use the proxy to connect.
	proxyAddr := listener.Addr().String()
	info.Addrs = []string{proxyAddr}
	conn, err := api.Connect(info, "/api", nil, api.DialOpts{})
	c.Assert(err, jc.ErrorIsNil)
	conn.Close()
	assertConnAddrForEnv(c, conn, proxyAddr, s.State.EnvironUUID(), "/api")

	// Now break Addrs[0], and ensure that Addrs[1]
	// is successfully connected to.
	info.Addrs = []string{proxyAddr, serverAddr}
	listener.Close()
	conn, err = api.Connect(info, "/api", nil, api.DialOpts{})
	c.Assert(err, jc.ErrorIsNil)
	conn.Close()
	assertConnAddrForEnv(c, conn, serverAddr, s.State.EnvironUUID(), "/api")
}
Beispiel #5
0
func (s *apiclientSuite) TestConnectWithHeader(c *gc.C) {
	var seenCfg *websocket.Config
	fakeNewDialer := func(cfg *websocket.Config, _ api.DialOpts) func(<-chan struct{}) (io.Closer, error) {
		seenCfg = cfg
		return func(<-chan struct{}) (io.Closer, error) {
			return nil, errors.New("fake")
		}
	}
	s.PatchValue(api.NewWebsocketDialerPtr, fakeNewDialer)

	header := utils.BasicAuthHeader("foo", "bar")
	api.Connect(s.APIInfo(c), "", header, api.DialOpts{}) // Return values not important here
	c.Assert(seenCfg, gc.NotNil)
	c.Assert(seenCfg.Header, gc.DeepEquals, header)
}
Beispiel #6
0
func (s *apiclientSuite) TestConnectMultipleError(c *gc.C) {
	listener, err := net.Listen("tcp", "127.0.0.1:0")
	c.Assert(err, jc.ErrorIsNil)
	defer listener.Close()
	go func() {
		for {
			client, err := listener.Accept()
			if err != nil {
				return
			}
			client.Close()
		}
	}()
	info := s.APIInfo(c)
	addr := listener.Addr().String()
	info.Addrs = []string{addr, addr, addr}
	_, err = api.Connect(info, "/api", nil, api.DialOpts{})
	c.Assert(err, gc.ErrorMatches, `unable to connect to "wss://.*/environment/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/api"`)
}
Beispiel #7
0
func (s *apiclientSuite) TestConnectPrefersLocalhostIfPresent(c *gc.C) {
	// Create a socket that proxies to the API server though our localhost address.
	info := s.APIInfo(c)
	serverAddr := info.Addrs[0]
	server, err := net.Dial("tcp", serverAddr)
	c.Assert(err, jc.ErrorIsNil)
	defer server.Close()
	listener, err := net.Listen("tcp", "localhost:0")
	c.Assert(err, jc.ErrorIsNil)
	defer listener.Close()
	go func() {
		for {
			client, err := listener.Accept()
			if err != nil {
				return
			}
			go io.Copy(client, server)
			go io.Copy(server, client)
		}
	}()

	// Check that we are using our working address to connect
	listenerAddress := listener.Addr().String()
	// listenAddress contains the actual IP address, but APIHostPorts
	// is going to report localhost, so just find the port
	_, port, err := net.SplitHostPort(listenerAddress)
	c.Check(err, jc.ErrorIsNil)
	portNum, err := strconv.Atoi(port)
	c.Check(err, jc.ErrorIsNil)
	expectedHostPort := fmt.Sprintf("localhost:%d", portNum)
	info.Addrs = []string{"fakeAddress:1", "fakeAddress:1", expectedHostPort}
	conn, err := api.Connect(info, "/api", nil, api.DialOpts{})
	c.Assert(err, jc.ErrorIsNil)
	defer conn.Close()
	assertConnAddrForEnv(c, conn, expectedHostPort, s.State.EnvironUUID(), "/api")
}
Beispiel #8
0
func (s *apiclientSuite) TestConnectRequiresTailStartsWithSlash(c *gc.C) {
	_, err := api.Connect(s.APIInfo(c), "foo", nil, api.DialOpts{})
	c.Assert(err, gc.ErrorMatches, `path tail must start with "/"`)
}