Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tables list/get access policies changes #22161

Merged
merged 9 commits into from
Jun 9, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,6 @@ static HttpPipeline buildPipeline(
httpHeaderList.add(new HttpHeader(header.getName(), header.getValue())));
}

// TODO: Remove the Accept header after making sure the JacksonAdapter can handle not setting such value.
policies.add(new AddHeadersPolicy(new HttpHeaders(httpHeaderList).set("Accept", "application/json")));

// Add per call additional policies.
policies.addAll(perCallAdditionalPolicies);
HttpPolicyProviders.addBeforeRetryPolicies(policies);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import com.azure.core.http.HttpRequest;
import com.azure.core.http.rest.PagedFlux;
import com.azure.core.http.rest.PagedResponse;
import com.azure.core.http.rest.PagedResponseBase;
import com.azure.core.http.rest.Response;
import com.azure.core.http.rest.SimpleResponse;
import com.azure.core.util.Context;
Expand Down Expand Up @@ -57,17 +56,15 @@
import reactor.core.publisher.Mono;

import java.net.URI;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.azure.core.util.CoreUtils.isNullOrEmpty;
import static com.azure.core.util.FluxUtil.fluxContext;
import static com.azure.core.util.FluxUtil.monoError;
import static com.azure.core.util.FluxUtil.pagedFluxError;
import static com.azure.core.util.FluxUtil.withContext;
import static com.azure.data.tables.implementation.TableUtils.swallowExceptionForStatusCode;
import static com.azure.data.tables.implementation.TableUtils.toTableServiceError;
Expand Down Expand Up @@ -845,41 +842,47 @@ <T extends TableEntity> Mono<Response<T>> getEntityWithResponse(String partition
* Retrieves details about any stored access policies specified on the table that may be used with Shared Access
* Signatures.
*
* @return A paged reactive result containing the HTTP response and the table's
* @return A reactive result containing the table's {@link TableSignedIdentifier access policies}.
*/
@ServiceMethod(returns = ReturnType.COLLECTION)
vcolin7 marked this conversation as resolved.
Show resolved Hide resolved
public Mono<List<TableSignedIdentifier>> listAccessPolicies() {
vcolin7 marked this conversation as resolved.
Show resolved Hide resolved
return withContext(context -> listAccessPoliciesWithResponse(context)
.flatMap(response -> Mono.justOrEmpty(response.getValue())));
}

/**
* Retrieves details about any stored access policies specified on the table that may be used with Shared Access
* Signatures.
*
* @return A reactive result containing the HTTP response and the table's
* {@link TableSignedIdentifier access policies}.
*/
@ServiceMethod(returns = ReturnType.COLLECTION)
public PagedFlux<TableSignedIdentifier> listAccessPolicies() {
return (PagedFlux<TableSignedIdentifier>) fluxContext(this::listAccessPolicies);
public Mono<Response<List<TableSignedIdentifier>>> listAccessPoliciesWithResponse() {
return withContext(this::listAccessPoliciesWithResponse);
}

PagedFlux<TableSignedIdentifier> listAccessPolicies(Context context) {
Mono<Response<List<TableSignedIdentifier>>> listAccessPoliciesWithResponse(Context context) {
context = context == null ? Context.NONE : context;

try {
Context finalContext = context;
Function<String, Mono<PagedResponse<TableSignedIdentifier>>> retriever =
marker ->
tablesImplementation.getTables()
.getAccessPolicyWithResponseAsync(tableName, null, null, finalContext)
.map(response -> new PagedResponseBase<>(response.getRequest(),
response.getStatusCode(),
response.getHeaders(),
response.getValue().stream()
.map(this::toTableSignedIdentifier)
.collect(Collectors.toList()),
null,
response.getDeserializedHeaders()));

return new PagedFlux<>(() -> retriever.apply(null), retriever);
return tablesImplementation.getTables()
.getAccessPolicyWithResponseAsync(tableName, null, null, context)
.map(response -> {
List<SignedIdentifier> signedIdentifiers = response.getValue();

return new SimpleResponse<>(response,
signedIdentifiers == null ? null : signedIdentifiers.stream()
.map(this::toTableSignedIdentifier)
.collect(Collectors.toList()));
});
} catch (RuntimeException e) {
return pagedFluxError(logger, e);
return monoError(logger, e);
}
}

private TableSignedIdentifier toTableSignedIdentifier(SignedIdentifier signedIdentifier) {
return new TableSignedIdentifier()
.setId(signedIdentifier.getId())
return new TableSignedIdentifier(signedIdentifier.getId())
.setAccessPolicy(toTableAccessPolicy(signedIdentifier.getAccessPolicy()));
}

Expand Down Expand Up @@ -918,11 +921,34 @@ public Mono<Response<Void>> setAccessPoliciesWithResponse(List<TableSignedIdenti
Mono<Response<Void>> setAccessPoliciesWithResponse(List<TableSignedIdentifier> tableSignedIdentifiers,
Context context) {
context = context == null ? Context.NONE : context;
List<SignedIdentifier> signedIdentifiers = null;

/*
We truncate to seconds because the service only supports nanoseconds or seconds, but doing an
OffsetDateTime.now will only give back milliseconds (more precise fields are zeroed and not serialized). This
allows for proper serialization with no real detriment to users as sub-second precision on active time for
signed identifiers is not really necessary.
*/
if (tableSignedIdentifiers != null) {
signedIdentifiers = tableSignedIdentifiers.stream()
.map(this::toSignedIdentifier)
.collect(Collectors.toList());

for (SignedIdentifier identifier : signedIdentifiers) {
if (identifier.getAccessPolicy() != null && identifier.getAccessPolicy().getStart() != null) {
identifier.getAccessPolicy().setStart(
identifier.getAccessPolicy().getStart().truncatedTo(ChronoUnit.SECONDS));
}
if (identifier.getAccessPolicy() != null && identifier.getAccessPolicy().getExpiry() != null) {
identifier.getAccessPolicy().setExpiry(
identifier.getAccessPolicy().getExpiry().truncatedTo(ChronoUnit.SECONDS));
}
vcolin7 marked this conversation as resolved.
Show resolved Hide resolved
}
}

try {
return tablesImplementation.getTables()
.setAccessPolicyWithResponseAsync(tableName, null, null,
tableSignedIdentifiers.stream().map(this::toSignedIdentifier).collect(Collectors.toList()), context)
.setAccessPolicyWithResponseAsync(tableName, null, null, signedIdentifiers, context)
.map(response -> new SimpleResponse<>(response, response.getValue()));
} catch (RuntimeException e) {
return monoError(logger, e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -414,9 +414,9 @@ public Response<TableEntity> getEntityWithResponse(String partitionKey, String r
* @return A reactive result containing the HTTP response and the table's
* {@link TableSignedIdentifier access policies}.
*/
@ServiceMethod(returns = ReturnType.COLLECTION)
public PagedIterable<TableSignedIdentifier> listAccessPolicies() {
return new PagedIterable<>(client.listAccessPolicies());
@ServiceMethod(returns = ReturnType.SINGLE)
public List<TableSignedIdentifier> listAccessPolicies() {
return client.listAccessPolicies().block();
}

/**
Expand All @@ -429,9 +429,9 @@ public PagedIterable<TableSignedIdentifier> listAccessPolicies() {
* @return A reactive result containing the HTTP response and the table's
* {@link TableSignedIdentifier access policies}.
*/
@ServiceMethod(returns = ReturnType.COLLECTION)
public PagedIterable<TableSignedIdentifier> listAccessPolicies(Duration timeout, Context context) {
return new PagedIterable<>(applyOptionalTimeout(client.listAccessPolicies(context), timeout));
@ServiceMethod(returns = ReturnType.SINGLE)
public Response<List<TableSignedIdentifier>> listAccessPoliciesWithResponse(Duration timeout, Context context) {
return blockWithOptionalTimeout(client.listAccessPoliciesWithResponse(context), timeout);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,6 @@ public Mono<Void> setProperties(TableServiceProperties tableServiceProperties) {
return this.setPropertiesWithResponse(tableServiceProperties).flatMap(FluxUtil::toMono);
}


/**
* Sets the properties of an account's Table service, including properties for Analytics and CORS (Cross-Origin
* Resource Sharing) rules.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.azure.data.tables.implementation.models.QueryOptions;
import com.azure.data.tables.implementation.models.ResponseFormat;
import com.azure.data.tables.implementation.models.SignedIdentifier;
import com.azure.data.tables.implementation.models.SignedIdentifiersWrapper;
import com.azure.data.tables.implementation.models.TableProperties;
import com.azure.data.tables.implementation.models.TableServiceErrorException;
import com.azure.data.tables.implementation.models.TablesCreateResponse;
Expand Down Expand Up @@ -238,7 +239,7 @@ Mono<TablesSetAccessPolicyResponse> setAccessPolicy(
@HeaderParam("x-ms-client-request-id") String requestId,
@PathParam("table") String table,
@QueryParam("comp") String comp,
@BodyParam("application/xml") List<SignedIdentifier> tableAcl,
@BodyParam("application/xml") SignedIdentifiersWrapper tableAcl,
@HeaderParam("Accept") String accept,
Context context);
}
Expand Down Expand Up @@ -725,14 +726,17 @@ public Mono<TablesSetAccessPolicyResponse> setAccessPolicyWithResponseAsync(
String table, Integer timeout, String requestId, List<SignedIdentifier> tableAcl, Context context) {
final String comp = "acl";
final String accept = "application/xml";

SignedIdentifiersWrapper tableAclConverted = new SignedIdentifiersWrapper(tableAcl);

return service.setAccessPolicy(
this.client.getUrl(),
timeout,
this.client.getVersion(),
requestId,
table,
comp,
tableAcl,
tableAclConverted,
accept,
context);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.azure.data.tables.implementation.models;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;

import java.util.List;

/** A wrapper around List&lt;SignedIdentifier&gt; which provides top-level metadata for serialization. */
@JacksonXmlRootElement(localName = "SignedIdentifiers")
public final class SignedIdentifiersWrapper {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an issue to get the code generator working correctly to generate this type?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, I don't know how to get it to do that, so I added the class manually and was looking to add a transform later (once I learn enough about autorest).

@JacksonXmlProperty(localName = "SignedIdentifier")
private final List<SignedIdentifier> signedIdentifiers;

/**
* Creates an instance of SignedIdentifiersWrapper.
*
* @param signedIdentifiers the list.
*/
@JsonCreator
public SignedIdentifiersWrapper(@JsonProperty("SignedIdentifier") List<SignedIdentifier> signedIdentifiers) {
this.signedIdentifiers = signedIdentifiers;
}

/**
* Get the List&lt;BlobSignedIdentifier&gt; contained in this wrapper.
*
* @return the List&lt;BlobSignedIdentifier&gt;.
*/
public List<SignedIdentifier> items() {
return signedIdentifiers;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

import com.azure.core.annotation.Fluent;

import java.util.Objects;

/**
* A signed identifier.
*/
Expand All @@ -13,33 +15,31 @@ public final class TableSignedIdentifier {
/*
* A unique id
*/
private String id;
private final String id;

/*
* An access policy.
*/
private TableAccessPolicy accessPolicy;

/**
* Get the unique id.
* Create a {@link TableSignedIdentifier}.
*
* @return The id.
* @param id A unique id for this {@link TableSignedIdentifier}.
*/
public String getId() {
return this.id;
public TableSignedIdentifier(String id) {
Objects.requireNonNull(id, "'id' cannot be null");

this.id = id;
}

/**
* Set a unique id.
*
* @param id The id to set.
* Get the unique id.
*
* @return The updated {@link TableSignedIdentifier} object.
* @return The id.
*/
public TableSignedIdentifier setId(String id) {
this.id = id;

return this;
public String getId() {
return this.id;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
import com.azure.core.test.TestBase;
import com.azure.core.test.utils.TestResourceNamer;
import com.azure.data.tables.models.ListEntitiesOptions;
import com.azure.data.tables.models.TableAccessPolicy;
import com.azure.data.tables.models.TableEntity;
import com.azure.data.tables.models.TableEntityUpdateMode;
import com.azure.data.tables.models.TableSignedIdentifier;
import com.azure.data.tables.models.TableTransactionAction;
import com.azure.data.tables.models.TableTransactionActionResponse;
import com.azure.data.tables.models.TableTransactionActionType;
Expand All @@ -35,6 +37,7 @@
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -1009,4 +1012,30 @@ public void canUseSasTokenToCreateValidTableClient() {
.expectComplete()
.verify();
}

@Test
public void setAndListAccessPolicies() {
vcolin7 marked this conversation as resolved.
Show resolved Hide resolved
OffsetDateTime startTime = OffsetDateTime.of(2021, 12, 12, 0, 0, 0, 0, ZoneOffset.UTC);
OffsetDateTime expiryTime = OffsetDateTime.of(2022, 12, 12, 0, 0, 0, 0, ZoneOffset.UTC);
String permissions = "r";
TableAccessPolicy tableAccessPolicy = new TableAccessPolicy()
.setStartsOn(startTime)
.setExpiresOn(expiryTime)
.setPermissions(permissions);
String id = "testPolicy";
TableSignedIdentifier tableSignedIdentifier = new TableSignedIdentifier(id).setAccessPolicy(tableAccessPolicy);

Response<Void> response =
vcolin7 marked this conversation as resolved.
Show resolved Hide resolved
tableClient.setAccessPoliciesWithResponse(Collections.singletonList(tableSignedIdentifier)).block();

assertEquals(204, response.getStatusCode());

TableSignedIdentifier signedIdentifier = tableClient.listAccessPolicies().block().get(0);
TableAccessPolicy accessPolicy = signedIdentifier.getAccessPolicy();

assertEquals(startTime, accessPolicy.getStartsOn());
assertEquals(expiryTime, accessPolicy.getExpiresOn());
assertEquals(permissions, accessPolicy.getPermissions());
assertEquals(id, signedIdentifier.getId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import com.azure.data.tables.models.ListTablesOptions;
import com.azure.data.tables.models.TableEntity;
import com.azure.data.tables.models.TableServiceException;
import com.azure.data.tables.models.TableServiceProperties;
import com.azure.data.tables.models.TableServiceStatistics;
import com.azure.data.tables.sas.TableAccountSasPermission;
import com.azure.data.tables.sas.TableAccountSasResourceType;
import com.azure.data.tables.sas.TableAccountSasService;
Expand Down Expand Up @@ -415,4 +417,27 @@ public void canUseSasTokenToCreateValidTableClient() {
.expectComplete()
.verify();
}

@Test
public void getProperties() {
TableServiceProperties properties = serviceClient.getProperties().block();

assertNotNull(properties);
assertNotNull(properties.getCorsRules());
assertEquals(1, properties.getCorsRules().size());
assertNotNull(properties.getCorsRules().get(0));
assertNotNull(properties.getHourMetrics());
assertNotNull(properties.getMinuteMetrics());
assertNotNull(properties.getLogging());
}

@Test
public void getStatistics() {
TableServiceStatistics statistics = serviceClient.getStatistics().block();

assertNotNull(statistics);
assertNotNull(statistics.getGeoReplication());
assertNotNull(statistics.getGeoReplication().getStatus());
assertNotNull(statistics.getGeoReplication().getLastSyncTime());
}
}
Loading