Skip to content

Conversation

@bulentelmaci
Copy link
Contributor

Command module for the new Microsoft.PolicyInsights RP.

This checklist is used to make sure that common guidelines for a pull request are followed.

  • The PR has modified HISTORY.rst describing any customer-facing, functional changes. Note that this does not include changes only to help content. (see Modifying change log).

  • I adhere to the Command Guidelines.

@promptws
Copy link

View a preview at https://prompt.ws/r/Azure/azure-cli/6378
This is an experimental preview for @microsoft users.

@codecov-io
Copy link

codecov-io commented May 17, 2018

Codecov Report

Merging #6378 into dev will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@         Coverage Diff         @@
##           dev   #6378   +/-   ##
===================================
  Coverage    0%      0%           
===================================
  Files       11      11           
  Lines      133     133           
  Branches     9       9           
===================================
  Misses     133     133

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ee4bb56...dd1fa77. Read the comment docs.

type: string

- name: --apply
type: string
Copy link
Member

Choose a reason for hiding this comment

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

None of these parameters entries are required.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thanks. will remove

- name: --policy-set-definition-name -ps
type: string

- name: --policy-definition-name -pd
Copy link
Member

Choose a reason for hiding this comment

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

Short options can only be a single character.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok

with self.argument_context('policy event') as c:
c.argument(
'management_group_name',
options_list=('--management-group-name', '-m'),
Copy link
Member

Choose a reason for hiding this comment

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

Please use list syntax (square brackets) and not tuple notation for options_list.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

will do.

c.argument(
'from_value',
options_list=('--from'),
help='Timestamp specifying the start time of the interval to query.')
Copy link
Member

Choose a reason for hiding this comment

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

What is the format of this? How are you (or are you?) validating this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

iso-8601. azure-mgmt-policyinsights API validates it to be iso-8601 and server validates it as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

You should probably give the timestamp format as part of the parameter help

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thanks. will do.

'all_results',
options_list=('--all'),
arg_type=get_three_state_flag(),
help='Within the specified time interval, get all policy states instead of the latest only.')
Copy link
Member

Choose a reason for hiding this comment

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

Is this a flag on the command behavior or a Boolean property? three_state_flag is intended for Boolean properties only. https://github.com/Azure/azure-cli/blob/dev/doc/authoring_command_modules/authoring_commands.md#registering-flags

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is a Boolean parameter.

Copy link
Member

Choose a reason for hiding this comment

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

Since it isn't saved (it's not a Boolean property on a resource) this should probably not use three_state_flag but instead use just "action=store_true"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the clarification. Will change this.

help='Resource group name.')
c.argument(
'resource_id',
options_list=('--resource-id', '-r'),
Copy link
Member

Choose a reason for hiding this comment

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

If this can be an arbitrary resource, it should expose the full range of resource ID or named components. See:
https://github.com/Azure/azure-cli/blob/dev/doc/authoring_command_modules/authoring_commands.md#supporting-name-or-id-parameters

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This makes the CLI inconsistent with the PS API, and ambiguous in itself. Our RP is an extension RP, and can be called with any resource as a scope. In the swagger API we specifically refrained from making parts of ARM resource ID separate parameters because that would make it impossible to support multiple nested level resources. API board review agreed on that. If we change this now in the CLI contract (so that we can support resource names), we will need to add multiple levels of namespace and resource type arguments, which makes the API unusable (and inconsistent with the PS API. Feel free to reach out to me to go over the swagger specs, PS API and any other details.

Copy link
Member

Choose a reason for hiding this comment

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

Consistency with Powershell is not important in the CLI, but consistency with other modules in the CLI is. This requires no change to swagger or the API.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As discussed offline, I'll implement additional parameters to make resourceid a resource that can take either an ID or a name.

c.argument(
'to_value',
options_list=('--to'),
help='Timestamp specifying the end time of the interval to query.')
Copy link
Member

Choose a reason for hiding this comment

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

There seems to be a lot of duplication of arguments. Please review: https://github.com/Azure/azure-cli/blob/dev/doc/authoring_command_modules/authoring_commands.md#customize-arguments

Please register your arguments at the appropriate scopes to avoid copy/paste duplicate code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is unavoidable. "policy event" and "policy state" share those parameters, but those do not exist in "policy".

If there is a way to define them once and use in different 'with' statements, please let me know - this is the first time I'm touching Phthon code.

Copy link
Contributor

Choose a reason for hiding this comment

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

You can use a for loop:

for scope in ['state', 'event']:
    with self.argument_context('policy {}'.format(scope)) as c:

Copy link
Contributor Author

Choose a reason for hiding this comment

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

state has one additional parameter. can i add it to the context after this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looks like I can. thanks!

Copy link
Member

Choose a reason for hiding this comment

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

If a parameter doesn't exist in a scope, it is ignored, so you don't need to worry too much about extras.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Cool. Just to make this explicit, I did common ones in a for loop and then specifically added the extra one (--all) for state into the context. It worked.

c.ignore('all_results')
c.ignore('order_by_clause')
c.ignore('select_clause')
c.ignore('apply_clause')
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do.

)

with self.command_group('policy event', policy_events_sdk, client_factory=policy_events_operations) as g:
g.custom_command('list', 'list_policy_events')
Copy link
Member

Choose a reason for hiding this comment

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

These commands are going to live side-by-side with the policy commands defined in azure-cli-resource. Is there a reason you don't just add your commands to that module?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, my intention is to maintain this package separately yet be part of the same command set. If the latter had not worked, I was planning to make it a separate command set.

Copy link
Contributor

Choose a reason for hiding this comment

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

Where do/will the powershell commands reside? If they are separate from the rest of the policy commands then this is also fine for us @twitchax

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In PS, there is no command set concept. You can name your cmdlets the way you want following some naming conventions. We have 3 cmdlets in PS: Get-AzureRmPolicyEvent, Get-AzureRmPolicyState and Get-AzureRmPolicyStateSummary.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I want to maintain the package separately for our RP. Not having to name the command set policyinsights makes it consistent with PS as well. This is probably not important for CLI, but I think it makes it much easier for customers to remember.

Copy link
Contributor

@williexu williexu May 21, 2018

Choose a reason for hiding this comment

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

We're fine with the new module in the CLI as in powershell, the policyinsights folder is also separate from that of resources

default_subscription_id,
query_options)

return summary.value[0]
Copy link
Member

Choose a reason for hiding this comment

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

What is the difference between summary and list?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

List returns a list of policy states. Summarize returns pre-cooked aggregations as a summary object. Feel free to reach out to me if you need more info on the RP. I explained the RP to @williexu briefly.

@bulentelmaci
Copy link
Contributor Author

@tjprescott @williexu Merged some of the requested changes. For the others and questions please see my comments above.

* Remove --subscription_id parameter
* Change --all to be store_true
* Change --resource_id to be --resource which can take resource ID or name
* Add --resource-provider-namespace and --resource-type parameters that are required if --resource is not an ID
@bulentelmaci
Copy link
Contributor Author

@tjprescott @williexu Updated the PR with the rest of the requested changes.

c.argument(
'apply_clause',
options_list=['--apply'],
help='Apply expression for aggregations using OData notation.')
Copy link
Contributor

Choose a reason for hiding this comment

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

Use the arg_group kwarg to group similar arguments. Ex. "Resource Id", "Query", "Policy", etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do

'resource_type',
options_list=['--resource-type', '-t'],
completer=get_resource_types_completion_list,
help='Resource type.')
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you format the resource args to align more closely with that of az resource?
Help for resource show shown below:

(env36) C:\Users\wilx\azure-cli>az resource show -h

Command
    az resource show: Get the details of a resource.

Arguments
    --include-response-body: Use if the default command output doesn't capture all of the property
                             data.  Allowed values: false, true.

Resource Id Arguments
    --api-version          : The api version of the resource (omit for latest).
    --ids                  : One or more resource IDs (space-delimited). If provided, no other
                             "Resource Id" arguments should be specified.
    --name -n              : The resource name. (Ex: myC).
    --namespace            : Provider namespace (Ex: 'Microsoft.Provider').
    --parent               : The parent path (Ex: 'resA/myA/resB/myB').
    --resource-group -g    : Name of resource group. You can configure the default group using `az
                             configure --defaults group=<name>`.
    --resource-type        : The resource type (Ex: 'resC'). Can also accept namespace/type format
                             (Ex: 'Microsoft.Provider/resC').

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As discussed, this does not apply to us.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will make the changes to align other resource parameters with the resources command set (will change names and add a parent parameter)

Copy link
Contributor

Choose a reason for hiding this comment

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

Yep, ignore the --ids parameter and allow --resource to accept both an id and name.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, thanks!

subscription_id,
query_options)

return summary.value[0]
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we only return the first value in the list?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The REST API path returns a list but the list always contains a single object (summary object).


subscription_id = get_subscription_id(cmd.cli_ctx)

if policy_assignment_name is not None:
Copy link
Contributor

Choose a reason for hiding this comment

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

Can the names be an empty string? If not, change this to if policy_assignment_name:.
Same for others below.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do

name=resource)
events = client.list_query_results_for_resource(
resource,
query_options)
Copy link
Contributor

Choose a reason for hiding this comment

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

Please provide a test for resource id scenario.
Also, what happens with more complex resource-ids like subnets? Here's an example id:
/subscriptions/<sub id>/resourceGroups/clitestlab/providers/Microsoft.Network/virtualNetworks/Dtlcliautomationlab/subnets/DtlcliautomationlabSubnet

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As discussed, I will add a test for that with a hard coded resource id which will not be enabled for live execution.

* Add arg_group to all parameters
* Don't override existing global resource_group_name parameter attributes other than arg_group; this way argument name and help stays standard with other commands.
* Change the name of the resource provider namespace argument to make it consistent with resource package
* Add parent argument to be used for resource name case to help specify nested resources
* Handle empty string in arguments
* Extend the scenario test to test all scopes and parameters; make it record only
@williexu
Copy link
Contributor

rebase to get the updates from #6407 please

@bulentelmaci
Copy link
Contributor Author

@tjprescott @williexu Updated the PR with the rest of the requested changes.

Copy link
Contributor

@williexu williexu left a comment

Choose a reason for hiding this comment

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

Looks generally good, small comments

arg_group='Scope')
c.argument(
'resource',
options_list=['--resource', '-r'],
Copy link
Contributor

Choose a reason for hiding this comment

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

the -r option should not be given as it is not available for other instances of --resource in the CLI and the default option is relatively short

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Forgot to remove. Will do.

help='Resource type (Ex: ''resC'').')
c.argument(
'policy_set_definition_name',
options_list=['--policy-set-definition-name', '-p'],
Copy link
Contributor

Choose a reason for hiding this comment

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

-s for set would be a much better choice

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed. Will change it.

@bulentelmaci
Copy link
Contributor Author

@tjprescott @williexu Made the small changes as well. Is this good to go?

@bulentelmaci
Copy link
Contributor Author

@tjprescott @williexu When merged, do I need to do anything for publishing this to PyPl? If not, how long after the merge should I expect it to be available there for PIP install?

@williexu
Copy link
Contributor

@bulentelmaci https://github.com/Azure/azure-cli/milestones has the dates of our release
Your command module will be released with the rest of the CLI on our release day

Copy link
Member

@tjprescott tjprescott left a comment

Choose a reason for hiding this comment

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

There's a major inconsistency between the "Resource ID" arguments and the "Scope" arguments. We should review options offline.

@bulentelmaci
Copy link
Contributor Author

@tjprescott “Resource ID” which is one of the query scopes (like MG, subscription, RG, policy set/definition/assignment) for policy events and states has no direct association to the scope for a policy assignment. I’ll ping you offline to explain and discuss.

Copy link
Contributor

@williexu williexu left a comment

Choose a reason for hiding this comment

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

More small fixes that came to mind.
The options_lists for --resource and --resource-type don't need to be given. By default, we will convert underscore-separated arguments to the corresponding arguments that users see, i.e. resource_type to --resource-type

options_list=['--resource'],
validator=validate_resource,
arg_group='Resource ID',
help='Resource ID or resource name.')
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd recommend adding an extra line to the help along the lines of,
If an name is given, please provide the resource_group and other relevant resource id arguments.

This is because --resource-group will be under a different argument group.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

will do

arg_group='Scope')
c.argument(
'resource',
options_list=['--resource'],
Copy link
Contributor

Choose a reason for hiding this comment

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

You can remove this options_list

Copy link
Contributor Author

Choose a reason for hiding this comment

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

will do.

help='The parent path (Ex: ''resA/myA/resB/myB'').')
c.argument(
'resource_type',
options_list=['--resource-type'],
Copy link
Contributor

Choose a reason for hiding this comment

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

and here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

will do

@williexu
Copy link
Contributor

@tjprescott for a last look

@troydai troydai merged commit f4ba5b0 into Azure:dev May 25, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants