Copilot commented on code in PR #13060:
URL: https://github.com/apache/cloudstack/pull/13060#discussion_r3153273727
##########
plugins/storage/volume/flasharray/src/main/java/org/apache/cloudstack/storage/datastore/adapter/flasharray/FlashArrayAdapter.java:
##########
@@ -661,72 +664,125 @@ private void login() {
skipTlsValidation = true;
}
+ // Resolve the long-lived API token. Prefer a pre-minted api_token
(Purity REST 2.x flow);
+ // fall back to legacy username/password auth via Purity REST 1.x for
backward compatibility.
+ String apiToken = connectionDetails.get(ProviderAdapter.API_TOKEN_KEY);
+ if (apiToken != null && apiToken.isEmpty()) {
+ apiToken = null;
+ }
+ boolean usingLegacyUserPass = apiToken == null;
+ if (usingLegacyUserPass && (username == null || password == null)) {
+ throw new CloudRuntimeException("FlashArray adapter requires
either " + ProviderAdapter.API_TOKEN_KEY
+ + " (preferred) or both " +
ProviderAdapter.API_USERNAME_KEY + " and "
+ + ProviderAdapter.API_PASSWORD_KEY + " in the connection
details");
+ }
+
+ CloseableHttpClient client = getClient();
CloseableHttpResponse response = null;
try {
- HttpPost request = new HttpPost(url + "/" + apiLoginVersion +
"/auth/apitoken");
- // request.addHeader("Content-Type", "application/json");
- // request.addHeader("Accept", "application/json");
- ArrayList<NameValuePair> postParms = new
ArrayList<NameValuePair>();
- postParms.add(new BasicNameValuePair("username", username));
- postParms.add(new BasicNameValuePair("password", password));
- request.setEntity(new UrlEncodedFormEntity(postParms, "UTF-8"));
- CloseableHttpClient client = getClient();
- response = (CloseableHttpResponse) client.execute(request);
+ // Discover the latest supported API version from the array unless
one was explicitly configured.
+ // GET /api/api_version is unauthenticated and returns
{"version":["1.0",...,"2.36"]}.
+ if (!apiVersionExplicit) {
+ HttpGet vReq = new HttpGet(url + "/api_version");
+ CloseableHttpResponse vResp = null;
+ try {
+ vResp = (CloseableHttpResponse) client.execute(vReq);
+ if (vResp.getStatusLine().getStatusCode() == 200) {
+ JsonNode root =
mapper.readTree(vResp.getEntity().getContent());
+ JsonNode versions = root.get("version");
+ if (versions != null && versions.isArray() &&
versions.size() > 0) {
+ apiVersion = versions.get(versions.size() -
1).asText();
+ }
+ } else {
+ logger.warn("Unexpected HTTP " +
vResp.getStatusLine().getStatusCode()
+ + " from FlashArray [" + url + "]
/api_version, falling back to default "
+ + API_VERSION_DEFAULT);
+ }
+ } catch (Exception e) {
+ logger.warn("Failed to discover Purity REST API version
from " + url
+ + "/api_version, falling back to default " +
API_VERSION_DEFAULT, e);
+ } finally {
+ if (vResp != null) {
+ try {
+ vResp.close();
+ } catch (IOException e) {
+ logger.debug("Error closing /api/api_version
response from FlashArray [" + url + "]", e);
+ }
+ }
+ }
+ }
- int statusCode = response.getStatusLine().getStatusCode();
- FlashArrayApiToken apitoken = null;
- if (statusCode == 200 | statusCode == 201) {
- apitoken = mapper.readValue(response.getEntity().getContent(),
FlashArrayApiToken.class);
- if (apitoken == null) {
+ 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.");
Review 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.
##########
plugins/storage/volume/flasharray/src/main/java/org/apache/cloudstack/storage/datastore/adapter/flasharray/FlashArrayAdapter.java:
##########
@@ -661,72 +664,125 @@ private void login() {
skipTlsValidation = true;
}
+ // Resolve the long-lived API token. Prefer a pre-minted api_token
(Purity REST 2.x flow);
+ // fall back to legacy username/password auth via Purity REST 1.x for
backward compatibility.
+ String apiToken = connectionDetails.get(ProviderAdapter.API_TOKEN_KEY);
+ if (apiToken != null && apiToken.isEmpty()) {
+ apiToken = null;
+ }
+ boolean usingLegacyUserPass = apiToken == null;
+ if (usingLegacyUserPass && (username == null || password == null)) {
+ throw new CloudRuntimeException("FlashArray adapter requires
either " + ProviderAdapter.API_TOKEN_KEY
+ + " (preferred) or both " +
ProviderAdapter.API_USERNAME_KEY + " and "
+ + ProviderAdapter.API_PASSWORD_KEY + " in the connection
details");
+ }
+
+ CloseableHttpClient client = getClient();
CloseableHttpResponse response = null;
try {
- HttpPost request = new HttpPost(url + "/" + apiLoginVersion +
"/auth/apitoken");
- // request.addHeader("Content-Type", "application/json");
- // request.addHeader("Accept", "application/json");
- ArrayList<NameValuePair> postParms = new
ArrayList<NameValuePair>();
- postParms.add(new BasicNameValuePair("username", username));
- postParms.add(new BasicNameValuePair("password", password));
- request.setEntity(new UrlEncodedFormEntity(postParms, "UTF-8"));
- CloseableHttpClient client = getClient();
- response = (CloseableHttpResponse) client.execute(request);
+ // Discover the latest supported API version from the array unless
one was explicitly configured.
+ // GET /api/api_version is unauthenticated and returns
{"version":["1.0",...,"2.36"]}.
+ if (!apiVersionExplicit) {
+ HttpGet vReq = new HttpGet(url + "/api_version");
+ CloseableHttpResponse vResp = null;
+ try {
+ vResp = (CloseableHttpResponse) client.execute(vReq);
+ if (vResp.getStatusLine().getStatusCode() == 200) {
+ JsonNode root =
mapper.readTree(vResp.getEntity().getContent());
+ JsonNode versions = root.get("version");
+ if (versions != null && versions.isArray() &&
versions.size() > 0) {
+ apiVersion = versions.get(versions.size() -
1).asText();
+ }
+ } else {
+ logger.warn("Unexpected HTTP " +
vResp.getStatusLine().getStatusCode()
+ + " from FlashArray [" + url + "]
/api_version, falling back to default "
+ + API_VERSION_DEFAULT);
+ }
+ } catch (Exception e) {
+ logger.warn("Failed to discover Purity REST API version
from " + url
+ + "/api_version, falling back to default " +
API_VERSION_DEFAULT, e);
+ } finally {
+ if (vResp != null) {
+ try {
+ vResp.close();
+ } catch (IOException e) {
+ logger.debug("Error closing /api/api_version
response from FlashArray [" + url + "]", e);
Review 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.
```suggestion
logger.debug("Error closing /api_version
response from FlashArray [" + url + "]", e);
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]