Beispiel #1
0
// Send sends the given metrics to the collector service.
func (s *HttpSender) Send(metrics []*wireformat.MetricBatch) (*wireformat.Response, error) {
	b, err := json.Marshal(metrics)
	if err != nil {
		return nil, errors.Trace(err)
	}
	r := bytes.NewBuffer(b)
	t := utils.NewHttpTLSTransport(&tls.Config{RootCAs: metricsCertsPool})
	client := &http.Client{Transport: t}
	resp, err := client.Post(metricsHost, "application/json", r)
	if err != nil {
		return nil, errors.Trace(err)
	}
	if resp.StatusCode != http.StatusOK {
		return nil, errors.Errorf("failed to send metrics http %v", resp.StatusCode)
	}

	defer resp.Body.Close()
	respReader := json.NewDecoder(resp.Body)
	metricsResponse := wireformat.Response{}
	err = respReader.Decode(&metricsResponse)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return &metricsResponse, nil
}
Beispiel #2
0
func (b *backendSuite) tlsServerAndClient(c *gc.C) (client *http.Client, url, dataDir string) {
	listener, url, dataDir := startServerTLS(c)
	b.AddCleanup(func(*gc.C) { listener.Close() })
	caCerts := x509.NewCertPool()
	c.Assert(caCerts.AppendCertsFromPEM([]byte(coretesting.CACert)), jc.IsTrue)
	client = &http.Client{
		Transport: utils.NewHttpTLSTransport(&tls.Config{RootCAs: caCerts}),
	}
	return client, url, dataDir
}
Beispiel #3
0
// NewHTTPClient returns an HTTP client initialized based on State.
func (s *State) NewHTTPClient() *http.Client {
	httpclient := utils.GetValidatingHTTPClient()
	tlsconfig := tls.Config{
		RootCAs: s.certPool,
		// We want to be specific here (rather than just using "anything".
		// See commit 7fc118f015d8480dfad7831788e4b8c0432205e8 (PR 899).
		ServerName: "juju-apiserver",
	}
	httpclient.Transport = utils.NewHttpTLSTransport(&tlsconfig)
	return httpclient
}
Beispiel #4
0
// ClientTLS returns a storage object that will talk to the
// storage server at the given network address (see Serve),
// using TLS. The client is given an authentication key,
// which the server will verify for Put and Remove* operations.
func ClientTLS(addr string, caCertPEM string, authkey string) (storage.Storage, error) {
	logger.Debugf("using https storage at %q", addr)
	caCerts := x509.NewCertPool()
	if !caCerts.AppendCertsFromPEM([]byte(caCertPEM)) {
		return nil, errors.New("error adding CA certificate to pool")
	}
	return &localStorage{
		addr:    addr,
		authkey: authkey,
		client: &http.Client{
			Transport: utils.NewHttpTLSTransport(&tls.Config{RootCAs: caCerts}),
		},
	}, nil
}
Beispiel #5
0
// bakeryDo provides a function suitable for using in httpRequestParams.Do
// that will use the given http client (or utils.GetNonValidatingHTTPClient()
// if client is nil) and use the given getBakeryError function
// to translate errors in responses.
func bakeryDo(client *http.Client, getBakeryError func(*http.Response) error) func(*http.Request) (*http.Response, error) {
	bclient := httpbakery.NewClient()
	if client != nil {
		bclient.Client = client
	} else {
		// Configure the default client to skip verification/
		tlsConfig := utils.SecureTLSConfig()
		tlsConfig.InsecureSkipVerify = true
		bclient.Client.Transport = utils.NewHttpTLSTransport(tlsConfig)
	}
	return func(req *http.Request) (*http.Response, error) {
		var body io.ReadSeeker
		if req.Body != nil {
			body = req.Body.(io.ReadSeeker)
			req.Body = nil
		}
		return bclient.DoWithBodyAndCustomError(req, body, getBakeryError)
	}
}
Beispiel #6
0
// open is the unexported version of open that also includes
// an explicit clock instance argument.
func open(
	info *Info,
	opts DialOpts,
	clock clock.Clock,
) (Connection, error) {
	if err := info.Validate(); err != nil {
		return nil, errors.Annotate(err, "validating info for opening an API connection")
	}
	if clock == nil {
		return nil, errors.NotValidf("nil clock")
	}
	conn, tlsConfig, err := dialAPI(info, opts)
	if err != nil {
		return nil, errors.Trace(err)
	}

	client := rpc.NewConn(jsoncodec.NewWebsocket(conn), observer.None())
	client.Start()

	bakeryClient := opts.BakeryClient
	if bakeryClient == nil {
		bakeryClient = httpbakery.NewClient()
	} else {
		// Make a copy of the bakery client and its HTTP client
		c := *opts.BakeryClient
		bakeryClient = &c
		httpc := *bakeryClient.Client
		bakeryClient.Client = &httpc
	}
	apiHost := conn.Config().Location.Host
	// Technically when there's no CACert, we don't need this
	// machinery, because we could just use http.DefaultTransport
	// for everything, but it's easier just to leave it in place.
	bakeryClient.Client.Transport = &hostSwitchingTransport{
		primaryHost: apiHost,
		primary:     utils.NewHttpTLSTransport(tlsConfig),
		fallback:    http.DefaultTransport,
	}

	st := &state{
		client: client,
		conn:   conn,
		clock:  clock,
		addr:   apiHost,
		cookieURL: &url.URL{
			Scheme: "https",
			Host:   conn.Config().Location.Host,
			Path:   "/",
		},
		pingerFacadeVersion: facadeVersions["Pinger"],
		serverScheme:        "https",
		serverRootAddress:   conn.Config().Location.Host,
		// We populate the username and password before
		// login because, when doing HTTP requests, we'll want
		// to use the same username and password for authenticating
		// those. If login fails, we discard the connection.
		tag:          tagToString(info.Tag),
		password:     info.Password,
		macaroons:    info.Macaroons,
		nonce:        info.Nonce,
		tlsConfig:    tlsConfig,
		bakeryClient: bakeryClient,
		modelTag:     info.ModelTag,
	}
	if !info.SkipLogin {
		if err := st.Login(info.Tag, info.Password, info.Nonce, info.Macaroons); err != nil {
			conn.Close()
			return nil, errors.Trace(err)
		}
	}

	st.broken = make(chan struct{})
	st.closed = make(chan struct{})

	go (&monitor{
		clock:       clock,
		ping:        st.Ping,
		pingPeriod:  PingPeriod,
		pingTimeout: pingTimeout,
		closed:      st.closed,
		dead:        client.Dead(),
		broken:      st.broken,
	}).run()
	return st, nil
}
Beispiel #7
0
// This unexported open method is used both directly above in the Open
// function, and also the OpenWithVersion function below to explicitly cause
// the API server to think that the client is older than it really is.
func open(
	info *Info,
	opts DialOpts,
	loginFunc func(st *state, tag names.Tag, pwd, nonce string, ms []macaroon.Slice) error,
) (Connection, error) {

	if err := info.Validate(); err != nil {
		return nil, errors.Annotate(err, "validating info for opening an API connection")
	}
	conn, tlsConfig, err := connectWebsocket(info, opts)
	if err != nil {
		return nil, errors.Trace(err)
	}

	client := rpc.NewConn(jsoncodec.NewWebsocket(conn), nil)
	client.Start()

	bakeryClient := opts.BakeryClient
	if bakeryClient == nil {
		bakeryClient = httpbakery.NewClient()
	} else {
		// Make a copy of the bakery client and its
		// HTTP client
		c := *opts.BakeryClient
		bakeryClient = &c
		httpc := *bakeryClient.Client
		bakeryClient.Client = &httpc
	}
	apiHost := conn.Config().Location.Host
	bakeryClient.Client.Transport = &hostSwitchingTransport{
		primaryHost: apiHost,
		primary:     utils.NewHttpTLSTransport(tlsConfig),
		fallback:    http.DefaultTransport,
	}

	st := &state{
		client: client,
		conn:   conn,
		addr:   apiHost,
		cookieURL: &url.URL{
			Scheme: "https",
			Host:   conn.Config().Location.Host,
			Path:   "/",
		},
		serverScheme:      "https",
		serverRootAddress: conn.Config().Location.Host,
		// why are the contents of the tag (username and password) written into the
		// state structure BEFORE login ?!?
		tag:          tagToString(info.Tag),
		password:     info.Password,
		macaroons:    info.Macaroons,
		nonce:        info.Nonce,
		tlsConfig:    tlsConfig,
		bakeryClient: bakeryClient,
	}
	if !info.SkipLogin {
		if err := loginFunc(st, info.Tag, info.Password, info.Nonce, info.Macaroons); err != nil {
			conn.Close()
			return nil, err
		}
	}
	st.broken = make(chan struct{})
	st.closed = make(chan struct{})
	go st.heartbeatMonitor()
	return st, nil
}