1# --------------------------------------------------------------------------------------------
2# Copyright (c) Microsoft Corporation. All rights reserved.
3# Licensed under the MIT License. See License.txt in the project root for license information.
4# --------------------------------------------------------------------------------------------
5
6from msrestazure.tools import is_valid_resource_id, resource_id
7
8from azure.cli.core.commands.client_factory import get_subscription_id
9from azure.cli.core.util import sdk_no_wait
10
11from knack.util import CLIError
12
13
14def list_policy_events(
15        cmd,
16        client,
17        management_group_name=None,
18        resource_group_name=None,
19        resource=None,
20        namespace=None,
21        resource_type_parent=None,
22        resource_type=None,
23        policy_set_definition_name=None,
24        policy_definition_name=None,
25        policy_assignment_name=None,
26        from_value=None,
27        to_value=None,
28        order_by_clause=None,
29        select_clause=None,
30        top_value=None,
31        filter_clause=None,
32        apply_clause=None):
33
34    from azure.mgmt.policyinsights.models import QueryOptions
35
36    query_options = QueryOptions(
37        top=top_value,
38        order_by=order_by_clause,
39        select=select_clause,
40        from_property=from_value,
41        to=to_value,
42        filter=filter_clause,
43        apply=apply_clause)
44
45    subscription_id = get_subscription_id(cmd.cli_ctx)
46
47    if policy_assignment_name:
48        if resource_group_name:
49            events = client.list_query_results_for_resource_group_level_policy_assignment(
50                subscription_id,
51                resource_group_name,
52                policy_assignment_name,
53                query_options)
54        else:
55            events = client.list_query_results_for_subscription_level_policy_assignment(
56                subscription_id,
57                policy_assignment_name,
58                query_options)
59    elif policy_definition_name:
60        events = client.list_query_results_for_policy_definition(
61            subscription_id,
62            policy_definition_name,
63            query_options)
64    elif policy_set_definition_name:
65        events = client.list_query_results_for_policy_set_definition(
66            subscription_id,
67            policy_set_definition_name,
68            query_options)
69    elif resource:
70        if not is_valid_resource_id(resource):
71            if resource_type_parent:
72                resource_type_parent = _remove_leading_and_trailing_slash(resource_type_parent)
73                resource_type = "{}/{}".format(resource_type_parent, resource_type)
74            resource = resource_id(
75                subscription=subscription_id,
76                resource_group=resource_group_name,
77                namespace=namespace,
78                type=resource_type,
79                name=resource)
80        events = client.list_query_results_for_resource(
81            resource,
82            query_options)
83    elif resource_group_name:
84        events = client.list_query_results_for_resource_group(
85            subscription_id,
86            resource_group_name,
87            query_options)
88    elif management_group_name:
89        events = client.list_query_results_for_management_group(
90            management_group_name,
91            query_options)
92    else:
93        events = client.list_query_results_for_subscription(
94            subscription_id,
95            query_options)
96
97    return events
98
99
100def list_policy_states(
101        cmd,
102        client,
103        all_results=False,
104        management_group_name=None,
105        resource_group_name=None,
106        resource=None,
107        namespace=None,
108        resource_type_parent=None,
109        resource_type=None,
110        policy_set_definition_name=None,
111        policy_definition_name=None,
112        policy_assignment_name=None,
113        from_value=None,
114        to_value=None,
115        order_by_clause=None,
116        select_clause=None,
117        top_value=None,
118        filter_clause=None,
119        apply_clause=None,
120        expand_clause=None):
121
122    from azure.mgmt.policyinsights.models import QueryOptions
123
124    query_options = QueryOptions(
125        top=top_value,
126        order_by=order_by_clause,
127        select=select_clause,
128        from_property=from_value,
129        to=to_value,
130        filter=filter_clause,
131        apply=apply_clause,
132        expand=expand_clause)
133
134    policy_states_resource = 'latest'
135    if all_results is True:
136        policy_states_resource = 'default'
137
138    subscription_id = get_subscription_id(cmd.cli_ctx)
139
140    if policy_assignment_name:
141        if resource_group_name:
142            states = client.list_query_results_for_resource_group_level_policy_assignment(
143                policy_states_resource,
144                subscription_id,
145                resource_group_name,
146                policy_assignment_name,
147                query_options)
148        else:
149            states = client.list_query_results_for_subscription_level_policy_assignment(
150                policy_states_resource,
151                subscription_id,
152                policy_assignment_name,
153                query_options)
154    elif policy_definition_name:
155        states = client.list_query_results_for_policy_definition(
156            policy_states_resource,
157            subscription_id,
158            policy_definition_name,
159            query_options)
160    elif policy_set_definition_name:
161        states = client.list_query_results_for_policy_set_definition(
162            policy_states_resource,
163            subscription_id,
164            policy_set_definition_name,
165            query_options)
166    elif resource:
167        if not is_valid_resource_id(resource):
168            if resource_type_parent:
169                resource_type_parent = _remove_leading_and_trailing_slash(resource_type_parent)
170                resource_type = "{}/{}".format(resource_type_parent, resource_type)
171            resource = resource_id(
172                subscription=subscription_id,
173                resource_group=resource_group_name,
174                namespace=namespace,
175                type=resource_type,
176                name=resource)
177        states = client.list_query_results_for_resource(
178            policy_states_resource,
179            resource,
180            query_options)
181    elif resource_group_name:
182        states = client.list_query_results_for_resource_group(
183            policy_states_resource,
184            subscription_id,
185            resource_group_name,
186            query_options)
187    elif management_group_name:
188        states = client.list_query_results_for_management_group(
189            policy_states_resource,
190            management_group_name,
191            query_options)
192    else:
193        states = client.list_query_results_for_subscription(
194            policy_states_resource,
195            subscription_id,
196            query_options)
197
198    return states
199
200
201def summarize_policy_states(
202        cmd,
203        client,
204        management_group_name=None,
205        resource_group_name=None,
206        resource=None,
207        namespace=None,
208        resource_type_parent=None,
209        resource_type=None,
210        policy_set_definition_name=None,
211        policy_definition_name=None,
212        policy_assignment_name=None,
213        from_value=None,
214        to_value=None,
215        top_value=None,
216        filter_clause=None):
217
218    from azure.mgmt.policyinsights.models import QueryOptions
219
220    query_options = QueryOptions(
221        top=top_value,
222        from_property=from_value,
223        to=to_value,
224        filter=filter_clause)
225
226    subscription_id = get_subscription_id(cmd.cli_ctx)
227
228    if policy_assignment_name:
229        if resource_group_name:
230            summary = client.summarize_for_resource_group_level_policy_assignment(
231                subscription_id,
232                resource_group_name,
233                policy_assignment_name,
234                query_options)
235        else:
236            summary = client.summarize_for_subscription_level_policy_assignment(
237                subscription_id,
238                policy_assignment_name,
239                query_options)
240    elif policy_definition_name:
241        summary = client.summarize_for_policy_definition(
242            subscription_id,
243            policy_definition_name,
244            query_options)
245    elif policy_set_definition_name:
246        summary = client.summarize_for_policy_set_definition(
247            subscription_id,
248            policy_set_definition_name,
249            query_options)
250    elif resource:
251        resource = _build_resource_id(
252            subscription_id,
253            resource,
254            resource_group_name,
255            namespace,
256            resource_type_parent,
257            resource_type)
258        summary = client.summarize_for_resource(
259            resource,
260            query_options)
261    elif resource_group_name:
262        summary = client.summarize_for_resource_group(
263            subscription_id,
264            resource_group_name,
265            query_options)
266    elif management_group_name:
267        summary = client.summarize_for_management_group(
268            management_group_name,
269            query_options)
270    else:
271        summary = client.summarize_for_subscription(
272            subscription_id,
273            query_options)
274
275    return summary.value[0]
276
277
278def trigger_policy_scan(
279        cmd,
280        client,
281        resource_group_name=None,
282        no_wait=False):
283
284    subscription_id = get_subscription_id(cmd.cli_ctx)
285    if resource_group_name:
286        return sdk_no_wait(no_wait, client.begin_trigger_resource_group_evaluation,
287                           subscription_id, resource_group_name)
288
289    return sdk_no_wait(no_wait, client.begin_trigger_subscription_evaluation,
290                       subscription_id)
291
292
293def get_policy_remediation(
294        cmd,
295        client,
296        remediation_name,
297        management_group_name=None,
298        resource_group_name=None,
299        resource=None,
300        namespace=None,
301        resource_type_parent=None,
302        resource_type=None):
303
304    return _execute_remediation_operation(
305        cmd,
306        client,
307        "get_at_resource",
308        management_group_name,
309        resource_group_name,
310        resource,
311        namespace,
312        resource_type_parent,
313        resource_type,
314        remediation_name)
315
316
317def list_policy_remediations(
318        cmd,
319        client,
320        management_group_name=None,
321        resource_group_name=None,
322        resource=None,
323        namespace=None,
324        resource_type_parent=None,
325        resource_type=None):
326
327    return _execute_remediation_operation(
328        cmd,
329        client,
330        "list_for_resource",
331        management_group_name,
332        resource_group_name,
333        resource,
334        namespace,
335        resource_type_parent,
336        resource_type)
337
338
339def delete_policy_remediation(
340        cmd,
341        client,
342        remediation_name,
343        management_group_name=None,
344        resource_group_name=None,
345        resource=None,
346        namespace=None,
347        resource_type_parent=None,
348        resource_type=None):
349
350    return _execute_remediation_operation(
351        cmd,
352        client,
353        "delete_at_resource",
354        management_group_name,
355        resource_group_name,
356        resource,
357        namespace,
358        resource_type_parent,
359        resource_type,
360        remediation_name)
361
362
363def cancel_policy_remediation(
364        cmd,
365        client,
366        remediation_name,
367        management_group_name=None,
368        resource_group_name=None,
369        resource=None,
370        namespace=None,
371        resource_type_parent=None,
372        resource_type=None):
373
374    return _execute_remediation_operation(
375        cmd,
376        client,
377        "cancel_at_resource",
378        management_group_name,
379        resource_group_name,
380        resource,
381        namespace,
382        resource_type_parent,
383        resource_type,
384        remediation_name)
385
386
387def list_policy_remediation_deployments(
388        cmd,
389        client,
390        remediation_name,
391        management_group_name=None,
392        resource_group_name=None,
393        resource=None,
394        namespace=None,
395        resource_type_parent=None,
396        resource_type=None):
397
398    return _execute_remediation_operation(
399        cmd,
400        client,
401        "list_deployments_at_resource",
402        management_group_name,
403        resource_group_name,
404        resource,
405        namespace,
406        resource_type_parent,
407        resource_type,
408        remediation_name)
409
410
411def create_policy_remediation(
412        cmd,
413        client,
414        remediation_name,
415        policy_assignment,
416        definition_reference_id=None,
417        location_filters=None,
418        management_group_name=None,
419        resource_group_name=None,
420        resource=None,
421        namespace=None,
422        resource_type_parent=None,
423        resource_type=None,
424        resource_discovery_mode=None):
425
426    subscription_id = get_subscription_id(cmd.cli_ctx)
427    scope = _build_remediation_scope(
428        management_group_name,
429        subscription_id,
430        resource_group_name,
431        resource,
432        resource_type_parent,
433        resource_type,
434        namespace)
435
436    from azure.mgmt.policyinsights.models import Remediation
437    remediation = Remediation(policy_definition_reference_id=definition_reference_id)
438
439    # Get the full resource ID of the referenced policy assignment
440    if (not is_valid_resource_id(policy_assignment) and
441            not policy_assignment.lower().startswith("/providers/microsoft.management/managementgroups/")):
442        from ._client_factory import cf_policy
443        policy_assignment_client = cf_policy(cmd.cli_ctx).policy_assignments
444        policy_assignments = policy_assignment_client.list()
445        policy_assignment_ids = [p.id for p in policy_assignments if p.name.lower() == policy_assignment.lower()]
446        if not policy_assignment_ids:
447            raise CLIError("No policy assignment with the name '{}' found.".format(policy_assignment))
448        if len(policy_assignment_ids) > 1:
449            raise CLIError("Multiple policy assignment with the name '{}' found. "
450                           "Specify the policy assignment ID.".format(policy_assignment))
451        policy_assignment = policy_assignment_ids[0]
452    remediation.policy_assignment_id = policy_assignment
453
454    # Ensure locations in the location filters are using their short name
455    if location_filters:
456        locations_list = []
457        for location_arg in location_filters:
458            locations_list.append(location_arg.replace(' ', ''))
459        from azure.mgmt.policyinsights.models import RemediationFilters
460        remediation.filters = RemediationFilters(locations=locations_list)
461
462    if resource_discovery_mode:
463        remediation.resource_discovery_mode = resource_discovery_mode
464
465    return client.create_or_update_at_resource(
466        resource_id=_remove_leading_and_trailing_slash(scope),
467        remediation_name=remediation_name,
468        parameters=remediation)
469
470
471def show_policy_metadata(cmd, client, resource_name):   # pylint: disable=unused-argument
472    return client.get_resource(resource_name=resource_name)
473
474
475def list_policy_metadata(cmd, client, top_value=None):   # pylint: disable=unused-argument
476    if top_value is not None:
477        from azure.mgmt.policyinsights.models import QueryOptions
478        page_iter = client.list(QueryOptions(top=top_value)).by_page()
479        results = []
480
481        while len(results) < top_value:
482            try:
483                results += list(next(page_iter))
484            except StopIteration:
485                break
486
487        return results[:top_value]
488
489    return list(client.list())
490
491
492def _execute_remediation_operation(
493        cmd,
494        client,
495        operation_name,
496        management_group_name=None,
497        resource_group_name=None,
498        resource=None,
499        namespace=None,
500        resource_type_parent=None,
501        resource_type=None,
502        remediation_name=None):
503
504    subscription_id = get_subscription_id(cmd.cli_ctx)
505    scope = _build_remediation_scope(
506        management_group_name,
507        subscription_id,
508        resource_group_name,
509        resource,
510        resource_type_parent,
511        resource_type,
512        namespace)
513
514    operation = getattr(client, operation_name)
515    if remediation_name is None:
516        return operation(resource_id=_remove_leading_and_trailing_slash(scope))
517    return operation(resource_id=_remove_leading_and_trailing_slash(scope), remediation_name=remediation_name)
518
519
520def _build_resource_id(
521        subscription_id,
522        resource,
523        resource_group_name=None,
524        namespace=None,
525        resource_type_parent=None,
526        resource_type=None):
527
528    if not is_valid_resource_id(resource):
529        if resource_type_parent:
530            resource_type_parent = _remove_leading_and_trailing_slash(resource_type_parent)
531            resource_type = "{}/{}".format(resource_type_parent, resource_type)
532
533        resource = resource_id(
534            subscription=subscription_id,
535            resource_group=resource_group_name,
536            namespace=namespace,
537            type=resource_type,
538            name=resource)
539
540    return resource
541
542
543def _build_remediation_scope(
544        management_group=None,
545        subscription=None,
546        resource_group_name=None,
547        resource=None,
548        resource_type_parent=None,
549        resource_type=None,
550        namespace=None):
551
552    if management_group:
553        return "/providers/Microsoft.Management/managementGroups/{}".format(management_group)
554    if resource:
555        return _build_resource_id(subscription, resource, resource_group_name,
556                                  namespace, resource_type_parent, resource_type)
557    return resource_id(subscription=subscription, resource_group=resource_group_name)
558
559
560def _remove_leading_and_trailing_slash(s):
561    if s:
562        if s.startswith('/'):
563            s = s[1:]
564        if s.endswith('/'):
565            s = s[:-1]
566
567    return s
568