// V2EndpointURL discovers the endpoint URL for a specific service from a ServiceCatalog acquired
// during the v2 identity service. The specified EndpointOpts are used to identify a unique,
// unambiguous endpoint to return. It's an error both when multiple endpoints match the provided
// criteria and when none do. The minimum that can be specified is a Type, but you will also often
// need to specify a Name and/or a Region depending on what's available on your OpenStack
// deployment.
func V2EndpointURL(catalog *tokens2.ServiceCatalog, opts gophercloud.EndpointOpts) (string, error) {
	// Extract Endpoints from the catalog entries that match the requested Type, Name if provided, and Region if provided.
	var endpoints = make([]tokens2.Endpoint, 0, 1)
	for _, entry := range catalog.Entries {
		if (entry.Type == opts.Type) && (opts.Name == "" || entry.Name == opts.Name) {
			for _, endpoint := range entry.Endpoints {
				if opts.Region == "" || endpoint.Region == opts.Region {
					endpoints = append(endpoints, endpoint)
				}
			}
		}
	}

	// Report an error if the options were ambiguous.
	if len(endpoints) > 1 {
		return "", fmt.Errorf("Discovered %d matching endpoints: %#v", len(endpoints), endpoints)
	}

	// Extract the appropriate URL from the matching Endpoint.
	for _, endpoint := range endpoints {
		switch opts.Availability {
		case gophercloud.AvailabilityPublic:
			return gophercloud.NormalizeURL(endpoint.PublicURL), nil
		case gophercloud.AvailabilityInternal:
			return gophercloud.NormalizeURL(endpoint.InternalURL), nil
		case gophercloud.AvailabilityAdmin:
			return gophercloud.NormalizeURL(endpoint.AdminURL), nil
		default:
			return "", fmt.Errorf("Unexpected availability in endpoint query: %s", opts.Availability)
		}
	}

	// Report an error if there were no matching endpoints.
	return "", gophercloud.ErrEndpointNotFound
}
Example #2
0
func newClient(endpoint string) (*gophercloud.ProviderClient, error) {
	u, err := url.Parse(endpoint)
	if err != nil {
		return nil, err
	}
	hadPath := u.Path != ""
	u.Path, u.RawQuery, u.Fragment = "", "", ""
	base := u.String()

	endpoint = gophercloud.NormalizeURL(endpoint)
	base = gophercloud.NormalizeURL(base)
	timeout := time.Duration(20 * time.Second)

	if !hadPath {
		endpoint = ""
	}
	return &gophercloud.ProviderClient{
		IdentityBase:     base,
		IdentityEndpoint: endpoint,
		HTTPClient: http.Client{
			Timeout: timeout,
		},
	}, nil

}
Example #3
0
// NewClient prepares an unauthenticated ProviderClient instance.
// Most users will probably prefer using the AuthenticatedClient function instead.
// This is useful if you wish to explicitly control the version of the identity service that's used for authentication explicitly,
// for example.
func NewClient(endpoint string) (*gophercloud.ProviderClient, error) {
	u, err := url.Parse(endpoint)
	if err != nil {
		return nil, err
	}

	u.RawQuery, u.Fragment = "", ""

	// Base is url with path
	endpoint = gophercloud.NormalizeURL(endpoint)
	base := gophercloud.NormalizeURL(u.String())

	path := u.Path
	if !strings.HasSuffix(path, "/") {
		path = path + "/"
	}

	parts := strings.Split(path[0:len(path)-1], "/")
	for index, version := range parts {
		if 2 <= len(version) && len(version) <= 4 && strings.HasPrefix(version, "v") {
			_, err := strconv.ParseFloat(version[1:], 64)
			if err == nil {
				// post version suffixes in path are not supported
				// version must be on the last index
				if index < len(parts)-1 {
					return nil, fmt.Errorf("Path suffixes (after version) are not supported.")
				}
				switch version {
				case "v2.0", "v3":
					// valid version found, strip from base
					return &gophercloud.ProviderClient{
						IdentityBase:     base[0 : len(base)-len(version)-1],
						IdentityEndpoint: endpoint,
					}, nil
				default:
					return nil, fmt.Errorf("Invalid identity endpoint version %v. Supported versions: v2.0, v3", version)
				}
			}
		}
	}

	return &gophercloud.ProviderClient{
		IdentityBase:     base,
		IdentityEndpoint: "",
	}, nil
}
Example #4
0
// NewClient prepares an unauthenticated ProviderClient instance.
// Most users will probably prefer using the AuthenticatedClient function instead.
// This is useful if you wish to explicitly control the version of the identity service that's used for authentication explicitly,
// for example.
func NewClient(endpoint string) (*gophercloud.ProviderClient, error) {
	u, err := url.Parse(endpoint)
	if err != nil {
		return nil, err
	}
	hadPath := u.Path != ""
	u.Path, u.RawQuery, u.Fragment = "", "", ""
	base := u.String()

	endpoint = gophercloud.NormalizeURL(endpoint)
	base = gophercloud.NormalizeURL(base)

	if hadPath {
		return &gophercloud.ProviderClient{
			IdentityBase:     base,
			IdentityEndpoint: endpoint,
		}, nil
	}

	return &gophercloud.ProviderClient{
		IdentityBase:     base,
		IdentityEndpoint: "",
	}, nil
}
// V3EndpointURL discovers the endpoint URL for a specific service using multiple calls against
// an identity v3 service endpoint. The specified EndpointOpts are used to identify a unique,
// unambiguous endpoint to return. It's an error both when multiple endpoints match the provided
// criteria and when none do. The minimum that can be specified is a Type, but you will also often
// need to specify a Name and/or a Region depending on what's available on your OpenStack
// deployment.
func V3EndpointURL(v3Client *gophercloud.ServiceClient, opts gophercloud.EndpointOpts) (string, error) {
	// Discover the service we're interested in.
	var services = make([]services3.Service, 0, 1)
	servicePager := services3.List(v3Client, services3.ListOpts{ServiceType: opts.Type})
	err := servicePager.EachPage(func(page pagination.Page) (bool, error) {
		part, err := services3.ExtractServices(page)
		if err != nil {
			return false, err
		}

		for _, service := range part {
			if service.Name == opts.Name {
				services = append(services, service)
			}
		}

		return true, nil
	})
	if err != nil {
		return "", err
	}

	if len(services) == 0 {
		return "", gophercloud.ErrServiceNotFound
	}
	if len(services) > 1 {
		return "", fmt.Errorf("Discovered %d matching services: %#v", len(services), services)
	}
	service := services[0]

	// Enumerate the endpoints available for this service.
	var endpoints []endpoints3.Endpoint
	endpointPager := endpoints3.List(v3Client, endpoints3.ListOpts{
		Availability: opts.Availability,
		ServiceID:    service.ID,
	})
	err = endpointPager.EachPage(func(page pagination.Page) (bool, error) {
		part, err := endpoints3.ExtractEndpoints(page)
		if err != nil {
			return false, err
		}

		for _, endpoint := range part {
			if opts.Region == "" || endpoint.Region == opts.Region {
				endpoints = append(endpoints, endpoint)
			}
		}

		return true, nil
	})
	if err != nil {
		return "", err
	}

	if len(endpoints) == 0 {
		return "", gophercloud.ErrEndpointNotFound
	}
	if len(endpoints) > 1 {
		return "", fmt.Errorf("Discovered %d matching endpoints: %#v", len(endpoints), endpoints)
	}
	endpoint := endpoints[0]

	return gophercloud.NormalizeURL(endpoint.URL), nil
}