Added support for get/set file service properties. (#384)
This commit is contained in:
parent
eeffd6248f
commit
626a8856f0
@ -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(
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
{
|
||||
/**
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user