flasharray: authenticate via REST 2.x api-token and discover API version#13060
flasharray: authenticate via REST 2.x api-token and discover API version#13060genegr wants to merge 3 commits intoapache:4.20from
Conversation
|
@blueorangutan package |
|
@winterhazel a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress. |
|
Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 17577 |
There was a problem hiding this comment.
Pull request overview
Updates the FlashArray managed-storage adapter to support Pure’s REST 2.x preferred authentication model by accepting a long-lived api_token and dynamically discovering the array’s supported REST API version, while keeping a deprecated username/password fallback for existing deployments.
Changes:
- Add support for authenticating directly to REST 2.x
/loginusing a pre-mintedapi_tokenpool detail, with a deprecation warning when falling back to REST 1.x username/password. - Discover the latest supported Purity REST API version via unauthenticated
GET /api/api_versionwhenapi_versionis not explicitly configured. - Improve some login error handling/messages around token-based auth.
Comments suppressed due to low confidence (1)
plugins/storage/volume/flasharray/src/main/java/org/apache/cloudstack/storage/datastore/adapter/flasharray/FlashArrayAdapter.java:603
apiVersionis re-derived fromconnectionDetails/query params on everylogin(). Whenapi_versionis not explicitly configured, this causes/api_versiondiscovery to run on every session refresh, not just the first login for a pool. Consider caching the discovered version in a field (e.g., only resolve whenapiVersionis null/uninitialized, or add anapiVersionResolvedflag) so subsequent logins reuse it without another discovery call.
apiVersion = connectionDetails.get(FlashArrayAdapter.API_VERSION);
boolean apiVersionExplicit = apiVersion != null;
if (apiVersion == null) {
apiVersion = queryParms.get(FlashArrayAdapter.API_VERSION);
apiVersionExplicit = apiVersion != null;
if (apiVersion == null) {
apiVersion = API_VERSION_DEFAULT;
}
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## 4.20 #13060 +/- ##
============================================
+ Coverage 16.26% 18.02% +1.75%
- Complexity 13435 16620 +3185
============================================
Files 5665 6029 +364
Lines 500556 542236 +41680
Branches 60790 66461 +5671
============================================
+ Hits 81416 97736 +16320
- Misses 410036 433483 +23447
- Partials 9104 11017 +1913
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Pushed
Smoke-tested locally: login via |
|
@genegr I saw other improvements by you on branch 4.20. Is this alright to go on later releases? |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (usingLegacyUserPass) { | ||
| logger.warn("FlashArray adapter at [" + url + "] is using deprecated username/password " | ||
| + "login against Purity REST 1.x. Replace with a pre-minted " | ||
| + ProviderAdapter.API_TOKEN_KEY + " detail; the username/password code path will be " | ||
| + "removed in a future release."); |
There was a problem hiding this comment.
The deprecation warning for legacy username/password auth is emitted on every login/refresh. With the default key TTL (~14 minutes), this can spam logs for each configured FlashArray pool. Consider rate-limiting (e.g., log once per adapter instance/endpoint) or downgrading subsequent messages to DEBUG after the first WARN.
| try { | ||
| vResp.close(); | ||
| } catch (IOException e) { | ||
| logger.debug("Error closing /api/api_version response from FlashArray [" + url + "]", e); |
There was a problem hiding this comment.
The request is sent to .../api_version (relative to url), but the debug message says "Error closing /api/api_version response...". Align the log text with the actual endpoint/path to avoid confusion during troubleshooting.
| logger.debug("Error closing /api/api_version response from FlashArray [" + url + "]", e); | |
| logger.debug("Error closing /api_version response from FlashArray [" + url + "]", e); |
The FlashArray adapter previously always made an initial call to the deprecated Purity REST 1.x session endpoint using a username and password to obtain a long-lived api_token, then exchanged that token for the REST 2.x x-auth-token session key. Purity 1.x is being removed from the array, so this path has an expiration date, and storing the username and password as pool details is not what the Purity documentation recommends. Accept a pre-minted api_token in the pool details (ProviderAdapter.API_TOKEN_KEY, already reserved in the base interface) and go straight to the REST 2.x /login endpoint. The api_token is long-lived and is created on the array via the Purity GUI (Users -> API Tokens) or CLI (pureadmin create --api-token). If api_token is not set, fall back to the legacy username/password flow and emit a deprecation warning so existing deployments keep working during the transition. The fallback path will be removed in a later release. While here, resolve the API version dynamically by calling the unauthenticated GET /api/api_version endpoint the first time a login happens on a pool, unless the operator pinned a specific version via API_VERSION. This makes the adapter pick up newer Purity releases automatically instead of being stuck on the hard-coded 2.23 default. Signed-off-by: Eugenio Grosso <eugenio.grosso@gmail.com>
- Replace nested null-check of apiVersion with !apiVersionExplicit for clarity (sureshanaparti). - Wrap vResp.close() in the api_version-discovery finally with its own try/catch; log any IOException at debug so a failed close does not mask a successful discovery. - Wrap the explicit response.close() after the legacy username/password auth with try/catch for the same reason. Signed-off-by: Eugenio Grosso <eugenio.grosso@gmail.com>
The Copilot review pointed out the debug message said /api/api_version but the path passed to the helper is /api_version (the helper itself prepends url + apiVersion). Update the log text to match what the code actually invokes. Signed-off-by: Eugenio Grosso <eugenio.grosso@gmail.com>
6abdc0d to
2938570
Compare
|
@DaanHoogland — yes, this is fine to ship in 4.20/4.22. Rebased onto Round 1 (
Round 2 (
Still open
Smoke-tested locally: login via |
|
@blueorangutan package |
|
@sureshanaparti a [SL] Jenkins job has been kicked to build packages. It will be bundled with KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress. |
|
Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 17645 |
|
@blueorangutan test |
|
@DaanHoogland a [SL] Trillian-Jenkins test job (ol8 mgmt + kvm-ol8) has been kicked to run smoke tests |
The FlashArray adapter previously always made an initial call to the deprecated Purity REST 1.x session endpoint using a username and password to obtain a long-lived api_token, then exchanged that token for the REST 2.x x-auth-token session key. Purity 1.x is being removed from the array, so this path has an expiration date, and storing the username and password as pool details is not what the Purity documentation recommends.
Accept a pre-minted api_token in the pool details (ProviderAdapter.API_TOKEN_KEY, already reserved in the base interface) and go straight to the REST 2.x /login endpoint. The api_token is long-lived and is created on the array via the Purity GUI (Users -> API Tokens) or CLI (pureadmin create --api-token).
If api_token is not set, fall back to the legacy username/password flow and emit a deprecation warning so existing deployments keep working during the transition. The fallback path will be removed in a later release.
While here, resolve the API version dynamically by calling the unauthenticated GET /api/api_version endpoint the first time a login happens on a pool, unless the operator pinned a specific version via API_VERSION. This makes the adapter pick up newer Purity releases automatically instead of being stuck on the hard-coded 2.23 default.
Description
The FlashArray adapter currently performs two calls to log in: a POST to the deprecated Purity REST 1.x
auth/apitokenendpoint with username/password to obtain a long-livedapi_token, then a POST to/api/<ver>/loginwithapi-token:header to get the sessionx-auth-token. Pure Storage is phasing out REST 1.x, and storing username/password as pool details is not the recommended pattern.This PR:
api_tokenas a pool detail (ProviderAdapter.API_TOKEN_KEY, already reserved in the base interface). When present, the adapter skips the 1.x call entirely and goes straight toPOST /api/<ver>/loginwithapi-token:header.api_tokenis not set, logging a deprecation warning. No existing deployments break; removal of the fallback can happen in a later release.GET /api/api_versionon first login (unless an explicitapi_versionpool detail pins it). Replaces the hardcoded2.23default, so the adapter tracks newer Purity releases automatically.Types of changes
How Has This Been Tested?
Validated on a 4.23-SNAPSHOT lab against a Purity 6.7.7 FlashArray:
details[api_token]=<long-lived-token>to an existing pool and restarted mgmt → adapter resumes without the deprecation warning, capacity polling and volume create continue working./api/1.19/auth/apitoken, still working./api/api_versiondiscovery resolves to2.36on Purity 6.7.7 without manual configuration.How to Get an API Token on the Array
Purity GUI: Settings → Users → <user> → API Tokens → Create API Token. CLI:
ssh pureuser@<array>; pureadmin create --api-token <user>.