func (s *apiAddresserSuite) TestAPIAddressesPrivateFirst(c *gc.C) { ctlr1, err := network.ParseHostPorts("52.7.1.1:17070", "10.0.2.1:17070") c.Assert(err, jc.ErrorIsNil) ctlr2, err := network.ParseHostPorts("53.51.121.17:17070", "10.0.1.17:17070") c.Assert(err, jc.ErrorIsNil) s.fake.hostPorts = [][]network.HostPort{ network.NewHostPorts(1, "apiaddresses"), ctlr1, ctlr2, network.NewHostPorts(2, "apiaddresses"), } for _, hps := range s.fake.hostPorts { for _, hp := range hps { c.Logf("%s - %#v", hp.Scope, hp) } } result, err := s.addresser.APIAddresses() c.Assert(err, jc.ErrorIsNil) c.Check(result.Result, gc.DeepEquals, []string{ "apiaddresses:1", "10.0.2.1:17070", "52.7.1.1:17070", "10.0.1.17:17070", "53.51.121.17:17070", "apiaddresses:2", }) }
func (*HostPortSuite) TestParseHostPortsSuccess(c *gc.C) { for i, test := range []struct { args []string expect []network.HostPort }{{ args: nil, expect: []network.HostPort{}, }, { args: []string{"1.2.3.4:42"}, expect: network.NewHostPorts(42, "1.2.3.4"), }, { args: []string{"[fc00::1]:1234"}, expect: network.NewHostPorts(1234, "fc00::1"), }, { args: []string{"[fc00::1]:1234", "127.0.0.1:4321", "example.com:42"}, expect: []network.HostPort{ {network.NewAddress("fc00::1"), 1234}, {network.NewAddress("127.0.0.1"), 4321}, {network.NewAddress("example.com"), 42}, }, }} { c.Logf("test %d: args %v", i, test.args) hps, err := network.ParseHostPorts(test.args...) c.Check(err, jc.ErrorIsNil) c.Check(hps, jc.DeepEquals, test.expect) } }
func apiAddrsToHostPorts(addrs []string) ([][]network.HostPort, error) { hps, err := network.ParseHostPorts(addrs...) if err != nil { return nil, errors.Trace(err) } return [][]network.HostPort{hps}, nil }
func mustParseHostPorts(ss []string) []network.HostPort { hps, err := network.ParseHostPorts(ss...) if err != nil { panic(err) } return hps }
func MustParseHostPorts(hostports ...string) []network.HostPort { out, err := network.ParseHostPorts(hostports...) if err != nil { panic(err) } return out }
func (s *apiclientSuite) TestOpenWithRedirect(c *gc.C) { redirectToHosts := []string{"0.1.2.3:1234", "0.1.2.4:1235"} redirectToCACert := "fake CA cert" srv := apiservertesting.NewAPIServer(func(modelUUID string) interface{} { return &redirectAPI{ modelUUID: modelUUID, redirectToHosts: redirectToHosts, redirectToCACert: redirectToCACert, } }) defer srv.Close() _, err := api.Open(&api.Info{ Addrs: srv.Addrs, CACert: jtesting.CACert, ModelTag: names.NewModelTag("beef1beef1-0000-0000-000011112222"), }, api.DialOpts{}) c.Assert(err, gc.ErrorMatches, `redirection to alternative server required`) hps, _ := network.ParseHostPorts(redirectToHosts...) c.Assert(errors.Cause(err), jc.DeepEquals, &api.RedirectError{ Servers: [][]network.HostPort{hps}, CACert: redirectToCACert, }) }
// cacheAPIInfo updates the local environment settings (.jenv file) // with the provided apiInfo, assuming we've just successfully // connected to the API server. func cacheAPIInfo(st apiState, info configstore.EnvironInfo, apiInfo *api.Info) (err error) { defer errors.DeferredAnnotatef(&err, "failed to cache API credentials") var environUUID string if names.IsValidEnvironment(apiInfo.EnvironTag.Id()) { environUUID = apiInfo.EnvironTag.Id() } else { // For backwards-compatibility, we have to allow connections // with an empty UUID. Login will work for the same reasons. logger.Warningf("ignoring invalid cached API endpoint environment UUID %v", apiInfo.EnvironTag.Id()) } hostPorts, err := network.ParseHostPorts(apiInfo.Addrs...) if err != nil { return errors.Annotatef(err, "invalid API addresses %v", apiInfo.Addrs) } addrConnectedTo, err := network.ParseHostPorts(st.Addr()) if err != nil { // Should never happen, since we've just connected with it. return errors.Annotatef(err, "invalid API address %q", st.Addr()) } addrs, hostnames, addrsChanged := PrepareEndpointsForCaching( info, [][]network.HostPort{hostPorts}, addrConnectedTo[0], ) endpoint := configstore.APIEndpoint{ CACert: string(apiInfo.CACert), EnvironUUID: environUUID, } if addrsChanged { endpoint.Addresses = addrs endpoint.Hostnames = hostnames } info.SetAPIEndpoint(endpoint) tag, ok := apiInfo.Tag.(names.UserTag) if !ok { return errors.Errorf("apiInfo.Tag was of type %T, expecting names.UserTag", apiInfo.Tag) } info.SetAPICredentials(configstore.APICredentials{ // This looks questionable. We have a tag, say "user-admin", but then only // the Id portion of the tag is recorded, "admin", so this is really a // username, not a tag, and cannot be reconstructed accurately. User: tag.Id(), Password: apiInfo.Password, }) return info.Write() }
func (s *AgentSuite) primeAPIHostPorts(c *gc.C) { apiInfo := s.APIInfo(c) c.Assert(apiInfo.Addrs, gc.HasLen, 1) hostPorts, err := network.ParseHostPorts(apiInfo.Addrs[0]) c.Assert(err, jc.ErrorIsNil) err = s.State.SetAPIHostPorts([][]network.HostPort{hostPorts}) c.Assert(err, jc.ErrorIsNil) c.Logf("api host ports primed %#v", hostPorts) }
// Ports returns the unique ports for the api addresses. func (info *Info) Ports() []int { ports := set.NewInts() hostPorts, err := network.ParseHostPorts(info.Addrs...) if err != nil { // Addresses have already been validated. panic(err) } for _, hp := range hostPorts { ports.Add(hp.Port) } return ports.Values() }
func (*HostPortSuite) TestParseHostPortsErrors(c *gc.C) { for i, test := range []struct { input string err string }{{ input: "", err: `cannot parse "" as address:port: missing port in address`, }, { input: " ", err: `cannot parse " " as address:port: missing port in address `, }, { input: ":", err: `cannot parse ":" port: strconv.ParseInt: parsing "": invalid syntax`, }, { input: "host", err: `cannot parse "host" as address:port: missing port in address host`, }, { input: "host:port", err: `cannot parse "host:port" port: strconv.ParseInt: parsing "port": invalid syntax`, }, { input: "::1", err: `cannot parse "::1" as address:port: too many colons in address ::1`, }, { input: "1.2.3.4", err: `cannot parse "1.2.3.4" as address:port: missing port in address 1.2.3.4`, }, { input: "1.2.3.4:foo", err: `cannot parse "1.2.3.4:foo" port: strconv.ParseInt: parsing "foo": invalid syntax`, }} { c.Logf("test %d: input %q", i, test.input) // First test all error cases with a single argument. hps, err := network.ParseHostPorts(test.input) c.Check(err, gc.ErrorMatches, test.err) c.Check(hps, gc.IsNil) } // Finally, test with mixed valid and invalid args. hps, err := network.ParseHostPorts("1.2.3.4:42", "[fc00::1]:12", "foo") c.Assert(err, gc.ErrorMatches, `cannot parse "foo" as address:port: missing port in address foo`) c.Assert(hps, gc.IsNil) }
func (a *redirectAPIAdmin) RedirectInfo() (params.RedirectInfoResult, error) { if !a.r.redirected { return params.RedirectInfoResult{}, errors.New("not redirected") } hps, err := network.ParseHostPorts(a.r.redirectToHosts...) if err != nil { panic(err) } return params.RedirectInfoResult{ Servers: [][]params.HostPort{params.FromNetworkHostPorts(hps)}, CACert: a.r.redirectToCACert, }, nil }
func (c *LoginCommand) cacheConnectionInfo(serverDetails envcmd.ServerFile, apiState api.Connection) (configstore.EnvironInfo, error) { store, err := configstore.Default() if err != nil { return nil, errors.Trace(err) } serverInfo := store.CreateInfo(c.Name) serverTag, err := apiState.ServerTag() if err != nil { return nil, errors.Wrap(err, errors.New("juju system too old to support login")) } connectedAddresses, err := network.ParseHostPorts(apiState.Addr()) if err != nil { // Should never happen, since we've just connected with it. return nil, errors.Annotatef(err, "invalid API address %q", apiState.Addr()) } addressConnectedTo := connectedAddresses[0] addrs, hosts, changed := juju.PrepareEndpointsForCaching(serverInfo, apiState.APIHostPorts(), addressConnectedTo) if !changed { logger.Infof("api addresses: %v", apiState.APIHostPorts()) logger.Infof("address connected to: %v", addressConnectedTo) return nil, errors.New("no addresses returned from prepare for caching") } serverInfo.SetAPICredentials( configstore.APICredentials{ User: serverDetails.Username, Password: serverDetails.Password, }) serverInfo.SetAPIEndpoint(configstore.APIEndpoint{ Addresses: addrs, Hostnames: hosts, CACert: serverDetails.CACert, ServerUUID: serverTag.Id(), }) if err = serverInfo.Write(); err != nil { return nil, errors.Trace(err) } return serverInfo, nil }
func (s *CacheAPIEndpointsSuite) SetUpTest(c *gc.C) { s.PatchValue(juju.ResolveOrDropHostnames, s.mockResolveOrDropHostnames) s.hostPorts = [][]network.HostPort{ network.NewHostPorts(1234, "1.0.0.1", "192.0.0.1", "127.0.0.1", "ipv4+6.example.com", "localhost", "169.254.1.1", "ipv4.example.com", "invalid host", "ipv6+6.example.com", "ipv4+4.example.com", "::1", "fe80::1", "ipv6.example.com", "fc00::111", "2001:db8::1", ), network.NewHostPorts(1235, "1.0.0.2", "2001:db8::2", "::1", "127.0.0.1", "ipv6+4.example.com", "localhost", ), } s.gocheckC = c s.resolveSeq = 1 s.resolveNumCalls = 0 s.numResolved = 0 s.envTag = names.NewEnvironTag(fakeUUID) s.store = configstore.NewMem() s.JujuConnSuite.SetUpTest(c) apiHostPort, err := network.ParseHostPorts(s.APIState.Addr()) c.Assert(err, jc.ErrorIsNil) s.apiHostPort = apiHostPort[0] }
// Validate validates the API info. func (info *Info) Validate() error { if len(info.Addrs) == 0 { return errors.NotValidf("missing addresses") } if _, err := network.ParseHostPorts(info.Addrs...); err != nil { return errors.NotValidf("host addresses: %v", err) } if info.SkipLogin { if info.Tag != nil { return errors.NotValidf("specifying Tag and SkipLogin") } if info.Password != "" { return errors.NotValidf("specifying Password and SkipLogin") } if len(info.Macaroons) > 0 { return errors.NotValidf("specifying Macaroons and SkipLogin") } } return nil }
func newAPIClient(envName string) (*api.State, error) { store, err := configstore.Default() if err != nil { return nil, errors.Trace(err) } st, err := newAPIFromStore(envName, store, defaultAPIOpen) if err != nil { return nil, errors.Trace(err) } return st.(*api.State), nil } // serverAddress returns the given string address:port as network.HostPort. var serverAddress = func(hostPort string) (network.HostPort, error) { addrConnectedTo, err := network.ParseHostPorts(hostPort) if err != nil { // Should never happen, since we've just connected with it. return network.HostPort{}, errors.Annotatef(err, "invalid API address %q", hostPort) } return addrConnectedTo[0], nil } // newAPIFromStore implements the bulk of NewAPIClientFromName // but is separate for testing purposes. func newAPIFromStore(envName string, store configstore.Storage, apiOpen apiOpenFunc) (apiState, error) { // Try to read the default environment configuration file. // If it doesn't exist, we carry on in case // there's some environment info for that environment. // This enables people to copy environment files // into their .juju/environments directory and have
func (s *HostPortSuite) assertHostPorts(c *gc.C, actual []network.HostPort, expected ...string) { parsed, err := network.ParseHostPorts(expected...) c.Assert(err, jc.ErrorIsNil) c.Assert(actual, jc.DeepEquals, parsed) }