genegr commented on code in PR #13060:
URL: https://github.com/apache/cloudstack/pull/13060#discussion_r3528233760
##########
plugins/storage/volume/flasharray/src/main/java/org/apache/cloudstack/storage/datastore/adapter/flasharray/FlashArrayAdapter.java:
##########
@@ -660,72 +669,127 @@ 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_version response
from FlashArray [" + url + "]", e);
+ }
Review Comment:
Done in `2983a100ff`: extracted to `fetchApiVersionFromPurity(client)` —
same body, sets `apiVersion` as before.
##########
plugins/storage/volume/flasharray/src/main/java/org/apache/cloudstack/storage/datastore/adapter/flasharray/FlashArrayAdapter.java:
##########
@@ -660,72 +669,127 @@ 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);
Review Comment:
Done in `2983a100ff`. Cleaned up all four `(CloseableHttpResponse)` casts in
the file (this one, line 732, and the two in the private POST/GET/PATCH helpers
around lines 960/1015/1057) for consistency.
##########
plugins/storage/volume/flasharray/src/main/java/org/apache/cloudstack/storage/datastore/adapter/flasharray/FlashArrayAdapter.java:
##########
@@ -660,72 +669,127 @@ 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_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) {
+ if (WARNED_LEGACY_URLS.add(url)) {
+ 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.");
+ }
+ HttpPost request = new HttpPost(url + "/" + apiLoginVersion +
"/auth/apitoken");
+ 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"));
+ response = (CloseableHttpResponse) client.execute(request);
Review Comment:
Also done in `2983a100ff` — this one is now inside the extracted
`getApiTokenUsingUserPass()`, cast dropped.
##########
plugins/storage/volume/flasharray/src/main/java/org/apache/cloudstack/storage/datastore/adapter/flasharray/FlashArrayAdapter.java:
##########
@@ -660,72 +669,127 @@ 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_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) {
Review Comment:
Done in `2983a100ff`: extracted to `getApiTokenUsingUserPass(client)`. The
extracted method also cleans up the response handling with a proper try/finally
so the caller no longer needs the manual `response.close()` + `response = null`
dance.
--
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]