Added support for get/set file service properties. (#384)

This commit is contained in:
Kan Tang 2020-08-05 10:31:48 +08:00 committed by GitHub
parent eeffd6248f
commit 626a8856f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 184 additions and 15 deletions

View File

@ -416,7 +416,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
};
// The retention policy.
struct RetentionPolicy
struct ShareRetentionPolicy
{
bool Enabled; // Indicates whether a retention policy is enabled for the File service. If false,
// metrics data is retained, and the user is responsible for deleting it.
@ -432,7 +432,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
bool Enabled; // Indicates whether metrics are enabled for the File service.
bool IncludeAPIs; // Indicates whether metrics should generate summary statistics for called API
// operations.
RetentionPolicy ShareRetentionPolicy;
ShareRetentionPolicy RetentionPolicy;
};
// An Azure Storage file range.
@ -1116,6 +1116,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
auto body = Azure::Core::Http::MemoryBodyStream(
reinterpret_cast<const uint8_t*>(xml_body.data()), xml_body.length());
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url, &body);
request.AddHeader("Content-Length", std::to_string(body.Length()));
request.AddQueryParameter(Details::c_QueryRestype, "service");
request.AddQueryParameter(Details::c_QueryComp, "properties");
if (setPropertiesOptions.Timeout.HasValue())
@ -1240,10 +1241,10 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
}
}
static void RetentionPolicyToXml(XmlWriter& writer, const RetentionPolicy& object)
static void ShareRetentionPolicyToXml(XmlWriter& writer, const ShareRetentionPolicy& object)
{
writer.Write(XmlNode{XmlNodeType::StartTag, "Enabled"});
writer.Write(XmlNode{XmlNodeType::Text, nullptr, std::to_string(object.Enabled).data()});
writer.Write(XmlNode{XmlNodeType::Text, nullptr, object.Enabled == 0 ? "false" : "true"});
writer.Write(XmlNode{XmlNodeType::EndTag});
writer.Write(XmlNode{XmlNodeType::StartTag, "Days"});
writer.Write(XmlNode{XmlNodeType::Text, nullptr, std::to_string(object.Days).data()});
@ -1256,19 +1257,20 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
writer.Write(XmlNode{XmlNodeType::Text, nullptr, object.Version.data()});
writer.Write(XmlNode{XmlNodeType::EndTag});
writer.Write(XmlNode{XmlNodeType::StartTag, "Enabled"});
writer.Write(XmlNode{XmlNodeType::Text, nullptr, std::to_string(object.Enabled).data()});
writer.Write(XmlNode{XmlNodeType::Text, nullptr, object.Enabled == 0 ? "false" : "true"});
writer.Write(XmlNode{XmlNodeType::EndTag});
writer.Write(XmlNode{XmlNodeType::StartTag, "IncludeAPIs"});
writer.Write(
XmlNode{XmlNodeType::Text, nullptr, std::to_string(object.IncludeAPIs).data()});
XmlNode{XmlNodeType::Text, nullptr, object.IncludeAPIs == 0 ? "false" : "true"});
writer.Write(XmlNode{XmlNodeType::EndTag});
writer.Write(XmlNode{XmlNodeType::StartTag, "RetentionPolicy"});
RetentionPolicyToXml(writer, object.ShareRetentionPolicy);
ShareRetentionPolicyToXml(writer, object.RetentionPolicy);
writer.Write(XmlNode{XmlNodeType::EndTag});
};
static void CorsRuleToXml(XmlWriter& writer, const CorsRule& object)
{
writer.Write(XmlNode{XmlNodeType::StartTag, "CorsRule"});
writer.Write(XmlNode{XmlNodeType::StartTag, "AllowedOrigins"});
writer.Write(XmlNode{XmlNodeType::Text, nullptr, object.AllowedOrigins.data()});
writer.Write(XmlNode{XmlNodeType::EndTag});
@ -1285,22 +1287,28 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
writer.Write(
XmlNode{XmlNodeType::Text, nullptr, std::to_string(object.MaxAgeInSeconds).data()});
writer.Write(XmlNode{XmlNodeType::EndTag});
writer.Write(XmlNode{XmlNodeType::EndTag});
};
static void StorageServicePropertiesToXml(
XmlWriter& writer,
const StorageServiceProperties& object)
{
writer.Write(XmlNode{XmlNodeType::StartTag, "StorageServiceProperties"});
writer.Write(XmlNode{XmlNodeType::StartTag, "HourMetrics"});
MetricsToXml(writer, object.HourMetrics);
writer.Write(XmlNode{XmlNodeType::EndTag});
writer.Write(XmlNode{XmlNodeType::StartTag, "MinuteMetrics"});
MetricsToXml(writer, object.MinuteMetrics);
writer.Write(XmlNode{XmlNodeType::EndTag});
writer.Write(XmlNode{XmlNodeType::StartTag, "Cors"});
for (const auto& item : object.Cors)
if (object.Cors.size() > 0)
{
CorsRuleToXml(writer, item);
writer.Write(XmlNode{XmlNodeType::StartTag, "Cors"});
for (const auto& item : object.Cors)
{
CorsRuleToXml(writer, item);
}
writer.Write(XmlNode{XmlNodeType::EndTag});
}
writer.Write(XmlNode{XmlNodeType::EndTag});
};
@ -1328,9 +1336,9 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
}
}
static RetentionPolicy RetentionPolicyFromXml(XmlReader& reader)
static ShareRetentionPolicy ShareRetentionPolicyFromXml(XmlReader& reader)
{
auto result = RetentionPolicy();
auto result = ShareRetentionPolicy();
enum class XmlTagName
{
c_Unknown,
@ -1445,7 +1453,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
if (path.size() == 1 && path[0] == XmlTagName::c_RetentionPolicy)
{
result.ShareRetentionPolicy = RetentionPolicyFromXml(reader);
result.RetentionPolicy = ShareRetentionPolicyFromXml(reader);
path.pop_back();
}
}
@ -1564,6 +1572,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
c_StorageServiceProperties,
c_HourMetrics,
c_MinuteMetrics,
c_CorsRule,
c_Cors,
};
std::vector<XmlTagName> path;
@ -1601,6 +1610,10 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
{
path.emplace_back(XmlTagName::c_MinuteMetrics);
}
else if (std::strcmp(node.Name, "CorsRule") == 0)
{
path.emplace_back(XmlTagName::c_CorsRule);
}
else if (std::strcmp(node.Name, "Cors") == 0)
{
path.emplace_back(XmlTagName::c_Cors);
@ -1624,8 +1637,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
path.pop_back();
}
else if (
path.size() == 2 && path[0] == XmlTagName::c_StorageServiceProperties
&& path[1] == XmlTagName::c_Cors)
path.size() == 3 && path[0] == XmlTagName::c_StorageServiceProperties
&& path[1] == XmlTagName::c_Cors && path[2] == XmlTagName::c_CorsRule)
{
result.Cors.emplace_back(CorsRuleFromXml(reader));
path.pop_back();
@ -2421,6 +2434,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
auto body = Azure::Core::Http::MemoryBodyStream(
reinterpret_cast<const uint8_t*>(xml_body.data()), xml_body.length());
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url, &body);
request.AddHeader("Content-Length", std::to_string(body.Length()));
request.AddQueryParameter(Details::c_QueryRestype, "share");
request.AddQueryParameter(Details::c_QueryComp, "acl");
if (setAccessPolicyOptions.Timeout.HasValue())
@ -2949,6 +2963,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
static void AccessPolicyToXml(XmlWriter& writer, const AccessPolicy& object)
{
writer.Write(XmlNode{XmlNodeType::StartTag, "AccessPolicy"});
writer.Write(XmlNode{XmlNodeType::StartTag, "Start"});
writer.Write(XmlNode{XmlNodeType::Text, nullptr, object.Start.data()});
writer.Write(XmlNode{XmlNodeType::EndTag});
@ -2958,16 +2973,19 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
writer.Write(XmlNode{XmlNodeType::StartTag, "Permission"});
writer.Write(XmlNode{XmlNodeType::Text, nullptr, object.Permission.data()});
writer.Write(XmlNode{XmlNodeType::EndTag});
writer.Write(XmlNode{XmlNodeType::EndTag});
};
static void SignedIdentifierToXml(XmlWriter& writer, const SignedIdentifier& object)
{
writer.Write(XmlNode{XmlNodeType::StartTag, "SignedIdentifier"});
writer.Write(XmlNode{XmlNodeType::StartTag, "Id"});
writer.Write(XmlNode{XmlNodeType::Text, nullptr, object.Id.data()});
writer.Write(XmlNode{XmlNodeType::EndTag});
writer.Write(XmlNode{XmlNodeType::StartTag, "AccessPolicy"});
AccessPolicyToXml(writer, object.Policy);
writer.Write(XmlNode{XmlNodeType::EndTag});
writer.Write(XmlNode{XmlNodeType::EndTag});
};
static void SignedIdentifiersToXml(

View File

@ -85,6 +85,24 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
Azure::Core::Response<ListSharesSegmentResult> ListSharesSegment(
const ListSharesOptions& options = ListSharesOptions()) const;
/**
* @brief Set the service's properties.
* @param properties The properties of the service that is to be set.
* @param options Optional parameters to set the properties of the service.
* @return Azure::Core::Response<ServiceProperties> The service's properties.
*/
Azure::Core::Response<SetServicePropertiesInfo> SetProperties(
StorageServiceProperties properties,
const SetServicePropertiesOptions& options = SetServicePropertiesOptions()) const;
/**
* @brief Get the service's properties.
* @param options Optional parameters to get the properties of the service.
* @return Azure::Core::Response<ServiceProperties> The service's properties.
*/
Azure::Core::Response<StorageServiceProperties> GetProperties(
const GetServicePropertiesOptions& options = GetServicePropertiesOptions()) const;
private:
UriBuilder m_serviceUri;
std::shared_ptr<Azure::Core::Http::HttpPipeline> m_pipeline;

View File

@ -66,6 +66,22 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
Azure::Core::Nullable<ListSharesIncludeType> ListSharesInclude;
};
struct SetServicePropertiesOptions
{
/**
* @brief Context for cancelling long running operations.
*/
Azure::Core::Context Context;
};
struct GetServicePropertiesOptions
{
/**
* @brief Context for cancelling long running operations.
*/
Azure::Core::Context Context;
};
struct CreateShareOptions
{
/**

View File

@ -10,6 +10,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
// ServiceClient models:
using ListSharesSegmentResult = ServiceListSharesSegmentResponse;
using SetServicePropertiesInfo = ServiceSetPropertiesResponse;
// ShareClient models:
using ShareInfo = ShareCreateResponse;

View File

@ -126,4 +126,28 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares {
m_serviceUri.ToString(), *m_pipeline, options.Context, protocolLayerOptions);
}
Azure::Core::Response<SetServicePropertiesInfo> ServiceClient::SetProperties(
StorageServiceProperties properties,
const SetServicePropertiesOptions& options) const
{
auto protocolLayerOptions = ShareRestClient::Service::SetPropertiesOptions();
protocolLayerOptions.ServiceProperties = std::move(properties);
return ShareRestClient::Service::SetProperties(
m_serviceUri.ToString(), *m_pipeline, options.Context, protocolLayerOptions);
}
Azure::Core::Response<StorageServiceProperties> ServiceClient::GetProperties(
const GetServicePropertiesOptions& options) const
{
auto protocolLayerOptions = ShareRestClient::Service::GetPropertiesOptions();
auto result = ShareRestClient::Service::GetProperties(
m_serviceUri.ToString(), *m_pipeline, options.Context, protocolLayerOptions);
StorageServiceProperties ret;
ret.Cors = std::move(result->Cors);
ret.HourMetrics = std::move(result->HourMetrics);
ret.MinuteMetrics = std::move(result->MinuteMetrics);
return Azure::Core::Response<StorageServiceProperties>(
std::move(ret), result.ExtractRawResponse());
}
}}}} // namespace Azure::Storage::Files::Shares

View File

@ -4,6 +4,7 @@
#include "service_client_test.hpp"
#include <algorithm>
#include <thread>
namespace Azure { namespace Storage { namespace Test {
@ -124,4 +125,95 @@ namespace Azure { namespace Storage { namespace Test {
}
}
TEST_F(FileShareServiceClientTest, GetProperties)
{
auto ret = m_fileShareServiceClient->GetProperties();
auto properties = *ret;
auto hourMetrics = properties.HourMetrics;
if (hourMetrics.Enabled)
{
EXPECT_FALSE(hourMetrics.Version.empty());
}
auto minuteMetrics = properties.HourMetrics;
if (minuteMetrics.Enabled)
{
EXPECT_FALSE(minuteMetrics.Version.empty());
}
}
TEST_F(FileShareServiceClientTest, SetProperties)
{
auto properties = *m_fileShareServiceClient->GetProperties();
auto originalProperties = properties;
properties.HourMetrics.Enabled = true;
properties.HourMetrics.RetentionPolicy.Enabled = true;
properties.HourMetrics.RetentionPolicy.Days = 4;
properties.HourMetrics.IncludeAPIs = true;
properties.MinuteMetrics.Enabled = true;
properties.MinuteMetrics.RetentionPolicy.Enabled = true;
properties.MinuteMetrics.RetentionPolicy.Days = 3;
properties.MinuteMetrics.IncludeAPIs = true;
Files::Shares::CorsRule corsRule;
corsRule.AllowedOrigins = "http://www.example1.com";
corsRule.AllowedMethods = "GET,PUT";
corsRule.AllowedHeaders = "x-ms-header1,x-ms-header2";
corsRule.ExposedHeaders = "x-ms-header3";
corsRule.MaxAgeInSeconds = 10;
properties.Cors.emplace_back(corsRule);
corsRule.AllowedOrigins = "http://www.example2.com";
corsRule.AllowedMethods = "DELETE";
corsRule.AllowedHeaders = "x-ms-header1";
corsRule.ExposedHeaders = "x-ms-header2,x-ms-header3";
corsRule.MaxAgeInSeconds = 20;
properties.Cors.emplace_back(corsRule);
EXPECT_NO_THROW(m_fileShareServiceClient->SetProperties(properties));
// It takes some time before the new properties comes into effect.
using namespace std::chrono_literals;
std::this_thread::sleep_for(10s);
auto downloadedProperties = *m_fileShareServiceClient->GetProperties();
EXPECT_EQ(downloadedProperties.HourMetrics.Version, properties.HourMetrics.Version);
EXPECT_EQ(downloadedProperties.HourMetrics.Enabled, properties.HourMetrics.Enabled);
EXPECT_EQ(downloadedProperties.HourMetrics.IncludeAPIs, properties.HourMetrics.IncludeAPIs);
EXPECT_EQ(
downloadedProperties.HourMetrics.RetentionPolicy.Enabled,
properties.HourMetrics.RetentionPolicy.Enabled);
EXPECT_EQ(
downloadedProperties.HourMetrics.RetentionPolicy.Days,
properties.HourMetrics.RetentionPolicy.Days);
EXPECT_EQ(downloadedProperties.MinuteMetrics.Version, properties.MinuteMetrics.Version);
EXPECT_EQ(downloadedProperties.MinuteMetrics.Enabled, properties.MinuteMetrics.Enabled);
EXPECT_EQ(downloadedProperties.MinuteMetrics.IncludeAPIs, properties.MinuteMetrics.IncludeAPIs);
EXPECT_EQ(
downloadedProperties.MinuteMetrics.RetentionPolicy.Enabled,
properties.MinuteMetrics.RetentionPolicy.Enabled);
EXPECT_EQ(
downloadedProperties.MinuteMetrics.RetentionPolicy.Days,
properties.MinuteMetrics.RetentionPolicy.Days);
EXPECT_EQ(downloadedProperties.Cors.size(), properties.Cors.size());
for (const auto& cors : downloadedProperties.Cors)
{
auto iter = std::find_if(
properties.Cors.begin(),
properties.Cors.end(),
[&cors](const Files::Shares::CorsRule& rule) {
return rule.AllowedOrigins == cors.AllowedOrigins;
});
EXPECT_EQ(iter->AllowedMethods, cors.AllowedMethods);
EXPECT_EQ(iter->AllowedHeaders, cors.AllowedHeaders);
EXPECT_EQ(iter->ExposedHeaders, cors.ExposedHeaders);
EXPECT_EQ(iter->MaxAgeInSeconds, cors.MaxAgeInSeconds);
EXPECT_NE(properties.Cors.end(), iter);
}
m_fileShareServiceClient->SetProperties(originalProperties);
}
}}} // namespace Azure::Storage::Test