Skip to content

Gophercloud does not support versioned discovery #3349

Closed

Description

@stephenfin

Per the keystone docs:

The OpenStack keystone service catalog allows API clients to dynamically discover and navigate to cloud services.

The catalog describes a list of services along with endpoints for same. For example:

GET /v3/auth/catalog
{
  "catalog": [
    {
      "endpoints": [
        {
          "id": "390de2ac62c5410fb53a7bf5e6bec533",
          "interface": "public",
          "region_id": "RegionOne",
          "url": "http://identity.example.com",
          "region": "RegionOne"
        }
      ],
      "id": "b2651a44a0bb44d5b5733052a1fc66f7",
      "type": "identity",
      "name": "keystone"
    },
  ],
  "links": {
    "self": "http://identity.example.com/v3/auth/catalog"
  }
}

Notably absent from the catalog though is any mention of version information. It is possible to have multiple endpoints for the same service type using different names. For example, Cinder previously had a v2 API. It is possible to expose both of these using the same service type:

{
  "catalog": [
    {
      "endpoints": [
        {
          "id": "cdec1b8a3134480c9e326edd8c1d4b13",
          "interface": "public",
          "region_id": "RegionOne",
          "url": "https://volume.example.com/v2",
          "region": "RegionOne"
        }
      ],
      "id": "8e5833137bc04a65a3f5dd500fe6bcc8",
      "type": "block-storage",
      "name": "cinder_v2"
    },
    {
      "endpoints": [
        {
          "id": "5e444bf893b247a69bf1d6fcf3334a23",
          "interface": "public",
          "region_id": "RegionOne",
          "url": "https://volume.example.com/v3",
          "region": "RegionOne"
        }
      ],
      "id": "8e5833137bc04a65a3f5dd500fe6bcc8",
      "type": "block-storage",
      "name": "cinder_v3"
    },
    {
      "endpoints": [
        {
          "id": "390de2ac62c5410fb53a7bf5e6bec533",
          "interface": "public",
          "region_id": "RegionOne",
          "url": "https://identity.example.com",
          "region": "RegionOne"
        }
      ],
      "id": "b2651a44a0bb44d5b5733052a1fc66f7",
      "type": "identity",
      "name": "keystone"
    },
  ],
  "links": {
    "self": "https://identity.example.com/v3/auth/catalog"
  }
}

The expected behavior here is to fetch the version discovery document from the URL indicated for each endpoint (the root API) (for all services except Swift, unfortunately). This will return a document like so:

GET /v3/
{
  "versions": [
    {
      "id": "v3.0",
      "status": "CURRENT",
      "version": "3.71",
      "min_version": "3.0",
      "updated": "2023-08-31T00:00:00Z",
      "links": [
        {
          "rel": "describedby",
          "type": "text/html",
          "href": "https://docs.openstack.org/"
        },
        {
          "rel": "self",
          "href": "http://volume.example.com/v3/"
        }
      ],
      "media-types": [
        {
          "base": "application/json",
          "type": "application/vnd.openstack.volume+json;version=3"
        }
      ]
    }
  ]
}

Gophercloud is not currently doing this, forcing deployments to use versioned service type aliases (i.e. volumev2 or volumev3) rather than the official service type. We should correct this.e

Activity

  1. gtema commented on Apr 18, 2025

    @gtema

    I am not 100% sure it is right. Historically there were always volumev2 and volumev3 as different service types but with different names. The service type volume (or also block-storage) was then pointing to the default (preferred) api. From the DB pov it is not possible to have multiple services with the same service type.
    There are however many tricks in the version discovery that I was reverse-engineering from docs and reference impl recently for the Rust. I will summarize them here later today/tomorrow.

  2. gtema commented on Apr 18, 2025

    @gtema

    @stephenfin
    Feel free to deduct the process from https://github.com/gtema/openstack/blob/main/openstack_sdk/src/openstack_async.rs#L449 which is a slightly optimized version of the reference implementation (as well as everything is in the single place compared to multiple places between os-service-type, keystoneauth, openstacksdk, os-client-config). You will hopefully see enough comments and tests with explanations.

    You can't have multiple occurrences of the service with the same type, but you can use versioned type aliases (volumev2, volumev3). The discoverability rule says that you can take any type and suffix it with the vX. Whenever this particular version is explicitly requested by the client it should be preferred. On every entry of the catalog you MUST still perform version discovery. What you get in the discovery document is than taken as a base and is being "fixed" with the url from catalog (i.e. version discovery may return localhost:1234/abc where the localhost:1234 must be replaced with the domain:port which was used to obtain this document. You must also verify whether version discovery doc contains at all a reasonable url. Further there are endpoint_overrides in the config, so the order is: discovered from catalog, catalog, override. And as mentioned above - depending on the needed client (version) you may have override or discovered version or not, so the process is not very straight forward.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions