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
pull/66300/head
haiyuan_zhang 6 years ago committed by Zim Kalinowski
parent e459eac565
commit bc37ea96d5

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

@ -241,6 +241,19 @@ options:
U(https://docs.microsoft.com/en-us/azure/virtual-machines/linux/using-cloud-init#cloud-init-overview), 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). follow these steps U(https://docs.microsoft.com/en-us/azure/virtual-machines/linux/cloudinit-prepare-custom-image).
version_added: "2.8" 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: extends_documentation_fragment:
- azure - azure
@ -261,6 +274,8 @@ EXAMPLES = '''
virtual_network_name: testvnet virtual_network_name: testvnet
upgrade_policy: Manual upgrade_policy: Manual
subnet_name: testsubnet subnet_name: testsubnet
terminate_event_timeout_minutes: 10
scale_in_policy: NewestVM
admin_username: adminUser admin_username: adminUser
ssh_password_enabled: false ssh_password_enabled: false
ssh_public_keys: ssh_public_keys:
@ -364,6 +379,11 @@ azure_vmss:
sample: { sample: {
"properties": { "properties": {
"overprovision": true, "overprovision": true,
"scaleInPolicy": {
"rules": [
"NewestVM"
]
},
"singlePlacementGroup": true, "singlePlacementGroup": true,
"upgradePolicy": { "upgradePolicy": {
"mode": "Manual" "mode": "Manual"
@ -410,6 +430,12 @@ azure_vmss:
}, },
"secrets": [] "secrets": []
}, },
"scheduledEventsProfile": {
"terminateNotificationProfile": {
"enable": true,
"notBeforeTimeout": "PT10M"
}
},
"storageProfile": { "storageProfile": {
"dataDisks": [ "dataDisks": [
{ {
@ -448,8 +474,6 @@ azure_vmss:
} }
''' # NOQA ''' # NOQA
import random
import re
import base64 import base64
try: try:
@ -508,6 +532,8 @@ class AzureRMVirtualMachineScaleSet(AzureRMModuleBase):
plan=dict(type='dict', options=dict(publisher=dict(type='str', required=True), plan=dict(type='dict', options=dict(publisher=dict(type='str', required=True),
product=dict(type='str', required=True), name=dict(type='str', required=True), product=dict(type='str', required=True), name=dict(type='str', required=True),
promotion_code=dict(type='str'))), 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 self.resource_group = None
@ -542,11 +568,8 @@ class AzureRMVirtualMachineScaleSet(AzureRMModuleBase):
self.zones = None self.zones = None
self.custom_data = None self.custom_data = None
self.plan = None self.plan = None
self.scale_in_policy = None
required_if = [ self.terminate_event_timeout_minutes = None
('state', 'present', [
'vm_size'])
]
mutually_exclusive = [('load_balancer', 'application_gateway')] mutually_exclusive = [('load_balancer', 'application_gateway')]
self.results = dict( self.results = dict(
@ -558,13 +581,10 @@ class AzureRMVirtualMachineScaleSet(AzureRMModuleBase):
super(AzureRMVirtualMachineScaleSet, self).__init__( super(AzureRMVirtualMachineScaleSet, self).__init__(
derived_arg_spec=self.module_arg_spec, derived_arg_spec=self.module_arg_spec,
supports_check_mode=True, supports_check_mode=True,
required_if=required_if,
mutually_exclusive=mutually_exclusive) mutually_exclusive=mutually_exclusive)
def exec_module(self, **kwargs): def exec_module(self, **kwargs):
nsg = None
for key in list(self.module_arg_spec.keys()) + ['tags']: for key in list(self.module_arg_spec.keys()) + ['tags']:
setattr(self, key, kwargs[key]) setattr(self, key, kwargs[key])
@ -585,11 +605,8 @@ class AzureRMVirtualMachineScaleSet(AzureRMModuleBase):
results = dict() results = dict()
vmss = None vmss = None
disable_ssh_password = None disable_ssh_password = None
vmss_dict = None
virtual_network = None
subnet = None subnet = None
image_reference = None image_reference = None
custom_image = False
load_balancer_backend_address_pools = None load_balancer_backend_address_pools = None
load_balancer_inbound_nat_pools = None load_balancer_inbound_nat_pools = None
load_balancer = None load_balancer = None
@ -737,6 +754,27 @@ class AzureRMVirtualMachineScaleSet(AzureRMModuleBase):
changed = True changed = True
vmss_dict['zones'] = self.zones 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'] nicConfigs = vmss_dict['properties']['virtualMachineProfile']['networkProfile']['networkInterfaceConfigurations']
backend_address_pool = nicConfigs[0]['properties']['ipConfigurations'][0]['properties'].get('loadBalancerBackendAddressPools', []) 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) lb_or_ag_id = "{0}/".format(application_gateway.id)
backend_address_pool_id = backend_address_pool[0].get('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') differences.append('load_balancer')
changed = True changed = True
@ -785,6 +823,9 @@ class AzureRMVirtualMachineScaleSet(AzureRMModuleBase):
if self.state == 'present': if self.state == 'present':
if not vmss: if not vmss:
# Create the 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.log("Create virtual machine scale set {0}".format(self.name))
self.results['actions'].append('Created VMSS {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.") self.fail("Parameter error: ssh_public_keys required when disabling SSH password.")
if not self.virtual_network_name: if not self.virtual_network_name:
default_vnet = self.create_default_vnet() self.fail("virtual network name is required")
virtual_network = default_vnet.id
self.virtual_network_name = default_vnet.name
if self.subnet_name: if self.subnet_name:
subnet = self.get_subnet(self.virtual_network_name, self.subnet_name) subnet = self.get_subnet(self.virtual_network_name, self.subnet_name)
@ -877,6 +916,12 @@ class AzureRMVirtualMachineScaleSet(AzureRMModuleBase):
zones=self.zones 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: if self.admin_password:
vmss_resource.virtual_machine_profile.os_profile.admin_password = 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 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: if image_reference is not None:
vmss_resource.virtual_machine_profile.storage_profile.image_reference = image_reference vmss_resource.virtual_machine_profile.storage_profile.image_reference = image_reference
self.log("Update virtual machine with parameters:") self.log("Update virtual machine with parameters:")
@ -1138,6 +1189,23 @@ class AzureRMVirtualMachineScaleSet(AzureRMModuleBase):
name = azure_id_to_dict(id).get('name') name = azure_id_to_dict(id).get('name')
return dict(id=id, name=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(): def main():
AzureRMVirtualMachineScaleSet() AzureRMVirtualMachineScaleSet()

@ -41,11 +41,20 @@ options:
power_state: power_state:
description: description:
- Use this option to change power state of the instance. - Use this option to change power state of the instance.
required: True
choices: choices:
- 'running' - 'running'
- 'stopped' - 'stopped'
- 'deallocated' - '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: state:
description: description:
- State of the VMSS instance. Use C(present) to update an instance and C(absent) to delete an instance. - 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 vmss_name: myVMSS
instance_id: "2" instance_id: "2"
latest_model: yes 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 = ''' RETURN = '''
@ -119,6 +135,12 @@ class AzureRMVirtualMachineScaleSetInstance(AzureRMModuleBase):
type='str', type='str',
choices=['running', 'stopped', 'deallocated'] choices=['running', 'stopped', 'deallocated']
), ),
protect_from_scale_in=dict(
type='bool'
),
protect_from_scale_set_actions=dict(
type='bool'
),
state=dict( state=dict(
type='str', type='str',
default='present', default='present',
@ -136,13 +158,16 @@ class AzureRMVirtualMachineScaleSetInstance(AzureRMModuleBase):
self.latest_model = None self.latest_model = None
self.power_state = None self.power_state = None
self.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) super(AzureRMVirtualMachineScaleSetInstance, self).__init__(self.module_arg_spec, supports_tags=False)
def exec_module(self, **kwargs): def exec_module(self, **kwargs):
for key in self.module_arg_spec: for key in self.module_arg_spec:
setattr(self, key, kwargs[key]) setattr(self, key, kwargs[key])
self.mgmt_client = self.get_mgmt_svc_client(ComputeManagementClient, 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() instances = self.get()
@ -175,6 +200,14 @@ class AzureRMVirtualMachineScaleSetInstance(AzureRMModuleBase):
if not self.check_mode: if not self.check_mode:
self.start(item['instance_id']) self.start(item['instance_id'])
self.results['changed'] = True 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] self.results['instances'] = [{'id': item['id']} for item in instances]
return self.results return self.results
@ -202,8 +235,8 @@ class AzureRMVirtualMachineScaleSetInstance(AzureRMModuleBase):
instance_ids=[instance_id]) instance_ids=[instance_id])
self.get_poller_result(poller) self.get_poller_result(poller)
except CloudError as exc: except CloudError as exc:
self.log("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.name, str(exc))) self.fail("Error applying latest model {0} - {1}".format(self.vmss_name, str(exc)))
def delete(self, instance_id): def delete(self, instance_id):
try: try:
@ -241,6 +274,27 @@ class AzureRMVirtualMachineScaleSetInstance(AzureRMModuleBase):
self.log('Could not deallocate instance of Virtual Machine Scale Set VM.') self.log('Could not deallocate instance of Virtual Machine Scale Set VM.')
self.fail('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): def format_response(self, item):
d = item.as_dict() d = item.as_dict()
iv = self.mgmt_client.virtual_machine_scale_set_vms.get_instance_view(resource_group_name=self.resource_group, 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'), 'tags': d.get('tags'),
'instance_id': d.get('instance_id'), 'instance_id': d.get('instance_id'),
'latest_model': d.get('latest_model_applied'), 'latest_model': d.get('latest_model_applied'),
'power_state': power_state 'power_state': power_state,
'protection_policy': d.get('protection_policy')
} }
return d return d

@ -7,7 +7,7 @@ azure-common==1.1.11
azure-mgmt-authorization==0.51.1 azure-mgmt-authorization==0.51.1
azure-mgmt-batch==5.0.1 azure-mgmt-batch==5.0.1
azure-mgmt-cdn==3.0.0 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-containerinstance==1.4.0
azure-mgmt-containerregistry==2.0.0 azure-mgmt-containerregistry==2.0.0
azure-mgmt-containerservice==4.4.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-keyvault==1.1.0
azure-mgmt-marketplaceordering==0.1.0 azure-mgmt-marketplaceordering==0.1.0
azure-mgmt-monitor==0.5.2 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-nspkg==2.0.0
azure-mgmt-redis==5.0.0 azure-mgmt-redis==5.0.0
azure-mgmt-resource==2.1.0 azure-mgmt-resource==2.1.0
@ -27,8 +27,8 @@ azure-mgmt-trafficmanager==0.50.0
azure-mgmt-web==0.41.0 azure-mgmt-web==0.41.0
azure-nspkg==2.0.0 azure-nspkg==2.0.0
azure-storage==0.35.1 azure-storage==0.35.1
msrest==0.6.1 msrest==0.6.10
msrestazure==0.5.0 msrestazure==0.6.2
azure-keyvault==1.0.0a1 azure-keyvault==1.0.0a1
azure-graphrbac==0.40.0 azure-graphrbac==0.40.0
azure-mgmt-cosmosdb==0.5.2 azure-mgmt-cosmosdb==0.5.2

@ -161,6 +161,9 @@ matrix:
- env: T=azure/2.7/10 - env: T=azure/2.7/10
- env: T=azure/3.6/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/2.7/1
- env: T=vcenter/3.6/1 - env: T=vcenter/3.6/1

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

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

@ -7,7 +7,7 @@ azure-common==1.1.11
azure-mgmt-authorization==0.51.1 azure-mgmt-authorization==0.51.1
azure-mgmt-batch==5.0.1 azure-mgmt-batch==5.0.1
azure-mgmt-cdn==3.0.0 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-containerinstance==1.4.0
azure-mgmt-containerregistry==2.0.0 azure-mgmt-containerregistry==2.0.0
azure-mgmt-containerservice==4.4.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-keyvault==1.1.0
azure-mgmt-marketplaceordering==0.1.0 azure-mgmt-marketplaceordering==0.1.0
azure-mgmt-monitor==0.5.2 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-nspkg==2.0.0
azure-mgmt-redis==5.0.0 azure-mgmt-redis==5.0.0
azure-mgmt-resource==2.1.0 azure-mgmt-resource==2.1.0
@ -27,8 +27,8 @@ azure-mgmt-trafficmanager==0.50.0
azure-mgmt-web==0.41.0 azure-mgmt-web==0.41.0
azure-nspkg==2.0.0 azure-nspkg==2.0.0
azure-storage==0.35.1 azure-storage==0.35.1
msrest==0.6.1 msrest==0.6.10
msrestazure==0.5.0 msrestazure==0.6.2
azure-keyvault==1.0.0a1 azure-keyvault==1.0.0a1
azure-graphrbac==0.40.0 azure-graphrbac==0.40.0
azure-mgmt-cosmosdb==0.5.2 azure-mgmt-cosmosdb==0.5.2

Loading…
Cancel
Save