Repository: cloud-custodian/cloud-custodian

Issue:
Support minutes in mark-for-op actions
**Is your feature request related to a problem? Please describe.**
`mark-for-op` just supports days and hours. These units are too big for some use cases.

**Describe the solution you'd like**
`mark-for-op` should also support minutes and maybe the other units supported by datetime.timedelta: seconds, microseconds, milliseconds, and weeks.
https://docs.python.org/3/library/datetime.html#datetime.timedelta

**Describe alternatives you've considered**
`mark-for-op` could also accept a float as hours, but this would be more complicated to implement and less reliable.

**Additional context**
```yaml
policies:
- name: ec2-mark-stop
  resource: ec2
  filters:
    - type: image-age
      op: ge
      minutes: 90
  actions:
    - type: mark-for-op
      tag: custodian_cleanup
      op: terminate
      minutes: 4
```



Discussion:
could you clarify the use case? I'm a bit unclear as to why? mark for op using minutes requires a fast periodic poller, which is typically an anti-pattern. ie. you'd have to be scanning instances every few minutes, which is going to ddos your api and all other usages of the ec2 api in the account, additionally its less than the default cache period.
Additionally, you can just specify `hours: 0.1` to get 6 minutes, for instance, if you wanted to be sure it was something less than your polling interval (which is typically no more frequent than hourly).
@kapilt I'm trying to automatically delete MSK clusters that are created without transit encryption. Those clusters take about 30min to get to a ready state, before that is not possible to delete the cluster. I've tried to delay the Lambda execution but I've noticed that it just calls a thread sleep instead of delaying the invocation itself, so I would be wasting a lot of minutes in AWS Lambda.
@tjstansell the schema currently requires an integer, I'm not able to specify 0.1 as a valid hour value.

https://github.com/cloud-custodian/cloud-custodian/blob/3736c896bb1fe52537d21b7743d52d5481653807/c7n/tags.py#L610

```
2020-07-15 12:12:12,581: custodian.commands:ERROR Configuration invalid: ./msk.yaml
2020-07-15 12:12:12,581: custodian.commands:ERROR Error on policy:msk-mark-noncompliant-clusters resource:kafka
0.1 is not of type 'integer'

Failed validating 'type' in schema[5]['properties']['hours']:
    {'minimum': 0, 'type': 'integer'}

On instance['hours']:
    0.1
2020-07-15 12:12:12,581: custodian.commands:ERROR msk-mark-noncompliant-clusters
```
oh, that's curious... I am using it for the `asg` resource and figured it was all the same.  Sure enough, `asg` is an override of `TagDelayedAction` and changes the schema from integer to number.  We should just change the default `TagDelayedAction` schema to numbers instead of integers.  Up to @kapilt if also adding minutes is reasonable.
I'm game to support numbers here in the schema for hours.

Resolving patch:
diff --git a/c7n/tags.py b/c7n/tags.py
--- a/c7n/tags.py
+++ b/c7n/tags.py
@@ -606,8 +606,8 @@ class TagDelayedAction(Action):
         'mark-for-op',
         tag={'type': 'string'},
         msg={'type': 'string'},
-        days={'type': 'integer', 'minimum': 0},
-        hours={'type': 'integer', 'minimum': 0},
+        days={'type': 'number', 'minimum': 0},
+        hours={'type': 'number', 'minimum': 0},
         tz={'type': 'string'},
         op={'type': 'string'})
     schema_alias = True
diff --git a/tools/c7n_azure/c7n_azure/actions/tagging.py b/tools/c7n_azure/c7n_azure/actions/tagging.py
--- a/tools/c7n_azure/c7n_azure/actions/tagging.py
+++ b/tools/c7n_azure/c7n_azure/actions/tagging.py
@@ -499,8 +499,8 @@ class TagDelayedAction(AzureBaseAction):
         'mark-for-op',
         tag={'type': 'string'},
         msg={'type': 'string'},
-        days={'type': 'integer', 'minimum': 0, 'exclusiveMinimum': False},
-        hours={'type': 'integer', 'minimum': 0, 'exclusiveMinimum': False},
+        days={'type': 'number', 'minimum': 0, 'exclusiveMinimum': False},
+        hours={'type': 'number', 'minimum': 0, 'exclusiveMinimum': False},
         tz={'type': 'string'},
         op={'type': 'string'})
     schema_alias = True
diff --git a/tools/c7n_gcp/c7n_gcp/actions/labels.py b/tools/c7n_gcp/c7n_gcp/actions/labels.py
--- a/tools/c7n_gcp/c7n_gcp/actions/labels.py
+++ b/tools/c7n_gcp/c7n_gcp/actions/labels.py
@@ -161,8 +161,8 @@ class LabelDelayedAction(BaseLabelAction):
         'mark-for-op',
         label={'type': 'string'},
         msg={'type': 'string'},
-        days={'type': 'integer', 'minimum': 0, 'exclusiveMinimum': False},
-        hours={'type': 'integer', 'minimum': 0, 'exclusiveMinimum': False},
+        days={'type': 'number', 'minimum': 0, 'exclusiveMinimum': False},
+        hours={'type': 'number', 'minimum': 0, 'exclusiveMinimum': False},
         tz={'type': 'string'},
         op={'type': 'string'}
     )


Test patch: