Vmss scale in policy (#66512)

* azure_rm_virtualmachinescaleset: add scale_in_policy and terminate_event_notification

* azure_rm_virtualmachinescalesetinstance: add vmss instance protection policy support
This commit is contained in:
haiyuan_zhang 2020-01-16 09:24:39 +08:00 committed by Zim Kalinowski
parent e459eac565
commit bc37ea96d5
8 changed files with 161 additions and 34 deletions

View File

@ -936,7 +936,7 @@ class AzureRMModuleBase(object):
if not self._network_client:
self._network_client = self.get_mgmt_svc_client(NetworkManagementClient,
base_url=self._cloud_environment.endpoints.resource_manager,
api_version='2018-08-01')
api_version='2019-06-01')
return self._network_client
@property
@ -964,13 +964,13 @@ class AzureRMModuleBase(object):
if not self._compute_client:
self._compute_client = self.get_mgmt_svc_client(ComputeManagementClient,
base_url=self._cloud_environment.endpoints.resource_manager,
api_version='2018-06-01')
api_version='2019-07-01')
return self._compute_client
@property
def compute_models(self):
self.log("Getting compute models")
return ComputeManagementClient.models("2018-06-01")
return ComputeManagementClient.models("2019-07-01")
@property
def dns_client(self):

View File

@ -241,6 +241,19 @@ options:
U(https://docs.microsoft.com/en-us/azure/virtual-machines/linux/using-cloud-init#cloud-init-overview),
follow these steps U(https://docs.microsoft.com/en-us/azure/virtual-machines/linux/cloudinit-prepare-custom-image).
version_added: "2.8"
scale_in_policy:
description:
- define the order in which vmss instances are scaled-in
choices:
- Default
- NewestVM
- OldestVM
version_added: "2.10"
terminate_event_timeout_minutes:
description:
- timeout time for termination notification event
- in range between 5 and 15
version_added: "2.10"
extends_documentation_fragment:
- azure
@ -261,6 +274,8 @@ EXAMPLES = '''
virtual_network_name: testvnet
upgrade_policy: Manual
subnet_name: testsubnet
terminate_event_timeout_minutes: 10
scale_in_policy: NewestVM
admin_username: adminUser
ssh_password_enabled: false
ssh_public_keys:
@ -364,6 +379,11 @@ azure_vmss:
sample: {
"properties": {
"overprovision": true,
"scaleInPolicy": {
"rules": [
"NewestVM"
]
},
"singlePlacementGroup": true,
"upgradePolicy": {
"mode": "Manual"
@ -410,6 +430,12 @@ azure_vmss:
},
"secrets": []
},
"scheduledEventsProfile": {
"terminateNotificationProfile": {
"enable": true,
"notBeforeTimeout": "PT10M"
}
},
"storageProfile": {
"dataDisks": [
{
@ -448,8 +474,6 @@ azure_vmss:
}
''' # NOQA
import random
import re
import base64
try:
@ -508,6 +532,8 @@ class AzureRMVirtualMachineScaleSet(AzureRMModuleBase):
plan=dict(type='dict', options=dict(publisher=dict(type='str', required=True),
product=dict(type='str', required=True), name=dict(type='str', required=True),
promotion_code=dict(type='str'))),
scale_in_policy=dict(type='str', choices=['Default', 'OldestVM', 'NewestVM']),
terminate_event_timeout_minutes=dict(type='int')
)
self.resource_group = None
@ -542,11 +568,8 @@ class AzureRMVirtualMachineScaleSet(AzureRMModuleBase):
self.zones = None
self.custom_data = None
self.plan = None
required_if = [
('state', 'present', [
'vm_size'])
]
self.scale_in_policy = None
self.terminate_event_timeout_minutes = None
mutually_exclusive = [('load_balancer', 'application_gateway')]
self.results = dict(
@ -558,13 +581,10 @@ class AzureRMVirtualMachineScaleSet(AzureRMModuleBase):
super(AzureRMVirtualMachineScaleSet, self).__init__(
derived_arg_spec=self.module_arg_spec,
supports_check_mode=True,
required_if=required_if,
mutually_exclusive=mutually_exclusive)
def exec_module(self, **kwargs):
nsg = None
for key in list(self.module_arg_spec.keys()) + ['tags']:
setattr(self, key, kwargs[key])
@ -585,11 +605,8 @@ class AzureRMVirtualMachineScaleSet(AzureRMModuleBase):
results = dict()
vmss = None
disable_ssh_password = None
vmss_dict = None
virtual_network = None
subnet = None
image_reference = None
custom_image = False
load_balancer_backend_address_pools = None
load_balancer_inbound_nat_pools = None
load_balancer = None
@ -737,6 +754,27 @@ class AzureRMVirtualMachineScaleSet(AzureRMModuleBase):
changed = True
vmss_dict['zones'] = self.zones
if self.terminate_event_timeout_minutes:
timeout = self.terminate_event_timeout_minutes
if timeout < 5 or timeout > 15:
self.fail("terminate_event_timeout_minutes should >= 5 and <= 15")
iso_8601_format = "PT" + str(timeout) + "M"
old = vmss_dict['properties']['virtualMachineProfile'].get('scheduledEventsProfile', {}).\
get('terminateNotificationProfile', {}).get('notBeforeTimeout', "")
if old != iso_8601_format:
differences.append('terminateNotification')
changed = True
vmss_dict['properties']['virtualMachineProfile'].setdefault('scheduledEventsProfile', {})['terminateNotificationProfile'] = {
'notBeforeTimeout': iso_8601_format,
"enable": 'true'
}
if self.scale_in_policy and self.scale_in_policy != vmss_dict['properties'].get('scaleInPolicy', {}).get('rules', [""])[0]:
self.log("CHANGED: virtual machine sale sets {0} scale in policy".format(self.name))
differences.append('scaleInPolicy')
changed = True
vmss_dict['properties'].setdefault('scaleInPolicy', {})['rules'] = [self.scale_in_policy]
nicConfigs = vmss_dict['properties']['virtualMachineProfile']['networkProfile']['networkInterfaceConfigurations']
backend_address_pool = nicConfigs[0]['properties']['ipConfigurations'][0]['properties'].get('loadBalancerBackendAddressPools', [])
@ -752,7 +790,7 @@ class AzureRMVirtualMachineScaleSet(AzureRMModuleBase):
lb_or_ag_id = "{0}/".format(application_gateway.id)
backend_address_pool_id = backend_address_pool[0].get('id')
if bool(lb_or_ag_id) != bool(backend_address_pool_id) or not backend_address_pool_id.startswith(lb_or_ag_id):
if lb_or_ag_id is not None and (bool(lb_or_ag_id) != bool(backend_address_pool_id) or not backend_address_pool_id.startswith(lb_or_ag_id)):
differences.append('load_balancer')
changed = True
@ -785,6 +823,9 @@ class AzureRMVirtualMachineScaleSet(AzureRMModuleBase):
if self.state == 'present':
if not vmss:
# Create the VMSS
if self.vm_size is None:
self.fail("vm size must be set")
self.log("Create virtual machine scale set {0}".format(self.name))
self.results['actions'].append('Created VMSS {0}'.format(self.name))
@ -793,9 +834,7 @@ class AzureRMVirtualMachineScaleSet(AzureRMModuleBase):
self.fail("Parameter error: ssh_public_keys required when disabling SSH password.")
if not self.virtual_network_name:
default_vnet = self.create_default_vnet()
virtual_network = default_vnet.id
self.virtual_network_name = default_vnet.name
self.fail("virtual network name is required")
if self.subnet_name:
subnet = self.get_subnet(self.virtual_network_name, self.subnet_name)
@ -877,6 +916,12 @@ class AzureRMVirtualMachineScaleSet(AzureRMModuleBase):
zones=self.zones
)
if self.scale_in_policy:
vmss_resource.scale_in_policy = self.gen_scale_in_policy()
if self.terminate_event_timeout_minutes:
vmss_resource.virtual_machine_profile.scheduled_events_profile = self.gen_scheduled_event_profile()
if self.admin_password:
vmss_resource.virtual_machine_profile.os_profile.admin_password = self.admin_password
@ -972,6 +1017,12 @@ class AzureRMVirtualMachineScaleSet(AzureRMModuleBase):
))
vmss_resource.virtual_machine_profile.storage_profile.data_disks = data_disks
if self.scale_in_policy:
vmss_resource.scale_in_policy = self.gen_scale_in_policy()
if self.terminate_event_timeout_minutes:
vmss_resource.virtual_machine_profile.scheduled_events_profile = self.gen_scheduled_event_profile()
if image_reference is not None:
vmss_resource.virtual_machine_profile.storage_profile.image_reference = image_reference
self.log("Update virtual machine with parameters:")
@ -1138,6 +1189,23 @@ class AzureRMVirtualMachineScaleSet(AzureRMModuleBase):
name = azure_id_to_dict(id).get('name')
return dict(id=id, name=name)
def gen_scheduled_event_profile(self):
if self.terminate_event_timeout_minutes is None:
return None
scheduledEventProfile = self.compute_models.ScheduledEventsProfile()
terminationProfile = self.compute_models.TerminateNotificationProfile()
terminationProfile.not_before_timeout = "PT" + str(self.terminate_event_timeout_minutes) + "M"
terminationProfile.enable = True
scheduledEventProfile.terminate_notification_profile = terminationProfile
return scheduledEventProfile
def gen_scale_in_policy(self):
if self.scale_in_policy is None:
return None
return self.compute_models.ScaleInPolicy(rules=[self.scale_in_policy])
def main():
AzureRMVirtualMachineScaleSet()

View File

@ -41,11 +41,20 @@ options:
power_state:
description:
- Use this option to change power state of the instance.
required: True
choices:
- 'running'
- 'stopped'
- 'deallocated'
protect_from_scale_in:
type: bool
description:
- turn on/off instance protection from scale in
version_added: "2.10"
protect_from_scale_set_actions:
type: bool
description:
- tun on/off instance protection from scale set actions
version_added: "2.10"
state:
description:
- State of the VMSS instance. Use C(present) to update an instance and C(absent) to delete an instance.
@ -69,6 +78,13 @@ EXAMPLES = '''
vmss_name: myVMSS
instance_id: "2"
latest_model: yes
- name: Turn on protect from scale in
azure_rm_virtualmachinescalesetinstance:
resource_group: myResourceGroup
vmss_name: myVMSS
instance_id: "2"
protect_from_scale_in: true
'''
RETURN = '''
@ -119,6 +135,12 @@ class AzureRMVirtualMachineScaleSetInstance(AzureRMModuleBase):
type='str',
choices=['running', 'stopped', 'deallocated']
),
protect_from_scale_in=dict(
type='bool'
),
protect_from_scale_set_actions=dict(
type='bool'
),
state=dict(
type='str',
default='present',
@ -136,13 +158,16 @@ class AzureRMVirtualMachineScaleSetInstance(AzureRMModuleBase):
self.latest_model = None
self.power_state = None
self.state = None
self.protect_from_scale_in = None
self.protect_from_scale_set_actions = None
super(AzureRMVirtualMachineScaleSetInstance, self).__init__(self.module_arg_spec, supports_tags=False)
def exec_module(self, **kwargs):
for key in self.module_arg_spec:
setattr(self, key, kwargs[key])
self.mgmt_client = self.get_mgmt_svc_client(ComputeManagementClient,
base_url=self._cloud_environment.endpoints.resource_manager)
base_url=self._cloud_environment.endpoints.resource_manager,
api_version='2019-07-01')
instances = self.get()
@ -175,6 +200,14 @@ class AzureRMVirtualMachineScaleSetInstance(AzureRMModuleBase):
if not self.check_mode:
self.start(item['instance_id'])
self.results['changed'] = True
if self.protect_from_scale_in is not None or self.protect_from_scale_set_actions is not None:
for item in instances:
protection_policy = item['protection_policy']
if protection_policy is None or self.protect_from_scale_in != protection_policy['protect_from_scale_in'] or \
self.protect_from_scale_set_actions != protection_policy['protect_from_scale_set_actions']:
if not self.check_mode:
self.update_protection_policy(self.instance_id, self.protect_from_scale_in, self.protect_from_scale_set_actions)
self.results['changed'] = True
self.results['instances'] = [{'id': item['id']} for item in instances]
return self.results
@ -202,8 +235,8 @@ class AzureRMVirtualMachineScaleSetInstance(AzureRMModuleBase):
instance_ids=[instance_id])
self.get_poller_result(poller)
except CloudError as exc:
self.log("Error applying latest model {0} - {1}".format(self.name, str(exc)))
self.fail("Error applying latest model {0} - {1}".format(self.name, str(exc)))
self.log("Error applying latest model {0} - {1}".format(self.vmss_name, str(exc)))
self.fail("Error applying latest model {0} - {1}".format(self.vmss_name, str(exc)))
def delete(self, instance_id):
try:
@ -241,6 +274,27 @@ class AzureRMVirtualMachineScaleSetInstance(AzureRMModuleBase):
self.log('Could not deallocate instance of Virtual Machine Scale Set VM.')
self.fail('Could not deallocate instance of Virtual Machine Scale Set VM.')
def update_protection_policy(self, instance_id, protect_from_scale_in, protect_from_scale_set_actions):
try:
d = {}
if protect_from_scale_in is not None:
d['protect_from_scale_in'] = protect_from_scale_in
if protect_from_scale_set_actions is not None:
d['protect_from_scale_set_actions'] = protect_from_scale_set_actions
protection_policy = self.compute_models.VirtualMachineScaleSetVMProtectionPolicy(**d)
instance = self.mgmt_client.virtual_machine_scale_set_vms.get(resource_group_name=self.resource_group,
vm_scale_set_name=self.vmss_name,
instance_id=instance_id)
instance.protection_policy = protection_policy
poller = self.mgmt_client.virtual_machine_scale_set_vms.update(resource_group_name=self.resource_group,
vm_scale_set_name=self.vmss_name,
instance_id=instance_id,
parameters=instance)
self.get_poller_result(poller)
except CloudError as e:
self.log('Could not update instance protection policy.')
self.fail('Could not update instance protection policy.')
def format_response(self, item):
d = item.as_dict()
iv = self.mgmt_client.virtual_machine_scale_set_vms.get_instance_view(resource_group_name=self.resource_group,
@ -257,7 +311,8 @@ class AzureRMVirtualMachineScaleSetInstance(AzureRMModuleBase):
'tags': d.get('tags'),
'instance_id': d.get('instance_id'),
'latest_model': d.get('latest_model_applied'),
'power_state': power_state
'power_state': power_state,
'protection_policy': d.get('protection_policy')
}
return d

View File

@ -7,7 +7,7 @@ azure-common==1.1.11
azure-mgmt-authorization==0.51.1
azure-mgmt-batch==5.0.1
azure-mgmt-cdn==3.0.0
azure-mgmt-compute==4.4.0
azure-mgmt-compute==10.0.0
azure-mgmt-containerinstance==1.4.0
azure-mgmt-containerregistry==2.0.0
azure-mgmt-containerservice==4.4.0
@ -15,7 +15,7 @@ azure-mgmt-dns==2.1.0
azure-mgmt-keyvault==1.1.0
azure-mgmt-marketplaceordering==0.1.0
azure-mgmt-monitor==0.5.2
azure-mgmt-network==2.3.0
azure-mgmt-network==4.0.0
azure-mgmt-nspkg==2.0.0
azure-mgmt-redis==5.0.0
azure-mgmt-resource==2.1.0
@ -27,8 +27,8 @@ azure-mgmt-trafficmanager==0.50.0
azure-mgmt-web==0.41.0
azure-nspkg==2.0.0
azure-storage==0.35.1
msrest==0.6.1
msrestazure==0.5.0
msrest==0.6.10
msrestazure==0.6.2
azure-keyvault==1.0.0a1
azure-graphrbac==0.40.0
azure-mgmt-cosmosdb==0.5.2

View File

@ -161,6 +161,9 @@ matrix:
- env: T=azure/2.7/10
- env: T=azure/3.6/10
- env: T=azure/2.7/11
- env: T=azure/3.6/11
- env: T=vcenter/2.7/1
- env: T=vcenter/3.6/1

View File

@ -1,6 +1,6 @@
cloud/azure
destructive
shippable/azure/group8
shippable/azure/group11
azure_rm_postgresqlserver_facts
azure_rm_postgresqldatabase
azure_rm_postgresqldatabase_facts

View File

@ -163,6 +163,7 @@
disk_size_gb: 64
caching: ReadWrite
managed_disk_type: Standard_LRS
scale_in_policy: "NewestVM"
register: results
- name: Assert that VMSS was created

View File

@ -7,7 +7,7 @@ azure-common==1.1.11
azure-mgmt-authorization==0.51.1
azure-mgmt-batch==5.0.1
azure-mgmt-cdn==3.0.0
azure-mgmt-compute==4.4.0
azure-mgmt-compute==10.0.0
azure-mgmt-containerinstance==1.4.0
azure-mgmt-containerregistry==2.0.0
azure-mgmt-containerservice==4.4.0
@ -15,7 +15,7 @@ azure-mgmt-dns==2.1.0
azure-mgmt-keyvault==1.1.0
azure-mgmt-marketplaceordering==0.1.0
azure-mgmt-monitor==0.5.2
azure-mgmt-network==2.3.0
azure-mgmt-network==4.0.0
azure-mgmt-nspkg==2.0.0
azure-mgmt-redis==5.0.0
azure-mgmt-resource==2.1.0
@ -27,8 +27,8 @@ azure-mgmt-trafficmanager==0.50.0
azure-mgmt-web==0.41.0
azure-nspkg==2.0.0
azure-storage==0.35.1
msrest==0.6.1
msrestazure==0.5.0
msrest==0.6.10
msrestazure==0.6.2
azure-keyvault==1.0.0a1
azure-graphrbac==0.40.0
azure-mgmt-cosmosdb==0.5.2