-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
Making -ResourceGroupName parameter optional for Get-AzureRmSqlServer cmdlet #4188
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test issue is the only blocker for me, other comments are just suggestions
|
||
# Test getting all servers in all resource groups | ||
$all2 = Get-AzureRmSqlServer | ||
Assert-AreEqual 3 $all2.Count |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will fail if I run it in my subscription that already has some sql servers unrelated to PS test. Can you change this so that it checks that the list contains the 3 previous servers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I can do that.
/// <summary> | ||
/// The base class for all Azure Sql cmdlets | ||
/// </summary> | ||
public abstract class AzureSqlCmdletBaseBase<M, A> : AzureRMCmdlet |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
haha okay ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My creativity shining through :)
{ | ||
/// <summary> | ||
/// Gets or sets the name of the resource group to use. | ||
/// </summary> | ||
[Parameter(Mandatory = false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you or some comment explaining why BaseBase when you have ResourceGroup param? I understand that's it's for Mandatory=false
when looking at this change in isolation, but it won't be obvious when reading this code later
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added a comment.
else | ||
{ | ||
results = ModelAdapter.GetServers(this.ResourceGroupName); | ||
throw new PSArgumentException("When specifying the serverName parameter the ResourceGroup parameter must also be used"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you split this into 2 ParamGroups so that it's enforced by powershell logic instead of custom code?
Group 1: Get-AzureRmSqlServer
Group 2: Get-AzureRmSqlServer -ResourceGroupName [- ServerName]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might be wrong here, not sure if "no parameters" is possible to specify as a parameter set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought a bit about this, but wasn't sure how to achieve it. According to MSDN-Parameter Set Requirements a parameter set must have at least 1 parameter.
Another option is to allow specifying the ServerName without the resourceGroupName and then just retrieve the list of all servers and filter it down to just the one with the matching name (potentially bad perf)? The underlying API doesn't support retrieving a specific server without the resource group name.
Assert-AreEqual 3 $all2.Count | ||
|
||
# It is possible that there were existing servers in the subscription when the test was recorded, so make sure | ||
# that the servers that we created are retrieved and ignore the other ones. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This works, but it's a bit confusing to read. Does something like this work?
($server1, $server2, $server3) | foreach { Assert-True $_.ServerName -in $all2.ServerName }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interestingly that does work. I wasn't aware that trying to access a property on an array would return the property value for each object in the array.
@@ -59,87 +36,5 @@ protected virtual string GetResourceId(M model) | |||
HelpMessage = "The name of the resource group.")] | |||
[ValidateNotNullOrEmpty] | |||
public string ResourceGroupName { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@akromm changing ResourceGroupName from mandatory to non-mandatory is a breaking change?
Any reason you want to do this now?
What scenarios are you trying to fix? or is it just ease for user?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shahabhijeet is relaxing the requirements of parameters a breaking change? I'm doing this change because there have been multiple github issues requesting it. eg: #635
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@akromm @shahabhijeet changing a parameter from mandatory to non-mandatory is not a breaking change; however, the other way around is a breaking change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cormacpayne thanks for correcting. I wrote that comment and then a day later realized that is not right what I wrote, but by that time I was not able to come back to GitHub to correct it.
/// <summary> | ||
/// The base class for all Azure Sql cmdlets | ||
/// </summary> | ||
public abstract class AzureSqlCmdletBaseBase<M, A> : AzureRMCmdlet |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@akromm any reason there aren't any constraints for M, A?
|
||
protected virtual string GetResourceId(M model) | ||
{ | ||
var serverProperty = model.GetType().GetProperty("ServerName"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@akromm maybe I am missing to see how this will work when model is of type IEnumerable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shahabhijeet I have updated the method to work with IEnumerable and other single entity types. I have also added a corresponding unittest to ensure it works.
…model and IEnumerable entity lists.
|
||
protected virtual string GetResourceId(M model) | ||
{ | ||
object m = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@akromm why m is not of type M? Why object?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So that overriding methods in subclasses can use the specific type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shahabhijeet I think the right thing to do here is make the method Abstract and force each cmdlet to implement it.
To answer your question. It is of type object because M can be IEnumerable and I want an object of type T not M.
|
||
if (m != null) | ||
{ | ||
var serverProperty = m.GetType().GetProperty("ServerName"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@akromm if you make M to some constraint class, you don't have to deal with late bound objects.
{ | ||
object m = null; | ||
|
||
if (typeof(IEnumerable).IsAssignableFrom(model.GetType())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@akromm you have now covered two scenarios, IEnumerable and M.
Are you sure those are the only two types your consumers are going to pass in?
That is the reason you need to define constraints on M.
And then you should have however many overloads GetResourceId e.g.
GetResourceId(IEumerable listOfModels)
GetResourceId(ICollection modelCollection) just to make my point, but overloads can handle IEnumerable.
Having generic class with no constraint is setting yourself for runtime errors.
{ | ||
} | ||
|
||
protected virtual string GetResourceId(M model) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@akromm plus anyone who overrides and have their own implementation of this method will have to make sure they have safety code for all possible types of M (similar to what you have)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shahabhijeet This would be overridden per cmdlet type (Database, Server, DataMasking, ...) and as such the type M will be well known and there shouldn't be the complex logic I have.
/// </summary> | ||
/// <param name="model">The about to be written model object</param> | ||
/// <returns>The prepared object to be written out</returns> | ||
protected virtual object TransformModelToOutputObject(M model) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@akromm any generic class with late bound return types defeats the purpose of your generic class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shahabhijeet
This is only used in a couple places.
Get-AzureRmSqlDatabaseDataMaskingRule cmdlet uses it to filter the results before showing the user.
SqlDatabaseDataMaskingRuleCmdletBase also uses it to do client side filtering of the results.
New-AzureRmSqlDatabase Actually uses it to modify the response slightly.
That being said, all this code is pre-existing code that already existed. I'm just moving it to a new file. I might have a different way to achieve my main goal without moving this stuff around.
/// </summary> | ||
public override void ExecuteCmdlet() | ||
{ | ||
ModelAdapter = InitModelAdapter(DefaultProfile.DefaultContext.Subscription); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@akromm can you point me where is InitModelAdapter implemented?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shahabhijeet InitModelAdapter is implemented in each individual cmdlet. Database Cmdlet base example
Making ResourceGroupName parameter virtual rather than creating a new base class.
@cormacpayne @shahabhijeet @jaredmoo Finally got the tests to pass (issues with dependencies and NuGet package versions). Can I please get this reviewed and merged now :) Thanks. |
restructured how the changes are being done.
@azuresdkci test this please |
1 similar comment
@azuresdkci test this please |
Description
This checklist is used to make sure that common guidelines for a pull request are followed. You can find a more complete discussion of PowerShell cmdlet best practices here.
General Guidelines
Testing Guidelines
Cmdlet Signature Guidelines
ShouldProcess
and haveSupportShouldProcess=true
specified in the cmdlet attribute. You can find more information onShouldProcess
here.OutputType
attribute if any output is produced - if the cmdlet produces no output, it should implement aPassThru
parameter.Cmdlet Parameter Guidelines