Skip to content

Commit 0873534

Browse files
committed
Merge pull request Azure#1153 from yoavrubin/dev
SQL Data masking cmdlets to stop using RuleId
2 parents e1653a2 + f63d784 commit 0873534

18 files changed

+7612
-4008
lines changed

src/ResourceManager/Sql/Commands.Sql.Test/ScenarioTests/AuditingTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ protected override void SetupManagementClients()
4343
helper.SetupSomeOfManagementClients(sqlCSMClient, storageClient, storageV2Client, resourcesClient, authorizationClient);
4444
}
4545

46-
[Fact(Skip = "PSGet: TODO fix by moving SM specific logic to test setup")] [Trait(Category.AcceptanceType, Category.Sql)]
46+
[Fact(Skip = "PSGet: TODO fix by moving SM specific logic to test setup")]
47+
[Trait(Category.AcceptanceType, Category.Sql)]
4748
public void TestAuditingDatabaseUpdatePolicyWithStorage()
4849
{
4950
RunPowerShellTest("Test-AuditingDatabaseUpdatePolicyWithStorage");

src/ResourceManager/Sql/Commands.Sql.Test/ScenarioTests/DataMaskingTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public void TestDatabaseDataMaskingTextRuleLifecycle()
5656
RunPowerShellTest("Test-DatabaseDataMaskingTextRuleLifecycle");
5757
}
5858

59-
[Fact]
59+
[Fact(Skip = "Waiting for database structure validation")]
6060
[Trait(Category.AcceptanceType, Category.BVT)]
6161
public void TestDatabaseDataMaskingRuleCreationFailures()
6262
{

src/ResourceManager/Sql/Commands.Sql.Test/ScenarioTests/DataMaskingTests.ps1

Lines changed: 39 additions & 67 deletions
Large diffs are not rendered by default.

src/ResourceManager/Sql/Commands.Sql.Test/SessionRecords/Microsoft.Azure.Commands.Sql.Test.ScenarioTests.DataMaskingTests/TestDatabaseDataMaskingBasicRuleLifecycle.json

Lines changed: 1056 additions & 816 deletions
Large diffs are not rendered by default.

src/ResourceManager/Sql/Commands.Sql.Test/SessionRecords/Microsoft.Azure.Commands.Sql.Test.ScenarioTests.DataMaskingTests/TestDatabaseDataMaskingNumberRuleLifecycle.json

Lines changed: 1567 additions & 859 deletions
Large diffs are not rendered by default.

src/ResourceManager/Sql/Commands.Sql.Test/SessionRecords/Microsoft.Azure.Commands.Sql.Test.ScenarioTests.DataMaskingTests/TestDatabaseDataMaskingRuleCreationWithoutPolicy.json

Lines changed: 739 additions & 1249 deletions
Large diffs are not rendered by default.

src/ResourceManager/Sql/Commands.Sql.Test/SessionRecords/Microsoft.Azure.Commands.Sql.Test.ScenarioTests.DataMaskingTests/TestDatabaseDataMaskingTextRuleLifecycle.json

Lines changed: 4005 additions & 801 deletions
Large diffs are not rendered by default.

src/ResourceManager/Sql/Commands.Sql/Common/AzureSqlCmdletBase.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,16 @@ internal AzureSqlCmdletBase()
8585
/// <returns>An initialized and ready to use ModelAdapter object</returns>
8686
protected abstract A InitModelAdapter(AzureSubscription subscription);
8787

88+
/// <summary>
89+
/// Transforms the given model object to be an object that is written out
90+
/// </summary>
91+
/// <param name="model">The about to be written model object</param>
92+
/// <returns>The prepared object to be written out</returns>
93+
protected virtual object TransformModelToOutputObject(M model)
94+
{
95+
return model;
96+
}
97+
8898
/// <summary>
8999
/// Executes the cmdlet
90100
/// </summary>
@@ -99,14 +109,14 @@ protected override void ProcessRecord()
99109
{
100110
if (WriteResult())
101111
{
102-
this.WriteObject(responseModel, true);
112+
this.WriteObject(TransformModelToOutputObject(responseModel), true);
103113
}
104114
}
105115
else
106116
{
107117
if (WriteResult())
108118
{
109-
this.WriteObject(updatedModel);
119+
this.WriteObject(TransformModelToOutputObject(updatedModel));
110120
}
111121
}
112122
}

src/ResourceManager/Sql/Commands.Sql/Data Masking/Cmdlet/BuildAzureSqlDatabaseDataMaskingRule.cs

Lines changed: 2 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,6 @@ namespace Microsoft.Azure.Commands.Sql.DataMasking.Cmdlet
2929
/// </summary>
3030
public abstract class BuildAzureSqlDatabaseDataMaskingRule : SqlDatabaseDataMaskingRuleCmdletBase
3131
{
32-
/// <summary>
33-
/// Gets or sets the schema name
34-
/// </summary>
35-
public virtual string SchemaName { get; set; }
36-
37-
/// <summary>
38-
/// Gets or sets the table name
39-
/// </summary>
40-
public virtual string TableName { get; set; }
41-
42-
/// <summary>
43-
/// Gets or sets the column name
44-
/// </summary>
45-
public virtual string ColumnName { get; set; }
46-
4732
/// <summary>
4833
/// Gets or sets the masking function - the definition of this property as a cmdlet parameter is done in the subclasses
4934
/// </summary>
@@ -91,12 +76,7 @@ public abstract class BuildAzureSqlDatabaseDataMaskingRule : SqlDatabaseDataMask
9176
/// <param name="model">A model object</param>
9277
protected override IEnumerable<DatabaseDataMaskingRuleModel> ApplyUserInputToModel(IEnumerable<DatabaseDataMaskingRuleModel> rules)
9378
{
94-
string errorMessage = ValidateRuleTarget(rules);
95-
if (string.IsNullOrEmpty(errorMessage))
96-
{
97-
errorMessage = ValidateOperation(rules);
98-
}
99-
79+
string errorMessage = ValidateOperation(rules);
10080
if(!string.IsNullOrEmpty(errorMessage))
10181
{
10282
throw new Exception(errorMessage);
@@ -106,20 +86,6 @@ protected override IEnumerable<DatabaseDataMaskingRuleModel> ApplyUserInputToMod
10686
return UpdateRuleList(rules, rule);
10787
}
10888

109-
/// <summary>
110-
/// Validation that the rule's target is set properly to be either a table and column for which there's no other rule, or an alias for which there's no other rule.
111-
/// </summary>
112-
/// <param name="rules">The data masking rules of the current database</param>
113-
/// <returns>A string containing error message or null in case all is fine</returns>
114-
protected string ValidateRuleTarget(IEnumerable<DatabaseDataMaskingRuleModel> rules)
115-
{
116-
if (rules.Any(r => r.TableName == TableName && r.ColumnName == ColumnName && r.RuleId != RuleId))
117-
{
118-
return string.Format(CultureInfo.InvariantCulture, Microsoft.Azure.Commands.Sql.Properties.Resources.DataMaskingTableAndColumnUsedError, TableName, ColumnName);
119-
}
120-
return null;
121-
}
122-
12389
/// <summary>
12490
/// Update the rule this cmdlet is operating on based on the values provided by the user
12591
/// </summary>
@@ -254,7 +220,7 @@ private MaskingFunction ModelizeMaskingFunction()
254220
/// <param name="model">The model object with the data to be sent to the REST endpoints</param>
255221
protected override IEnumerable<DatabaseDataMaskingRuleModel> PersistChanges(IEnumerable<DatabaseDataMaskingRuleModel> rules)
256222
{
257-
ModelAdapter.SetDatabaseDataMaskingRule(rules.First(r => r.RuleId == RuleId), clientRequestId);
223+
ModelAdapter.SetDatabaseDataMaskingRule(rules.First(IsModelOfRule), clientRequestId);
258224
return null;
259225
}
260226

src/ResourceManager/Sql/Commands.Sql/Data Masking/Cmdlet/GetAzureSqlDatabaseDataMaskingRule.cs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
// ----------------------------------------------------------------------------------
1414

1515
using Microsoft.Azure.Commands.Sql.DataMasking.Model;
16+
using System;
1617
using System.Collections.Generic;
18+
using System.Linq;
1719
using System.Management.Automation;
1820

1921
namespace Microsoft.Azure.Commands.Sql.DataMasking.Cmdlet
@@ -23,13 +25,37 @@ namespace Microsoft.Azure.Commands.Sql.DataMasking.Cmdlet
2325
/// </summary>
2426
[Cmdlet(VerbsCommon.Get, "AzureRmSqlDatabaseDataMaskingRule"), OutputType(typeof(IEnumerable<DatabaseDataMaskingRuleModel>))]
2527
public class GetAzureSqlDatabaseDataMaskingRule : SqlDatabaseDataMaskingRuleCmdletBase
26-
{
28+
{
2729
/// <summary>
28-
/// Gets or sets the id of the rule use, if not provided then the list of rules for this DB is returned
30+
/// Gets or sets the schema name
2931
/// </summary>
30-
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "Data Masking rule Id.")]
31-
public override string RuleId { get; set; } // intentionally overiding to make this property non mandatory (thus allow a LIST call)
32+
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "The schema name.")]
33+
[ValidateNotNullOrEmpty]
34+
public override string SchemaName { get; set; }
3235

36+
/// <summary>
37+
/// Gets or sets the table name
38+
/// </summary>
39+
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "The table name.")]
40+
[ValidateNotNullOrEmpty]
41+
public override string TableName { get; set; }
42+
43+
/// <summary>
44+
/// Gets or sets the column name
45+
/// </summary>
46+
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "The column name.")]
47+
[ValidateNotNullOrEmpty]
48+
public override string ColumnName { get; set; }
49+
50+
protected override object TransformModelToOutputObject(IEnumerable<DatabaseDataMaskingRuleModel> model)
51+
{
52+
Predicate<DatabaseDataMaskingRuleModel> colPred = (DatabaseDataMaskingRuleModel r) => { return string.IsNullOrEmpty(ColumnName) ? true : r.ColumnName == ColumnName; };
53+
Predicate<DatabaseDataMaskingRuleModel> tablePred = (DatabaseDataMaskingRuleModel r) => { return string.IsNullOrEmpty(TableName) ? true : r.TableName == TableName; };
54+
Predicate<DatabaseDataMaskingRuleModel> schemaPred = (DatabaseDataMaskingRuleModel r) => { return string.IsNullOrEmpty(SchemaName) ? true : r.SchemaName == SchemaName; };
55+
return model.Where(r => { return colPred(r) && tablePred(r) && schemaPred(r); }).ToList();
56+
}
57+
58+
3359
/// <summary>
3460
/// No sending is needed as this is a Get cmdlet
3561
/// </summary>

src/ResourceManager/Sql/Commands.Sql/Data Masking/Cmdlet/NewAzureSqlDatabaseDataMaskingRule.cs

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,6 @@ namespace Microsoft.Azure.Commands.Sql.DataMasking.Cmdlet
3030
[Cmdlet(VerbsCommon.New, "AzureRmSqlDatabaseDataMaskingRule")]
3131
public class NewAzureSqlDatabaseDataMaskingRule : BuildAzureSqlDatabaseDataMaskingRule
3232
{
33-
/// <summary>
34-
/// Gets or sets the column name
35-
/// </summary>
36-
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The column name.")]
37-
[ValidateNotNullOrEmpty]
38-
public override string ColumnName { get; set; }
39-
40-
/// <summary>
41-
/// Gets or sets the schema name
42-
/// </summary>
43-
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The schema name.")]
44-
[ValidateNotNullOrEmpty]
45-
public override string SchemaName { get; set; }
46-
47-
/// <summary>
48-
/// Gets or sets the table name
49-
/// </summary>
50-
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The table name.")]
51-
[ValidateNotNullOrEmpty]
52-
public override string TableName { get; set; }
53-
5433
/// <summary>
5534
/// Gets or sets the masking function
5635
/// </summary>
@@ -65,7 +44,7 @@ public class NewAzureSqlDatabaseDataMaskingRule : BuildAzureSqlDatabaseDataMaski
6544
/// <returns>A model object</returns>
6645
protected override IEnumerable<DatabaseDataMaskingRuleModel> GetEntity()
6746
{
68-
return ModelAdapter.GetDatabaseDataMaskingRule(ResourceGroupName, ServerName, DatabaseName, clientRequestId);
47+
return ModelAdapter.GetDatabaseDataMaskingRules(ResourceGroupName, ServerName, DatabaseName, clientRequestId);
6948
}
7049

7150
/// <summary>
@@ -75,15 +54,9 @@ protected override IEnumerable<DatabaseDataMaskingRuleModel> GetEntity()
7554
/// <returns>An error message or null if all is fine</returns>
7655
protected override string ValidateOperation(IEnumerable<DatabaseDataMaskingRuleModel> rules)
7756
{
78-
var ruleIdRegex = new Regex("^[^/\\\\#+=<>*%&:?]*[^/\\\\#+=<>*%&:?.]$");
79-
80-
if (!ruleIdRegex.IsMatch(RuleId)) // an invalid rule name
81-
{
82-
return string.Format(CultureInfo.InvariantCulture, Microsoft.Azure.Commands.Sql.Properties.Resources.NewDataMaskingRuleIdIsNotValid, RuleId);
83-
}
84-
if(rules.Any(r=> r.RuleId == RuleId))
57+
if (rules.Any(IsModelOfRule))
8558
{
86-
return string.Format(CultureInfo.InvariantCulture, Microsoft.Azure.Commands.Sql.Properties.Resources.NewDataMaskingRuleIdAlreadyExistError, RuleId);
59+
return string.Format(CultureInfo.InvariantCulture, Microsoft.Azure.Commands.Sql.Properties.Resources.NewDataMaskingRuleIdAlreadyExistError, ColumnName, TableName, SchemaName);
8760
}
8861
return null;
8962
}
@@ -99,7 +72,6 @@ protected override DatabaseDataMaskingRuleModel GetRule(IEnumerable<DatabaseData
9972
rule.ResourceGroupName = ResourceGroupName;
10073
rule.ServerName = ServerName;
10174
rule.DatabaseName = DatabaseName;
102-
rule.RuleId = RuleId;
10375
return rule;
10476
}
10577

src/ResourceManager/Sql/Commands.Sql/Data Masking/Cmdlet/RemoveAzureSqlDatabaseDataMaskingRule.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,10 @@ public class RemoveAzureSqlDatabaseDataMaskingRule : SqlDatabaseDataMaskingRuleC
4747
protected override IEnumerable<DatabaseDataMaskingRuleModel> PersistChanges(IEnumerable<DatabaseDataMaskingRuleModel> rules)
4848
{
4949
if (!Force.IsPresent && !ShouldProcess(
50-
string.Format(CultureInfo.InvariantCulture, Microsoft.Azure.Commands.Sql.Properties.Resources.RemoveDatabaseDataMaskingRuleDescription, RuleId, DatabaseName),
51-
string.Format(CultureInfo.InvariantCulture, Microsoft.Azure.Commands.Sql.Properties.Resources.RemoveDatabaseDataMaskingRuleWarning, RuleId, DatabaseName),
50+
string.Format(CultureInfo.InvariantCulture, Microsoft.Azure.Commands.Sql.Properties.Resources.RemoveDatabaseDataMaskingRuleDescription,
51+
ColumnName, TableName, SchemaName, DatabaseName),
52+
string.Format(CultureInfo.InvariantCulture, Microsoft.Azure.Commands.Sql.Properties.Resources.RemoveDatabaseDataMaskingRuleWarning,
53+
ColumnName, TableName, SchemaName, DatabaseName),
5254
Microsoft.Azure.Commands.Sql.Properties.Resources.ShouldProcessCaption))
5355
{
5456
return null;

src/ResourceManager/Sql/Commands.Sql/Data Masking/Cmdlet/SetAzureSqlDatabaseDataMaskingRule.cs

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,25 +29,6 @@ namespace Microsoft.Azure.Commands.Sql.DataMasking.Cmdlet
2929
[Cmdlet(VerbsCommon.Set, "AzureRmSqlDatabaseDataMaskingRule")]
3030
public class SetAzureSqlDatabaseDataMaskingRule : BuildAzureSqlDatabaseDataMaskingRule
3131
{
32-
33-
/// <summary>
34-
/// Gets or sets the column name
35-
/// </summary>
36-
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "The column name.")]
37-
public override string ColumnName { get; set; }
38-
39-
/// <summary>
40-
/// Gets or sets the table name
41-
/// </summary>
42-
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "The table name.")]
43-
public override string TableName { get; set; }
44-
45-
/// <summary>
46-
/// Gets or sets the schema name
47-
/// </summary>
48-
[Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "The schema name.")]
49-
public override string SchemaName { get; set; }
50-
5132
/// <summary>
5233
/// Gets or sets the masking function
5334
/// </summary>
@@ -62,9 +43,9 @@ public class SetAzureSqlDatabaseDataMaskingRule : BuildAzureSqlDatabaseDataMaski
6243
/// <returns>An error message or null if all is fine</returns>
6344
protected override string ValidateOperation(IEnumerable<DatabaseDataMaskingRuleModel> rules)
6445
{
65-
if(!rules.Any(r=> r.RuleId == RuleId))
46+
if (!rules.Any(IsModelOfRule))
6647
{
67-
return string.Format(CultureInfo.InvariantCulture, Microsoft.Azure.Commands.Sql.Properties.Resources.SetDataMaskingRuleIdDoesNotExistError, RuleId);
48+
return string.Format(CultureInfo.InvariantCulture, Microsoft.Azure.Commands.Sql.Properties.Resources.SetDataMaskingRuleIdDoesNotExistError, SchemaName, TableName, ColumnName);
6849
}
6950
return null;
7051
}
@@ -75,8 +56,8 @@ protected override string ValidateOperation(IEnumerable<DatabaseDataMaskingRuleM
7556
/// <param name="rules">The database's data masking rules</param>
7657
/// <returns>A data masking rule object, initialized for the user provided rule identity</returns>
7758
protected override DatabaseDataMaskingRuleModel GetRule(IEnumerable<DatabaseDataMaskingRuleModel> rules)
78-
{
79-
return rules.First(r=> r.RuleId == RuleId);
59+
{
60+
return rules.First(IsModelOfRule);
8061
}
8162

8263
/// <summary>

src/ResourceManager/Sql/Commands.Sql/Data Masking/Cmdlet/SqlDatabaseDataMaskingRuleCmdletBase.cs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,49 @@ namespace Microsoft.Azure.Commands.Sql.DataMasking.Cmdlet
2828
public abstract class SqlDatabaseDataMaskingRuleCmdletBase : AzureSqlDatabaseCmdletBase<IEnumerable<DatabaseDataMaskingRuleModel>, SqlDataMaskingAdapter>
2929
{
3030
/// <summary>
31-
/// Gets or sets the id of the rule use.
31+
/// Gets or sets the schema name
3232
/// </summary>
33-
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "Data Masking rule Id.")]
33+
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The schema name.")]
3434
[ValidateNotNullOrEmpty]
35-
public virtual string RuleId { get; set; }
35+
public virtual string SchemaName { get; set; }
36+
37+
/// <summary>
38+
/// Gets or sets the table name
39+
/// </summary>
40+
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The table name.")]
41+
[ValidateNotNullOrEmpty]
42+
public virtual string TableName { get; set; }
43+
44+
/// <summary>
45+
/// Gets or sets the column name
46+
/// </summary>
47+
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, HelpMessage = "The column name.")]
48+
[ValidateNotNullOrEmpty]
49+
public virtual string ColumnName { get; set; }
50+
51+
/// <summary>
52+
/// Checks whether the model of the current cmdlet is the same as the model of the given rule
53+
/// </summary>
54+
protected bool IsModelOfRule(BaseDataMaskingRuleModel rule)
55+
{
56+
return rule.ColumnName == ColumnName && rule.TableName == TableName && rule.SchemaName == SchemaName;
57+
}
58+
59+
/// <summary>
60+
/// The model is a list of rules. This method would return the specific rule that was updated
61+
/// </summary>
62+
protected override object TransformModelToOutputObject(IEnumerable<DatabaseDataMaskingRuleModel> model)
63+
{
64+
return model.FirstOrDefault(IsModelOfRule);
65+
}
3666

3767
/// <summary>
3868
/// Provides the model element that this cmdlet operates on
3969
/// </summary>
4070
/// <returns>A model object</returns>
4171
protected override IEnumerable<DatabaseDataMaskingRuleModel> GetEntity()
4272
{
43-
return ModelAdapter.GetDatabaseDataMaskingRule(ResourceGroupName, ServerName, DatabaseName, clientRequestId, RuleId);
73+
return ModelAdapter.GetDatabaseDataMaskingRules(ResourceGroupName, ServerName, DatabaseName, clientRequestId);
4474
}
4575

4676
/// <summary>

src/ResourceManager/Sql/Commands.Sql/Data Masking/Model/BaseDataMaskingRuleModel.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,6 @@ public class BaseDataMaskingRuleModel
3434
/// </summary>
3535
public string ServerName { get; set; }
3636

37-
/// <summary>
38-
/// Gets or sets the rule id
39-
/// </summary>
40-
public string RuleId { get; set; }
41-
4237
/// <summary>
4338
/// Gets or sets the name of the chema that contains the table on which the rule operates on
4439
/// </summary>

0 commit comments

Comments
 (0)