Added enableSoftDelete, DeletedVault, and Purge to method group#432
Added enableSoftDelete, DeletedVault, and Purge to method group#432anuchandy merged 16 commits intoAzure:kv2018from
Conversation
| * authenticating requests to the key vault. | ||
| */ | ||
| String tenantId(); | ||
| UUID tenantId(); |
There was a problem hiding this comment.
Changing return type of an existing property is a breaking change. Key-vault Fluent Mgmt lib is GA-ed, so we might want to wait for next major version upgrade of fluent lib for this. Can we convert to it string like inner.tenantId.toString() in impl and return.
| * @param tenantId the tenant ID for the key vault. | ||
| * @return the next stage of access policy definition | ||
| */ | ||
| WithAttach<ParentT> forTenantId(UUID tenantId); |
There was a problem hiding this comment.
should we use string as param type instead of UUID [for tenantId, applicationId]? to be consistent with the property getter return type.
| /** | ||
| * @return whether soft delete is enabled for this key vault. | ||
| */ | ||
| boolean softDeleteEnabled(); |
There was a problem hiding this comment.
To be consistent with naming pattern of other existing properties returning bool (e.g. enabledForDeployment, enabledForDiskEncryption, enabledForTemplateDeployment), should we rename these new getters, like purgeProtectionEnabled -> enabledForPurgeProtection, softDeleteEnabled -> enabledForSoftDelete
There was a problem hiding this comment.
@schaabs and I discussed this a bit and decided to go with this pattern to make it consistent with our other languages.
There was a problem hiding this comment.
@tiffanyachen in this case you need to be consistent with the rest of the Java SDK naming patterns for this service and not other languages. There's a good reason and lots of review discussions before we chose the naming we use today. So unless you want to change all the other method names and introduce your own new naming pattern, then work around the backward compatibility breaks resulted from these change, then my recommendation is to stay with @anuchandy feedback.
There was a problem hiding this comment.
@anuchandy @milismsft In the case of the first three fields, enableForDeployment, enabledForDiskEncryption, and enabledForTemplateDeployment, they are named this way because the user is enabling the vault to be accesed FOR arm deployments, disk encryption, and template deployment. In the case of softDeleteEnabled and purgeProtectionEnabled the user is enabling the features soft delete and purge protection on the vault.
There was a problem hiding this comment.
@schaabs I don't understand how is soft delete any different then the others... It looks like it is required for instance when setting up SQL TDE (see customer report Azure/azure-libraries-for-net#315).
If "soft delete" and "purge protection" are simple vault properties it might be worth removing the whole "enabled" thing from the name, i.e "bool softDelete()" and "bool purgeProtection()".
There was a problem hiding this comment.
Also the "with" methods could be renamed as "withSoftDelete()" and "withPurgeProtection()" IF these properties are indeed vault only properties.
| * | ||
| * @return the next stage of key vault definition | ||
| */ | ||
| Update withSoftDeleteEnabled(); |
There was a problem hiding this comment.
Is it possible to disable soft delete once enabled? if so we may need withSoftDeleteDisabled, withPurgeProtectionDisabled
There was a problem hiding this comment.
SoftDelete and PurgeProtection can't be disabled.
| @Fluent(ContainerName = "/Microsoft.Azure.Management.Fluent.KeyVault") | ||
| public interface Vaults extends | ||
| SupportsCreating<Vault.DefinitionStages.Blank>, | ||
| SupportsDeletingById, |
There was a problem hiding this comment.
We should not remove SupportsDeletingById support, this is a breaking change and keyVault lib is GA-ed.
| public String id() { | ||
| return inner().id(); | ||
| } | ||
|
|
There was a problem hiding this comment.
Indentation should be 4 space.
There was a problem hiding this comment.
You can run mvn checkstyle:check from the project root to catch coding style (e.g. indentation) violations.
| if (inner().properties() == null || inner().properties().enableSoftDelete() == null) { | ||
| return false; | ||
| } | ||
| return inner().properties().enableSoftDelete(); |
There was a problem hiding this comment.
We can use utility method to simplify this, like
if (inner().properties() == null) {
return false;
}
return Utils.toPrimitiveBoolean(inner().properties().enableSoftDelete());
| if (inner().getDeleted(vaultName, location) == null) { | ||
| return null; | ||
| } | ||
| return (DeletedVault) new DeletedVaultImpl(inner().getDeleted(vaultName, location)); |
There was a problem hiding this comment.
Seems we are making two api calls, we could have something like
DeletedVaultInner deletedVault = inner().getDeleted(vaultName, location);
if (deletedVault == null) {
return null;
} else {
return new DeletedVaultImpl(deletedVault);
}
|
|
||
| // DELETE | ||
| keyVaultManager.vaults().delete(RG_NAME, VAULT_NAME); | ||
| Thread.sleep(20000); |
There was a problem hiding this comment.
To avoid sleeping while running in mock mode we can use SdkContext.sleep(20000) here.
| } | ||
| }; | ||
| return converter.convert(listDeleted); | ||
| } |
There was a problem hiding this comment.
This is correct.
Just make sure we are not using the name wrapPage, we could move converter variable def to public PagedList<DeletedVault> listDeleted() method.
| * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent | ||
| * @return the DeletedVaultInner object if successful. | ||
| */ | ||
| public DeletedVault getDeleted(String vaultName, String location); |
There was a problem hiding this comment.
Async:
public Observable<DeletedVault> getDeletedAsync(String vaultName, String location) {
VaultsInner client = this.inner();
return client.getDeletedAsync(vaultName, location)
.map(new Func1<DeletedVaultInner, DeletedVault>() {
@Override
public DeletedVault call(DeletedVaultInner inner) {
return new DeletedVaultImpl(inner);
}
});
}| * @throws CloudException thrown if the request is rejected by server | ||
| * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent | ||
| */ | ||
| public void purgeDeleted(String vaultName, String location); |
There was a problem hiding this comment.
Async
public Completable purgeDeletedAsync(String vaultName, String location) {
VaultsInner client = this.inner();
return client.purgeDeletedAsync(vaultName, location).toCompletable();
}| HasManager<KeyVaultManager>, | ||
| HasInner<VaultsInner> { | ||
|
|
||
| public PagedList<DeletedVault> listDeleted(); |
There was a problem hiding this comment.
Async:
public Observable<DeletedVault> listDeletedAsync() {
VaultsInner client = this.inner();
return client.listDeletedAsync()
.flatMap(new Func1<Page<DeletedVaultInner>, Observable<Page<DeletedVaultInner>>>() {
@Override
public Observable<Page<DeletedVaultInner>> call(Page<DeletedVaultInner> page) {
return listDeletedNextInnerPageAsync(page.nextPageLink());
}
})
.flatMapIterable(new Func1<Page<DeletedVaultInner>, Iterable<DeletedVaultInner>>() {
@Override
public Iterable<DeletedVaultInner> call(Page<DeletedVaultInner> page) {
return page.items();
}
})
.map(new Func1<DeletedVaultInner, DeletedVault>() {
@Override
public DeletedVault call(DeletedVaultInner inner) {
return new DeletedVaultImpl(inner);
}
});
} private Observable<Page<DeletedVaultInner>> listDeletedNextInnerPageAsync(String nextLink) {
if (nextLink == null) {
Observable.empty();
}
VaultsInner client = this.inner();
return client.listDeletedNextAsync(nextLink)
.flatMap(new Func1<Page<DeletedVaultInner>, Observable<Page<DeletedVaultInner>>>() {
@Override
public Observable<Page<DeletedVaultInner>> call(Page<DeletedVaultInner> page) {
return Observable.just(page).concatWith(listDeletedNextInnerPageAsync(page.nextPageLink()));
}
});
}
anuchandy
left a comment
There was a problem hiding this comment.
@tiffanyachen - please note that in fluent lib the only async option we expose is RX based (Observable), we will not expose Future based model to customer. The idea is keep the fluent lib simple by exposing one way to do async, and if customers needed they can convert Observable to future using well know operators.
The only additional work we need to do here is expose async and sync for resource specific actions. In case of Vault they are listing deleted vaults, purge a vault and check name availability.
| * @throws IllegalArgumentException thrown if parameters fail the validation | ||
| * @return the observable for the request | ||
| */ | ||
| public Observable<ServiceResponse<Vault>> createOrUpdateWithServiceResponseAsync(String resourceGroupName, String vaultName, VaultCreateOrUpdateParameters parameters); |
There was a problem hiding this comment.
We should not expose any of the createOrUpdate variants, the reason is - we have a standard pattern to create [vaults().define(..)..createAsync()] and update [vault.update()..applyAsync()] any resource. We've already exposed them for vaults.
The guideline is - (1) in fluent lib underlying creareOrUpdate should not be exposed as it is, it has to be wrapped in standard fluent patterns.
(2) In fluent layer we will not expose Future based async option, only async option available will be Rx based. Customer can convert Observable<Vault> returned by define.createAsync() and update()..applyAsync() to future using well-known rx operators.
There was a problem hiding this comment.
What about async methods that take a callback and are exposed by VaultsInner?
There was a problem hiding this comment.
Idea is we expose only one way of doing async programming which is rx. If customer want they can convert rx observable to call back in their application layer. like:
ServiceFuture.fromBody(apiCallthatReturnsRxType(params), callback)
| * @return the observable to the Vault object | ||
| */ | ||
| public Observable<ServiceResponse<Vault>> updateWithServiceResponseAsync(String resourceGroupName, String vaultName, VaultPatchParameters parameters); | ||
|
|
There was a problem hiding this comment.
Same comment for update as well, it is already supported via standard fluent update()..apply() pattern.
General guideline is - In fluent layer we will not expose Future based async option, only async option available will be Rx based. Customer can convert Observable returned by update()..applyAsync() to future using well-known rx operators.
| * @throws IllegalArgumentException thrown if parameters fail the validation | ||
| * @return the {@link ServiceResponse} object if successful. | ||
| */ | ||
| public Observable<ServiceResponse<Void>> deleteWithServiceResponseAsync(String resourceGroupName, String vaultName); |
There was a problem hiding this comment.
Delete sync and async are already exposed via standard fluent methods Vaults().deleteByResourceGroup(), vaults.deletebyId(), so these three methods does not have to be exposed like this.
General guideline is - In fluent layer we will not expose Future based async option, only async option available will be Rx based. Customer can convert Completable returned by delete to future using well-known rx operators.
| * @throws IllegalArgumentException thrown if parameters fail the validation | ||
| * @return the observable to the Vault object | ||
| */ | ||
| public Observable<Vault> getByResourceGroupAsync(String resourceGroupName, String vaultName); |
There was a problem hiding this comment.
Vaults already implements SupportsGettingByResourceGroup
hence this explicit methods are not needed
General guideline is - In fluent layer we will not expose Future based async option, only async option available will be Rx based. Customer can convert Observable returned by SupportsGettingByResourceGroup.GetByResourceGrouoAsync to future using well-known rx operators.
| * @throws IllegalArgumentException thrown if parameters fail the validation | ||
| * @return the PagedList<Vault> object wrapped in {@link ServiceResponse} if successful. | ||
| */ | ||
| public Observable<ServiceResponse<Page<Vault>>> listByResourceGroupSinglePageAsync(final String resourceGroupName); |
There was a problem hiding this comment.
Vaults already implements SupportsListByResourceGroup
hence this explicit methods are not needed
| * @return the observable to the VaultAccessPolicyParameters object | ||
| */ | ||
| public Observable<ServiceResponse<VaultAccessPolicyParameters>> updateAccessPolicyWithServiceResponseAsync(String resourceGroupName, String vaultName, AccessPolicyUpdateKind operationKind, VaultAccessPolicyProperties properties); | ||
|
|
There was a problem hiding this comment.
create, update and delete of access policy is already exposed as a child operation on keyVault
hence no need to expose them like this|
@tiffanyachen I have a similar change that only addresses enabling soft delete and purge protection at milismsft@b52185b. Would you be able to incorporate it into your changes? |
|
|
||
| /** | ||
| * Wrapper for CheckNameAvailabilityResultInner | ||
| * @author tifchen |
There was a problem hiding this comment.
Can you please remove this comment and change the overall description of the method to something like "The result of checking for the Key Vault name availability."?
| @Fluent(ContainerName = "/Microsoft.Azure.Management.Fluent.KeyVault") | ||
| public interface CheckNameAvailabilityResult extends | ||
| HasInner<CheckNameAvailabilityResultInner>{ | ||
|
|
There was a problem hiding this comment.
I would expect to see here some methods such as isAvailable(), unavailabilityReason() and unavailabilityMessage()...
|
@milismsft See @schaabs comment's above regarding property names; ManageSqlServerKeysWithAzureKeyVaultKey.java's changes we can add. |
…ts, updates to checkNameAvailabilityResult
| HasInner<DeletedVaultInner>, | ||
| HasName, | ||
| HasId { | ||
|
|
There was a problem hiding this comment.
@tiffanyachen In Fluent we try to avoid exposing the users to the *Inner classes (or any other class that is part of the "implementation" folder except for the *Manager). In this particular case we can "promote" the DeletedVaultProperties properties as methods of this interface rather than having the user navigate through two levels of indirection in order to reach them (one being the .inner()). Would you be able to add the corresponding methods please? The exact mapping is:
location() -> inner().properties().location()
deleteDate() ->inner().properties().deleteDate()
scheduledPurgeDate() -> inner().properties().scheduledPurgeDate()
tags() -> inner().properties().tags()
| * | ||
| * @return the next stage of key vault definition | ||
| */ | ||
| WithCreate withCreateMode(CreateMode createMode); |
There was a problem hiding this comment.
@tiffanyachen Could CreateMode.RECOVER be used with an existing Key Vault resource that has not been deleted? What impact other settings prior to reaching this method during the create flow will have when this value is set?
There was a problem hiding this comment.
This can only be used for recovering a deleted vault with soft delete enabled; in any other case it'll result in an error.
There was a problem hiding this comment.
@tiffanyachen If this is the case then we will have to rework a bit the "Create()" flow. What's the maximum properties in the JSON body that can be passed to the create op when CreateMode.RECOVER is specified?
Basically we will need to think of a way to shortcut the current create flow for the user to be able to use this setting. I'm thinking it might be worth having a separate set of methods as part of Vaults.java something like recoverDeletedVault(resourceGroupName, vaultName) or recoverSoftDeletedVault() (plus the Async one), instead of expecting the user to specify the CreateMode via the define()/create() flow... Because I don't see the later how it will ever succeed when we ask the user for SKU and other stuff before it can reach to withCreateMode().
| new PagedListConverter<DeletedVaultInner, DeletedVault> () { | ||
| @Override | ||
| public Observable<DeletedVault> typeConvertAsync(DeletedVaultInner inner) { | ||
| return Observable.just((DeletedVault) new DeletedVaultImpl(inner)); |
There was a problem hiding this comment.
@tiffanyachen the cast is not needed here (if DeletedVaultImpl class implements DeletedVault interface).
|
@tiffanyachen the Travis build is failing because of check-style errors; you can try to reproduce them locally by executing "mvn checkstyle:check". |
| * @throws IllegalArgumentException thrown if parameters fail the validation | ||
| * @return the observable to the PagedList<DeletedVault> object | ||
| */ | ||
| public Observable<ServiceResponse<Page<DeletedVault>>> listDeletedWithServiceResponseAsync(); |
There was a problem hiding this comment.
@tiffanyachen Same here, we can remove this method as well.
| * @throws IllegalArgumentException thrown if parameters fail the validation | ||
| * @return the {@link ServiceFuture} object | ||
| */ | ||
| public ServiceFuture<List<DeletedVault>> listDeletedAsync(final ListOperationCallback<DeletedVault> serviceCallback); |
There was a problem hiding this comment.
@tiffanyachen Let's remove this method since we don't need to expose it in the Fluent implementation.
| * @throws IllegalArgumentException thrown if parameters fail the validation | ||
| * @return the PagedList<DeletedVault> object wrapped in {@link ServiceResponse} if successful. | ||
| */ | ||
| public Observable<ServiceResponse<Page<DeletedVault>>> listDeletedSinglePageAsync(); |
| * @throws IllegalArgumentException thrown if parameters fail the validation | ||
| * @return the PagedList<DeletedVault> object wrapped in {@link ServiceResponse} if successful. | ||
| */ | ||
| public Observable<ServiceResponse<Page<DeletedVault>>> listDeletedNextSinglePageAsync(final String nextPageLink); |
| * @throws IllegalArgumentException thrown if parameters fail the validation | ||
| * @return the observable to the DeletedVault object | ||
| */ | ||
| public Observable<ServiceResponse<DeletedVault>> getDeletedWithServiceResponseAsync(String vaultName, String location); |
| * @throws IllegalArgumentException thrown if parameters fail the validation | ||
| * @return the observable for the request | ||
| */ | ||
| public Observable<ServiceResponse<Void>> purgeDeletedWithServiceResponseAsync(String vaultName, String location); |
There was a problem hiding this comment.
please remove, not needed for Fluent.
| * @throws IllegalArgumentException thrown if parameters fail the validation | ||
| * @return the {@link ServiceFuture} object | ||
| */ | ||
| public ServiceFuture<CheckNameAvailabilityResult> checkNameAvailabilityAsync(String name, final ServiceCallback<CheckNameAvailabilityResult> serviceCallback); |
There was a problem hiding this comment.
please remove, not needed for Fluent.
| * @throws IllegalArgumentException thrown if parameters fail the validation | ||
| * @return the observable to the CheckNameAvailabilityResult object | ||
| */ | ||
| public Observable<ServiceResponse<CheckNameAvailabilityResult>> checkNameAvailabilityWithServiceResponseAsync(String name); |
There was a problem hiding this comment.
please remove, not needed for Fluent.
| * @throws IllegalArgumentException thrown if parameters fail the validation | ||
| * @return the {@link ServiceFuture} object | ||
| */ | ||
| public ServiceFuture<List<DeletedVault>> listDeletedNextAsync(final String nextPageLink, final ServiceFuture<List<DeletedVault>> serviceFuture, final ListOperationCallback<DeletedVault> serviceCallback); |
There was a problem hiding this comment.
please remove, not needed for Fluent.
| * @throws IllegalArgumentException thrown if parameters fail the validation | ||
| * @return the observable to the PagedList<DeletedVault> object | ||
| */ | ||
| public Observable<ServiceResponse<Page<DeletedVault>>> listDeletedNextWithServiceResponseAsync(final String nextPageLink); |
There was a problem hiding this comment.
please remove, not needed for Fluent.
| @Fluent(ContainerName = "/Microsoft.Azure.Management.Fluent.KeyVault") | ||
| public interface VaultAccessPolicyParameters extends | ||
| HasInner<VaultAccessPolicyParametersInner>{ | ||
|
|
There was a problem hiding this comment.
@tiffanyachen similar comments I made about the DeletedVault interface; we should "promote" the properties from VaultAccessPolicyPropertiesInner class as methods of this interface. Also the interface should extend HasId(), HasName() and expose type() and location().
|
@tiffanyachen, @schaabs PR is good, just approved it. You can ignore the CI failures (which are not related to key vault), when we merge kv2018 back to master, we will make sure its green. |
* Generate key vault 2018-02-14-preview * kv2018 Sync with upstream master (#446) * Added namespace filtering for Monitor Metrics query. (#427) * Added namespace filtering for Monitor Metrics query. * re-recorded test * Regenerated Batch from swagger tag=package-2017-09 (#429) * Regenerated Batch from swagger tag=package-2017-09 * Re-recorded tests. * Re-recorded Batch sample. * Fix JavaDoc NPE exception when generating JavaDoc under JDK 9 (#410) * Fix use of ampersand characters in JavaDoc by replacing with & * Update JavaDoc comment that incorrectly attempts to use @link to reference a type U, where U is not a class that can be looked up. This results in a JavaDoc NPE when using JDK 9, preventing JavaDoc from being generated for this library due to the issue discussed at https://bugs.openjdk.java.net/browse/JDK-8188248 * Updating Network (#428) * Added application security groups * Added route filters * Added route filter rules * checkstyle * Adding list availbale providers for network watcher * Adding reachability report for network watcher * checkstyle * Connection Monitor for Network Watcher * test for Connection Monitor * Adding DDoS protection plans * Adding disableBgpRoutePropagation property to RouteTable * checkstyle * Adding DDoS protection plans and VM protection * remoteAddressSpace property for NetworkPeering * updateTags() for LocalNetworkGateway * updateTags() for Network * updateTags() for ExpressRouteCircuit, NetworkSecurityGroup, PublicIPAddress, NetworkWatcher, VirtualNetworkGateway * updateTags() for NetworkInterface * updateTags() for RouteTable * checkstyle * updateTags() for LoadBalancer, ApplicationGateway and VirtualNetworkGatewayConnection Protocol setter for connectivity check * ipTags for PublicIPAddress * adding application security groups for NetworkInterface * fixing build * session record * addressing code review * Add implementation to create Cassandra, Azure Table and Gremlin data model CosmosDB accounts. (#431) * Batch AI bugfix (#434) * Batch AI bugfix * Batch AI bugfix * Batch AI usages operation * Addressing code review * Adding new Australia Central regions (#436) * Re-record multiple wars test (#440) * Readme 1.10 (#439) * Readme 1.10 (#437) first draft * adding changes for Batch AI * updating migration notes * Up versions * [maven-release-plugin] prepare release v1.10.0 * [maven-release-plugin] prepare for next development iteration * AKS: Kubernetes versions support (#442) * Add new Kubernetes versions and implement overload to pass the version as a string value. * ACI: refactoring and add support for launchExec() operation. (#444) * Refactoring and add support for launchExec() operation. * Added storage method annotation to Fluent flow (#443) * Added storage method annotation to Fluent flow * Added more Method annotation to Storage * Added enableSoftDelete, DeletedVault, and Purge to method group (#432) * Added enableSoftDelete, DeletedVault, and Purge to method group * re-recorded tests * Updates from code review * Updated access policy to include storage * Moved converter for DeletedVaultInner * Added async methods * Removed unecessary async methods and SupportsListing<Vault> from Vaults, updates to checkNameAvailabilityResult * Simplified async access and elevated properties for Vault and DeletedVault * Updated checkstyle * Elevated access policies * Moved recovery of softDeletedVault to independent method * Changed purgeDeletedAsync to return Completable * Removed unused interfaces and added beta annotations * Unused imports in vaultImpl * Updated javadocs for accessPolicy * Kv2018 acl update (#449) * Added networkAcl access create/update * Updated network acls by elevating inner props * Vault had extraneous method * Fixed javadoc errors for keyvault * Corrected and rerecorded tests * Moving the wrap deployment portion of app-service test to run only on live
No description provided.