func dialAPI(ctx context.Context, info *Info, opts0 DialOpts) (*dialResult, error) {
	if len(info.Addrs) == 0 {
		return nil, errors.New("no API addresses to connect to")
	}

	addrs := info.Addrs[:]

	if info.Proxier != nil {
		if err := info.Proxier.Start(); err != nil {
			return nil, errors.Annotate(err, "starting proxy for api connection")
		}
		logger.Debugf("starting proxier for connection")

		switch p := info.Proxier.(type) {
		case jujuproxy.TunnelProxier:
			logger.Debugf("tunnel proxy in use at %s on port %s", p.Host(), p.Port())
			addrs = []string{
				fmt.Sprintf("%s:%s", p.Host(), p.Port()),
			}
		default:
			info.Proxier.Stop()
			return nil, errors.New("unknown proxier provided")
		}
	}

	opts := dialOpts{
		DialOpts:    opts0,
		sniHostName: info.SNIHostName,
	}
	if info.CACert != "" {
		certPool, err := CreateCertPool(info.CACert)
		if err != nil {
			return nil, errors.Annotate(err, "cert pool creation failed")
		}
		opts.certPool = certPool
	}
	// Set opts.DialWebsocket and opts.Clock here rather than in open because
	// some tests call dialAPI directly.
	if opts.DialWebsocket == nil {
		opts.DialWebsocket = gorillaDialWebsocket
	}
	if opts.IPAddrResolver == nil {
		opts.IPAddrResolver = net.DefaultResolver
	}
	if opts.Clock == nil {
		opts.Clock = clock.WallClock
	}
	if opts.DNSCache == nil {
		opts.DNSCache = nopDNSCache{}
	}
	path, err := apiPath(info.ModelTag, "/api")
	if err != nil {
		return nil, errors.Trace(err)
	}

	// Encourage load balancing by shuffling controller addresses.
	rand.Shuffle(len(addrs), func(i, j int) { addrs[i], addrs[j] = addrs[j], addrs[i] })

	if opts.VerifyCA != nil {
		if err := verifyCAMulti(ctx, addrs, &opts); err != nil {
			return nil, err
		}
	}

	if opts.DialTimeout > 0 {
		ctx1, cancel := utils.ContextWithTimeout(ctx, opts.Clock, opts.DialTimeout)
		defer cancel()
		ctx = ctx1
	}
	dialInfo, err := dialWebsocketMulti(ctx, addrs, path, opts)
	if err != nil {
		return nil, errors.Trace(err)
	}
	logger.Infof("connection established to %q", dialInfo.urlStr)
	dialInfo.proxier = info.Proxier
	return dialInfo, nil
}
// dialAPI establishes a websocket connection to the RPC
// API websocket on the API server using Info. If multiple API addresses
// are provided in Info they will be tried concurrently - the first successful
// connection wins.
//
// It also returns the TLS configuration that it has derived from the Info.
dialAPI establishes a websocket connection to the RPC
API websocket on the API server using Info. If multiple API addresses
are provided in Info they will be tried concurrently - the first successful
connection wins.

It also returns the TLS configuration that it has derived from the Info.
// dialAPI establishes a websocket connection to the RPC // API websocket on the API server using Info . If multiple API addresses // are provided in Info they will be tried concurrently - the first successful // connection wins . // // It also returns the TLS configuration that it has derived from the Info .
func dialAPI(ctx context.Context, info *Info, opts0 DialOpts) (*dialResult, error) {
	if len(info.Addrs) == 0 {
		return nil, errors.New("no API addresses to connect to")
	}
	addrs := info.Addrs[:]
	if info.Proxier != nil {
		if err := info.Proxier.Start(); err != nil {
			return nil, errors.Annotate(err, "starting proxy for api connection")
		}
		logger.Debugf("starting proxier for connection")
		switch p := info.Proxier.(type) {
		case jujuproxy.TunnelProxier:
			logger.Debugf("tunnel proxy in use at %s on port %s", p.Host(), p.Port())
			addrs = []string{
				fmt.Sprintf("%s:%s", p.Host(), p.Port()),
			}
		default:
			info.Proxier.Stop()
			return nil, errors.New("unknown proxier provided")
		}
	}
	opts := dialOpts{
		DialOpts:    opts0,
		sniHostName: info.SNIHostName,
	}
	if info.CACert != "" {
		certPool, err := CreateCertPool(info.CACert)
		if err != nil {
			return nil, errors.Annotate(err, "cert pool creation failed")
		}
		opts.certPool = certPool
	}
	if opts.DialWebsocket == nil {
		opts.DialWebsocket = gorillaDialWebsocket
	}
	if opts.IPAddrResolver == nil {
		opts.IPAddrResolver = net.DefaultResolver
	}
	if opts.Clock == nil {
		opts.Clock = clock.WallClock
	}
	if opts.DNSCache == nil {
		opts.DNSCache = nopDNSCache{}
	}
	path, err := apiPath(info.ModelTag, "/api")
	if err != nil {
		return nil, errors.Trace(err)
	}
	rand.Shuffle(len(addrs), func(i, j int) { addrs[i], addrs[j] = addrs[j], addrs[i] })
	if opts.VerifyCA != nil {
		if err := verifyCAMulti(ctx, addrs, &opts); err != nil {
			return nil, err
		}
	}
	if opts.DialTimeout > 0 {
		ctx1, cancel := utils.ContextWithTimeout(ctx, opts.Clock, opts.DialTimeout)
		defer cancel()
		ctx = ctx1
	}
	dialInfo, err := dialWebsocketMulti(ctx, addrs, path, opts)
	if err != nil {
		return nil, errors.Trace(err)
	}
	logger.Infof("connection established to %q", dialInfo.urlStr)
	dialInfo.proxier = info.Proxier
	return dialInfo, nil
}
func dialAPI ( ctx context . Context , info * Info , opts0 DialOpts ) ( * dialResult , error ) { if len ( info . Addrs ) == 0 { return nil , errors . New ( " " ) } addrs := info . Addrs [ : ] if info . Proxier != nil { if err := info . Proxier . Start ( ) ; err != nil { return nil , errors . Annotate ( err , " " ) } logger . Debugf ( " " ) switch p := info . Proxier . ( type ) { case jujuproxy . TunnelProxier : logger . Debugf ( " " , p . Host ( ) , p . Port ( ) ) addrs = [ ] string { fmt . Sprintf ( " " , p . Host ( ) , p . Port ( ) ) , } default : info . Proxier . Stop ( ) return nil , errors . New ( " " ) } } opts := dialOpts { DialOpts : opts0 , sniHostName : info . SNIHostName , } if info . CACert != " " { certPool , err := CreateCertPool ( info . CACert ) if err != nil { return nil , errors . Annotate ( err , " " ) } opts . certPool = certPool } if opts . DialWebsocket == nil { opts . DialWebsocket = gorillaDialWebsocket } if opts . IPAddrResolver == nil { opts . IPAddrResolver = net . DefaultResolver } if opts . Clock == nil { opts . Clock = clock . WallClock } if opts . DNSCache == nil { opts . DNSCache = nopDNSCache { } } path , err := apiPath ( info . ModelTag , " " ) if err != nil { return nil , errors . Trace ( err ) } rand . Shuffle ( len ( addrs ) , func ( i , j int ) { addrs [ i ] , addrs [ j ] = addrs [ j ] , addrs [ i ] } ) if opts . VerifyCA != nil { if err := verifyCAMulti ( ctx , addrs , & opts ) ; err != nil { return nil , err } } if opts . DialTimeout > 0 { ctx1 , cancel := utils . ContextWithTimeout ( ctx , opts . Clock , opts . DialTimeout ) defer cancel ( ) ctx = ctx1 } dialInfo , err := dialWebsocketMulti ( ctx , addrs , path , opts ) if err != nil { return nil , errors . Trace ( err ) } logger . Infof ( " " , dialInfo . urlStr ) dialInfo . proxier = info . Proxier return dialInfo , nil }
dialAPI establishes a websocket connection to the RPC
API websocket on the API server using Info.
dialAPI establishes a websocket connection to the RPC API websocket on the API server using Info .
// Set opts.DialWebsocket and opts.Clock here rather than in open because // some tests call dialAPI directly. // Encourage load balancing by shuffling controller addresses.