Skip to content

Commit 7577819

Browse files
author
Chris Wiechmann
committed
Merge branch 'develop' into test-with-7.7-20200130
2 parents 2643a7d + 7924d70 commit 7577819

45 files changed

Lines changed: 758 additions & 147 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,22 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
66

77
## [Unreleased]
88
### Fixed
9+
- New API-Manager 7.7-September release settings are ignored during import (See issue [#119](https://github.com/Axway-API-Management-Plus/apim-cli/issues/119))
10+
- Policies not shown in console view if API is not using a Routing-Policy (See issue [#121](https://github.com/Axway-API-Management-Plus/apim-cli/issues/121))
11+
12+
### Added
13+
- Support to upgrade one or multiple APIs (See issue [#120](https://github.com/Axway-API-Management-Plus/apim-cli/issues/120))
14+
15+
## [1.3.2] 2020-11-25
16+
### Fixed
17+
- Application-Subscription not restored, when API is Republished to be updated and no applications given the API-Config (See issue [#117](https://github.com/Axway-API-Management-Plus/apim-cli/issues/117))
18+
19+
## [1.3.1] 2020-11-24
20+
### Fixed
921
- Created BE-API response was parsing the response wrong. This could lead to an issue, if the API contains a createdOn field. (See issue [#112](https://github.com/Axway-API-Management-Plus/apim-cli/issues/112))
1022
- Unicode API-Name was not shown correctly in the Backend-API overview (See issue [#113](https://github.com/Axway-API-Management-Plus/apim-cli/issues/113))
1123
- Application-Subscription not restored, when API is Republished to be updated (See issue [#114](https://github.com/Axway-API-Management-Plus/apim-cli/issues/114))
24+
- Filters not taken into consideration when deleting orgs
1225

1326
### Added
1427
- Support to use a proxy for the API-Manager communication (See issue [#109](https://github.com/Axway-API-Management-Plus/apim-cli/issues/109))

distribution/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<parent>
66
<groupId>com.github.axway-api-management-plus.apim-cli</groupId>
77
<artifactId>parent</artifactId>
8-
<version>1.3.1-SNAPSHOT</version>
8+
<version>1.3.3-SNAPSHOT</version>
99
<relativePath>../pom.xml</relativePath>
1010
</parent>
1111

modules/apim-adapter/assembly/conf/env.properties.sample

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,12 @@ admin_password=changeme
7979
# configures it according to the old API and finally clients are switched to the new API.
8080
# This new API then has a new ID and runtime quotas are lost. The configured quotas are
8181
# transferred to the new API.
82-
# zeroDowntimeUpdate=true
82+
# zeroDowntimeUpdate=true
83+
84+
# Use the following parameters to configure a proxy for the APIM CLI
85+
# You can pass them either globally in env.properties, per
86+
# stage (e.g. env.prod.properties) or individually as command-line parameters.
87+
# httpProxyHost=proxyHost
88+
# httpProxyPort=8987
89+
# httpProxyUsername=proxyUser
90+
# httpProxyPassword=proxyPassword

modules/apim-adapter/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>com.github.axway-api-management-plus.apim-cli</groupId>
66
<artifactId>parent</artifactId>
7-
<version>1.3.1-SNAPSHOT</version>
7+
<version>1.3.3-SNAPSHOT</version>
88
<relativePath>../../pom.xml</relativePath>
99
</parent>
1010

modules/apim-adapter/src/main/java/com/axway/apim/adapter/apis/APIManagerAPIAccessAdapter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ public APIAccess createAPIAccess(APIAccess apiAccess, AbstractEntity parentEntit
205205
LOG.info("Successfully created API-Access on retry. Received Status-Code: " +statusCode );
206206
}
207207
} else if(statusCode==409 && response.contains("resource already exists")) {
208-
LOG.debug("Unexpected response while creating/updating API Access: "+apiAccess+". Response-Code: "+statusCode+". Got response: '"+response+"'. Ignoring this error.");
208+
LOG.info("Unexpected response while creating/updating API Access: "+apiAccess+". Response-Code: "+statusCode+". Got response: '"+response+"'. Ignoring this error.");
209209
return apiAccess;
210210
} else {
211211
LOG.error("Error creating/updating API Access: "+apiAccess+". Response-Code: "+statusCode+". Got response: '"+response+"'");

modules/apim-adapter/src/main/java/com/axway/apim/adapter/apis/APIManagerAPIAdapter.java

Lines changed: 73 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -814,72 +814,30 @@ private JsonNode importFromSwagger(API api) throws URISyntaxException, AppExcept
814814
}
815815
}
816816

817-
public void upgradeAccessToNewerAPI(API newAPI, API oldAPI) throws AppException {
818-
if(newAPI.getState().equals(API.STATE_UNPUBLISHED)) {
819-
LOG.debug("No need to grant access to newly created API, as desired state of API is unpublished.");
820-
return;
821-
}
822-
LOG.info("Upgrade access & subscriptions to newly created API.");
823-
817+
public void upgradeAccessToNewerAPI(API apiToUpgrade, API referenceAPI) throws AppException {
818+
upgradeAccessToNewerAPI(apiToUpgrade, referenceAPI, null, null, null);
819+
// Existing applications now got access to the new API, hence we have to update the internal state
820+
// APIManagerAdapter.getInstance().addClientApplications(inTransitState, actualState);
821+
// Additionally we need to preserve existing (maybe manually created) application quotas
824822
URI uri;
825823
HttpEntity entity;
826824
RestAPICall request;
827825
HttpResponse httpResponse = null;
828-
829-
try {
830-
uri = new URIBuilder(cmd.getAPIManagerURL()).setPath(RestAPICall.API_VERSION+"/proxies/upgrade/"+oldAPI.getId()).build();
831-
832-
List<NameValuePair> params = new Vector<NameValuePair>();
833-
params.add(new BasicNameValuePair("upgradeApiId", newAPI.getId()));
834-
835-
entity = new UrlEncodedFormEntity(params, "UTF-8");
836-
837-
request = new POSTRequest(entity, uri, true);
838-
request.setContentType("application/x-www-form-urlencoded");
839-
840-
httpResponse = request.execute();
841-
int statusCode = httpResponse.getStatusLine().getStatusCode();
842-
if(statusCode != 204){
843-
String response = EntityUtils.toString(httpResponse.getEntity());
844-
if(statusCode==403 && response.contains("Unknown API")) {
845-
LOG.warn("Got unexpected error: 'Unknown API' while granting access to newer API ... Try again in 1 second.");
846-
Thread.sleep(1000);
847-
httpResponse = request.execute();
848-
statusCode = httpResponse.getStatusLine().getStatusCode();
849-
if(statusCode != 204) {
850-
LOG.error("Error upgrading access to newer API. Received Status-Code: " +statusCode + ", Response: " + EntityUtils.toString(httpResponse.getEntity()));
851-
throw new AppException("Error upgrading access to newer API. Received Status-Code: " +statusCode, ErrorCode.CANT_CREATE_BE_API);
852-
} else {
853-
LOG.info("Successfully granted access to newer API on retry. Received Status-Code: " +statusCode );
854-
}
855-
}
856-
}
857-
} catch (Exception e) {
858-
throw new AppException("Can't upgrade access to newer API!", ErrorCode.CANT_UPGRADE_API_ACCESS, e);
859-
} finally {
860-
try {
861-
if(httpResponse!=null)
862-
((CloseableHttpResponse)httpResponse).close();
863-
} catch (Exception ignore) {}
864-
}
865-
// Existing applications now got access to the new API, hence we have to update the internal state
866-
// APIManagerAdapter.getInstance().addClientApplications(inTransitState, actualState);
867-
// Additionally we need to preserve existing (maybe manually created) application quotas
868826
boolean updateAppQuota = false;
869-
if(oldAPI.getApplications().size()!=0) {
870-
LOG.debug("Found: "+oldAPI.getApplications().size()+" subscribed applications for this API. Taking over potentially configured quota configuration.");
871-
for(ClientApplication app : oldAPI.getApplications()) {
827+
if(referenceAPI.getApplications().size()!=0) {
828+
LOG.debug("Found: "+referenceAPI.getApplications().size()+" subscribed applications for this API. Taking over potentially configured quota configuration.");
829+
for(ClientApplication app : referenceAPI.getApplications()) {
872830
if(app.getAppQuota()==null) continue;
873831
// REST-API for App-Quota is also returning Default-Quotas, but we have to ignore them here!
874832
if(app.getAppQuota().getId().equals(APIManagerAdapter.APPLICATION_DEFAULT_QUOTA) || app.getAppQuota().getId().equals(APIManagerAdapter.SYSTEM_API_QUOTA)) continue;
875833
for(QuotaRestriction restriction : app.getAppQuota().getRestrictions()) {
876-
if(restriction.getApi().equals(oldAPI.getId())) { // This application has a restriction for this specific API
834+
if(restriction.getApi().equals(referenceAPI.getId())) { // This application has a restriction for this specific API
877835
updateAppQuota = true;
878-
restriction.setApi(newAPI.getId()); // Take over the quota config to new API
836+
restriction.setApi(apiToUpgrade.getId()); // Take over the quota config to new API
879837
if(!restriction.getMethod().equals("*")) { // The restriction is for a specific method
880-
String originalMethodName = APIManagerAdapter.getInstance().methodAdapter.getMethodForId(oldAPI.getId(), restriction.getMethod()).getName();
838+
String originalMethodName = APIManagerAdapter.getInstance().methodAdapter.getMethodForId(referenceAPI.getId(), restriction.getMethod()).getName();
881839
// Try to find the same operation for the newly created API based on the name
882-
String newMethodId = APIManagerAdapter.getInstance().methodAdapter.getMethodForName(newAPI.getId(), originalMethodName).getId();
840+
String newMethodId = APIManagerAdapter.getInstance().methodAdapter.getMethodForName(apiToUpgrade.getId(), originalMethodName).getId();
883841
restriction.setMethod(newMethodId);
884842
}
885843
}
@@ -911,6 +869,67 @@ public void upgradeAccessToNewerAPI(API newAPI, API oldAPI) throws AppException
911869
}
912870
}
913871

872+
public boolean upgradeAccessToNewerAPI(API apiToUpgrade, API referenceAPI, Boolean deprecateRefApi, Boolean retireRefApi, Long retirementDateRefAPI) throws AppException {
873+
if(apiToUpgrade.getState().equals(API.STATE_UNPUBLISHED)) {
874+
LOG.info("API to upgrade has state unpublished.");
875+
return false;
876+
}
877+
if(apiToUpgrade.getId().equals(referenceAPI.getId())) {
878+
LOG.warn("API to upgrade: "+Utils.getAPILogString(apiToUpgrade)+" and "
879+
+ "reference/old API: "+Utils.getAPILogString(referenceAPI)+" are the same. Skip upgrade access to newer API.");
880+
return false;
881+
}
882+
LOG.debug("Upgrade access & subscriptions to API: " + apiToUpgrade.getName() + " " + apiToUpgrade.getVersion() + "("+apiToUpgrade.getId()+")");
883+
884+
URI uri;
885+
HttpEntity entity;
886+
RestAPICall request;
887+
HttpResponse httpResponse = null;
888+
try {
889+
uri = new URIBuilder(cmd.getAPIManagerURL()).setPath(RestAPICall.API_VERSION+"/proxies/upgrade/"+referenceAPI.getId()).build();
890+
891+
List<NameValuePair> params = new Vector<NameValuePair>();
892+
params.add(new BasicNameValuePair("upgradeApiId", apiToUpgrade.getId()));
893+
if(deprecateRefApi != null) params.add(new BasicNameValuePair("deprecate", deprecateRefApi.toString()));
894+
if(retireRefApi != null) params.add(new BasicNameValuePair("retire", retireRefApi.toString()));
895+
if(retirementDateRefAPI != null) params.add(new BasicNameValuePair("retirementDate", formatRetirementDate(retirementDateRefAPI)));
896+
897+
entity = new UrlEncodedFormEntity(params, "UTF-8");
898+
899+
request = new POSTRequest(entity, uri, true);
900+
request.setContentType("application/x-www-form-urlencoded");
901+
902+
httpResponse = request.execute();
903+
int statusCode = httpResponse.getStatusLine().getStatusCode();
904+
if(statusCode != 204){
905+
String response = EntityUtils.toString(httpResponse.getEntity());
906+
if(statusCode==403 && response.contains("Unknown API")) {
907+
LOG.warn("Got unexpected error: 'Unknown API' while granting access to newer API ... Try again in 1 second.");
908+
Thread.sleep(1000);
909+
httpResponse = request.execute();
910+
statusCode = httpResponse.getStatusLine().getStatusCode();
911+
if(statusCode != 204) {
912+
LOG.error("Error upgrading access to newer API. Received Status-Code: " +statusCode + ", Response: " + EntityUtils.toString(httpResponse.getEntity()));
913+
throw new AppException("Error upgrading access to newer API. Received Status-Code: " +statusCode, ErrorCode.CANT_CREATE_BE_API);
914+
} else {
915+
LOG.info("Successfully granted access to newer API on retry. Received Status-Code: " +statusCode );
916+
}
917+
} else {
918+
LOG.error("Error upgrading access to newer API. Received Status-Code: " +statusCode + ", Response: " + response);
919+
throw new AppException("Error upgrading access to newer API. Received Status-Code: " +statusCode, ErrorCode.CANT_CREATE_BE_API);
920+
}
921+
}
922+
return true;
923+
} catch (Exception e) {
924+
throw new AppException("Can't upgrade access to newer API!", ErrorCode.CANT_UPGRADE_API_ACCESS, e);
925+
} finally {
926+
try {
927+
if(httpResponse!=null)
928+
((CloseableHttpResponse)httpResponse).close();
929+
} catch (Exception ignore) {}
930+
}
931+
}
932+
914933
public void grantClientOrganization(List<Organization> grantAccessToOrgs, API api, boolean allOrgs) throws AppException {
915934
URI uri;
916935
HttpEntity entity;

modules/apim-adapter/src/main/java/com/axway/apim/adapter/apis/APIManagerConfigAdapter.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,15 @@ public APIManagerConfigAdapter() {}
4848
Map<Boolean, Config> managerConfig = new HashMap<Boolean, Config>();
4949

5050

51-
private static enum ConfigFields {
52-
version77 ("7.7.0", new String[] {"userNameRegex", "apiImportTimeout", "apiImportMimeValidation", "apiImportEditable", "lockUserAccount" }),
53-
version762 ("7.6.2", new String[] {
54-
"changePasswordOnFirstLogin", "passwordExpiryEnabled", "passwordLifetimeDays", "applicationScopeRestrictions", "strictCertificateChecking",
55-
"serverCertificateVerification", "advisoryBannerEnabled", "advisoryBannerText"
51+
/**
52+
* Config fields that were introduced with a certain API-Manager version.
53+
* This list is mainly used to filter out fields, when using an older API-Manager version.
54+
*/
55+
protected static enum ConfigFields {
56+
version7720200130 ("7.7.20200130", new String[] {"apiImportTimeout", "apiImportMimeValidation", "apiImportEditable", "lockUserAccount" }),
57+
version77 ("7.7.0", new String[] {
58+
"userNameRegex", "changePasswordOnFirstLogin", "passwordExpiryEnabled", "passwordLifetimeDays",
59+
"applicationScopeRestrictions", "strictCertificateChecking", "serverCertificateVerification", "advisoryBannerEnabled", "advisoryBannerText"
5660
});
5761

5862
private String[] ignoreFields;
@@ -70,11 +74,11 @@ public String getManagerVersion() {
7074
public static String[] getIgnoredFields() {
7175
String[] restrictedFields = new String[] {};
7276
for(ConfigFields fields : values()) {
73-
restrictedFields = ArrayUtils.addAll(restrictedFields, fields.ignoreFields);
7477
// Add all ignore fields until we reached the used API-Manager version
7578
if(APIManagerAdapter.hasAPIManagerVersion(fields.getManagerVersion())) {
7679
break;
7780
}
81+
restrictedFields = ArrayUtils.addAll(restrictedFields, fields.ignoreFields);
7882
}
7983
return restrictedFields;
8084
}

modules/apim-adapter/src/main/java/com/axway/apim/api/API.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import com.axway.apim.api.model.TagMap;
2323
import com.axway.apim.api.model.apps.ClientApplication;
2424
import com.axway.apim.lib.APIPropertyAnnotation;
25-
import com.axway.apim.lib.errorHandling.AppException;
2625
import com.fasterxml.jackson.annotation.JsonAlias;
2726
import com.fasterxml.jackson.annotation.JsonFilter;
2827
import com.fasterxml.jackson.annotation.JsonIgnore;

modules/apim-adapter/src/main/java/com/axway/apim/lib/utils/Utils.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,27 @@
77
import java.net.URLDecoder;
88
import java.nio.charset.StandardCharsets;
99
import java.nio.file.Files;
10+
import java.text.ParseException;
11+
import java.text.SimpleDateFormat;
12+
import java.time.ZoneId;
13+
import java.util.Arrays;
14+
import java.util.Date;
1015
import java.util.HashMap;
1116
import java.util.Iterator;
1217
import java.util.LinkedHashMap;
1318
import java.util.List;
19+
import java.util.Locale;
1420
import java.util.Map;
1521
import java.util.Scanner;
22+
import java.util.TimeZone;
1623

1724
import org.apache.commons.text.StringSubstitutor;
1825
import org.slf4j.Logger;
1926
import org.slf4j.LoggerFactory;
2027

2128
import com.axway.apim.adapter.APIManagerAdapter;
2229
import com.axway.apim.api.model.CustomProperties.Type;
30+
import com.axway.apim.api.API;
2331
import com.axway.apim.api.model.CustomPropertiesEntity;
2432
import com.axway.apim.api.model.CustomProperty;
2533
import com.axway.apim.api.model.CustomProperty.Option;
@@ -239,4 +247,31 @@ public static void addCustomPropertiesForEntity(List<? extends CustomPropertiesE
239247
entity.setCustomProperties((customProperties.size()==0) ? null : customProperties);
240248
}
241249
}
250+
251+
public static Long getParsedDate(String date) throws AppException {
252+
List<String> dateFormats = Arrays.asList("dd.MM.yyyy", "dd/MM/yyyy", "yyyy-MM-dd", "dd-MM-yyyy");
253+
SimpleDateFormat format;
254+
Date retDate = null;
255+
for (String dateFormat : dateFormats) {
256+
format = new SimpleDateFormat(dateFormat, Locale.US);
257+
format.setTimeZone(TimeZone.getTimeZone(ZoneId.of("Z")));
258+
try {
259+
retDate = format.parse(date);
260+
} catch (ParseException e) { }
261+
if(retDate!=null && retDate.after(new Date())) {
262+
LOG.info("Parsed retirementDate: '"+date+"' using format: '"+dateFormat+"' to: '"+retDate+"'");
263+
break;
264+
}
265+
}
266+
if(retDate==null || retDate.before(new Date())) {
267+
ErrorState.getInstance().setError("Unable to parse the given retirementDate using the following formats: " + dateFormats, ErrorCode.CANT_READ_CONFIG_FILE, false);
268+
throw new AppException("Cannnot parse given retirementDate", ErrorCode.CANT_READ_CONFIG_FILE);
269+
}
270+
return retDate.getTime();
271+
}
272+
273+
public static String getAPILogString(API api) {
274+
if(api==null) return "N/A";
275+
return api.getName() + " " + api.getVersion() + " ("+api.getVersion()+")";
276+
}
242277
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.axway.apim.adapter.apis;
2+
3+
import org.testng.Assert;
4+
import org.testng.annotations.Test;
5+
6+
import com.axway.apim.adapter.APIManagerAdapter;
7+
8+
public class APIManagerConfigAdapterTest {
9+
10+
@Test
11+
public void testCorrectFieldsAreIgnored() {
12+
APIManagerAdapter.apiManagerVersion = "7.7.20200930";
13+
String[] ignoreFields = APIManagerConfigAdapter.ConfigFields.getIgnoredFields();
14+
// No field should be ignored for the Sept-Release
15+
Assert.assertNotNull(ignoreFields);
16+
Assert.assertEquals(ignoreFields.length, 0);
17+
18+
APIManagerAdapter.apiManagerVersion = "7.7.20200730";
19+
ignoreFields = APIManagerConfigAdapter.ConfigFields.getIgnoredFields();
20+
// Same for July, as fields have been added in January release
21+
Assert.assertNotNull(ignoreFields);
22+
Assert.assertEquals(ignoreFields.length, 0);
23+
24+
APIManagerAdapter.apiManagerVersion = "7.7.0";
25+
ignoreFields = APIManagerConfigAdapter.ConfigFields.getIgnoredFields();
26+
// 7.7.0 plain already supports some new settings
27+
Assert.assertNotNull(ignoreFields);
28+
Assert.assertEquals(ignoreFields.length, 4); // Only brand new fields are returned to be ignored
29+
30+
APIManagerAdapter.apiManagerVersion = "7.6.2";
31+
ignoreFields = APIManagerConfigAdapter.ConfigFields.getIgnoredFields();
32+
Assert.assertNotNull(ignoreFields);
33+
// 7.6.2 doesn't support all of the new fields
34+
Assert.assertEquals(ignoreFields.length, 13);
35+
}
36+
}

0 commit comments

Comments
 (0)