From 2eaf5ee206359368cf18187d4e926f8032fb6dc4 Mon Sep 17 00:00:00 2001 From: Vincent Viallet Date: Fri, 21 Jun 2013 17:01:29 +0800 Subject: [PATCH] Fix last bugs, complete all tests. --- library/cloud/linode | 162 +++++++++++++++++++++++++------------------ 1 file changed, 96 insertions(+), 66 deletions(-) diff --git a/library/cloud/linode b/library/cloud/linode index 01e2aeadc98..11ab11a4b50 100644 --- a/library/cloud/linode +++ b/library/cloud/linode @@ -1,4 +1,4 @@ -#!/usr/bin/env python -tt +#!/usr/bin/python # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify @@ -33,11 +33,19 @@ options: default: null name: description: - - Name to give the instance + - Name to give the instance (alphanumeric, dashes, underscore) + - To keep sanity on the Linode Web Console, name is prepended with LinodeID_ default: null - flavor: + type: string + linode_id: description: - - flavor to use for the instance (Linode plan) + - Unique ID of a linode server + aliases: lid + default: null + type: integer + plan: + description: + - plan to use for the instance (Linode plan) default: null type: integer payment_term: @@ -61,14 +69,14 @@ options: - swap size in MB default: 512 type: integer - image: + distribution: description: - - image to use for the instance (Linode Distribution) + - distribution to use for the instance (Linode Distribution) default: null type: integer - region: + datacenter: description: - - Region to create an instance in (Linode Datacenter) + - datacenter to create an instance in (Linode Datacenter) default: null type: integer wait: @@ -92,9 +100,9 @@ EXAMPLES = ''' module: linode api_key: 'longStringFromLinodeApi' name: linode-test1 - flavor: 1 - region: 2 - image: 99 + plan: 1 + datacenter: 2 + distribution: 99 password: 'superSecureRootPassword' ssh_pub_key: 'ssh-rsa qwerty' swap: 768 @@ -108,9 +116,9 @@ EXAMPLES = ''' api_key: 'longStringFromLinodeApi' name: linode-test1 linode_id: 12345678 - flavor: 1 - region: 2 - image: 99 + plan: 1 + datacenter: 2 + distribution: 99 password: 'superSecureRootPassword' ssh_pub_key: 'ssh-rsa qwerty' swap: 768 @@ -148,6 +156,9 @@ import time import os try: + # linode module raise warning due to ssl - silently ignore them ... + import warnings + warnings.simplefilter("ignore") from linode import api as linode_api except ImportError: print("failed=True msg='linode-python required for this module'") @@ -181,7 +192,7 @@ def getInstanceDetails(api, server): # Populate with ips for ip in api.linode_ip_list(LinodeId=server['LINODEID']): - if ip['ISPUBLIC'] and not instance['ipv4']: + if ip['ISPUBLIC'] and 'ipv4' not in instance: instance['ipv4'] = ip['IPADDRESS'] instance['fqdn'] = ip['RDNS_NAME'] if ip['ISPUBLIC']: @@ -194,7 +205,7 @@ def getInstanceDetails(api, server): 'ip_id': ip['IPADDRESSID']}) return instance -def linodeServers(module, api, state, name, flavor, image, region, linode_id, +def linodeServers(module, api, state, name, plan, distribution, datacenter, linode_id, payment_term, password, ssh_pub_key, swap, wait, wait_timeout): instances = [] changed = False @@ -209,12 +220,15 @@ def linodeServers(module, api, state, name, flavor, image, region, linode_id, # For the moment we only consider linode_id as criteria for match # Later we can use more (size, name, etc.) and update existing servers = api.linode_list(LinodeId=linode_id) - disks = api.linode_disk_list(LinodeId=linode_id) - configs = api.linode_config_list(LinodeId=linode_id) + # Attempt to fetch details about disks and configs only if servers are + # found with linode_id + if servers: + disks = api.linode_disk_list(LinodeId=linode_id) + configs = api.linode_config_list(LinodeId=linode_id) # Act on the state if state in ('active', 'present', 'started'): - # TODO: validate all the flavor / image / region are valid + # TODO: validate all the plan / distribution / datacenter are valid # Multi step process/validation: # - need linode_id (entity) @@ -225,16 +239,22 @@ def linodeServers(module, api, state, name, flavor, image, region, linode_id, if not servers: new_server = True # TODO - improve - for arg in (name, flavor, image, region): - if not arg: - module.fail_json(msg='%s is required for active state' % arg) + if not name: + module.fail_json(msg='%s is required for active state' % 'name') + if not plan: + module.fail_json(msg='%s is required for active state' % 'plan') + if not distribution: + module.fail_json(msg='%s is required for active state' % 'distribution') + if not datacenter: + module.fail_json(msg='%s is required for active state' % 'datacenter') + # Create linode entity try: - res = api.linode_create(DatacenterID=region, PlanID=flavor, + res = api.linode_create(DatacenterID=datacenter, PlanID=plan, PaymentTerm=payment_term) linode_id = res['LinodeID'] # Update linode Label to match name - api.linode_update(LinodeId=linode_id, Label=name) + api.linode_update(LinodeId=linode_id, Label='%s_%s' % (linode_id, name)) # Save server servers = api.linode_list(LinodeId=linode_id); except Exception, e: @@ -243,9 +263,13 @@ def linodeServers(module, api, state, name, flavor, image, region, linode_id, if not disks: new_server = True # TODO - improve - for arg in (linode_id, name, image): - if not arg: - module.fail_json(msg='%s is required for active state' % arg) + if not name: + module.fail_json(msg='%s is required for active state' % 'name') + if not linode_id: + module.fail_json(msg='%s is required for active state' % 'linode_id') + if not distribution: + module.fail_json(msg='%s is required for active state' % 'distribution') + # Create disks (1 from distrib, 1 for SWAP) try: if not password: @@ -257,18 +281,18 @@ def linodeServers(module, api, state, name, flavor, image, region, linode_id, size = servers[0]['TOTALHD'] - swap if ssh_pub_key: res = api.linode_disk_createfromdistribution( - LinodeId=linode_id, DistributionID=image, + LinodeId=linode_id, DistributionID=distribution, rootPass=password, rootSSHKey=ssh_pub_key, - Label='%s data disk' % name, Size=size) + Label='%s data disk (lid: %s)' % (name, linode_id), Size=size) else: res = api.linode_disk_createfromdistribution( - LinodeId=linode_id, DistributionID=image, - rootPass=password, Label='%s data disk' % name, - Size=size) + LinodeId=linode_id, DistributionID=distribution, rootPass=password, + Label='%s data disk (lid: %s)' % (name, linode_id), Size=size) jobs.append(res['JobID']) # Create SWAP disk res = api.linode_disk_create(LinodeId=linode_id, Type='swap', - Label='%s swap disk' % name, Size=swap) + Label='%s swap disk (lid: %s)' % (name, linode_id), + Size=swap) jobs.append(res['JobID']) except Exception, e: # TODO: destroy linode ? @@ -277,12 +301,16 @@ def linodeServers(module, api, state, name, flavor, image, region, linode_id, if not configs: new_server = True # TODO - improve - for arg in (linode_id, name, image): - if not arg: - module.fail_json(msg='%s is required for active state' % arg) + if not name: + module.fail_json(msg='%s is required for active state' % 'name') + if not linode_id: + module.fail_json(msg='%s is required for active state' % 'linode_id') + if not distribution: + module.fail_json(msg='%s is required for active state' % 'distribution') + # Check architecture for distrib in api.avail_distributions(): - if distrib['DISTRIBUTIONID'] != image: + if distrib['DISTRIBUTIONID'] != distribution: continue arch = '32' if distrib['IS64BIT']: @@ -298,11 +326,11 @@ def linodeServers(module, api, state, name, flavor, image, region, linode_id, # Get disk list disks_id = [] - for disk in api.linode_disk_list(): + for disk in api.linode_disk_list(LinodeId=linode_id): if disk['TYPE'] == 'ext3': - disks_id.insert(0, disk['DISKID']) + disks_id.insert(0, str(disk['DISKID'])) continue - disks_id.append(disk['DISKID']) + disks_id.append(str(disk['DISKID'])) # Trick to get the 9 items in the list while len(disks_id) < 9: disks_id.append('') @@ -310,9 +338,8 @@ def linodeServers(module, api, state, name, flavor, image, region, linode_id, # Create config try: - res = api.linode_config_create(LinodeId=linode_id, KernelId=kernel_id, - Disklist=disks_list, Label='%s config' % name) - config_id = res['ConfigId'] + api.linode_config_create(LinodeId=linode_id, KernelId=kernel_id, + Disklist=disks_list, Label='%s config' % name) configs = api.linode_config_list(LinodeId=linode_id) except Exception, e: module.fail_json(msg = '%s' % e.value[0]['ERRORMESSAGE']) @@ -340,12 +367,12 @@ def linodeServers(module, api, state, name, flavor, image, region, linode_id, time.sleep(5) if wait and wait_timeout <= time.time(): # waiting took too long - module.fail_json(msg = 'Timeout waiting on %s - %s' % + module.fail_json(msg = 'Timeout waiting on %s (lid: %s)' % (server['LABEL'], server['LINODEID'])) # Get a fresh copy of the server details server = api.linode_list(LinodeId=server['LINODEID'])[0] if server['STATUS'] == -2: - module.fail_json(msg = '%s - %s failed to boot' % + module.fail_json(msg = '%s (lid: %s) failed to boot' % (server['LABEL'], server['LINODEID'])) # From now on we know the task is a success # Build instance report @@ -362,12 +389,13 @@ def linodeServers(module, api, state, name, flavor, image, region, linode_id, instance['password'] = password instances.append(instance) elif state in ('stopped'): - for arg in (linode_id, name): - if not arg: - module.fail_json(msg='%s is required for stopped state' % arg) + if not name: + module.fail_json(msg='%s is required for stopped state' % 'name') + if not linode_id: + module.fail_json(msg='%s is required for stopped state' % 'linode_id') + if not servers: - module.fail_json(msg = 'Server %s (%s) not found' % - (name, linode_id)) + module.fail_json(msg = 'Server %s (lid: %s) not found' % (name, linode_id)) for server in servers: instance = getInstanceDetails(api, server) if server['STATUS'] != 2: @@ -381,12 +409,13 @@ def linodeServers(module, api, state, name, flavor, image, region, linode_id, instance['status'] = 'Stopped' instances.append(instance) elif state in ('restarted'): - for arg in ('linode_id', 'name'): - if not arg: - module.fail_json(msg='%s is required for restarted state' % arg) + if not name: + module.fail_json(msg='%s is required for restarted state' % 'name') + if not linode_id: + module.fail_json(msg='%s is required for restarted state' % 'linode_id') + if not servers: - module.fail_json(msg = 'Server %s (%s) not found' % - (name, linode_id)) + module.fail_json(msg = 'Server %s (lid: %s) not found' % (name, linode_id)) for server in servers: instance = getInstanceDetails(api, server) try: @@ -415,18 +444,19 @@ def linodeServers(module, api, state, name, flavor, image, region, linode_id, def main(): module = AnsibleModule( argument_spec = dict( - state = dict(default='present', choices=['active', 'present', 'started' - 'deleted', 'absent', 'stopped']), + state = dict(default='present', choices=['active', 'present', 'started', + 'deleted', 'absent', 'stopped', + 'restarted']), api_key = dict(), name = dict(type='str'), - flavor = dict(type='int'), - image = dict(type='int'), - region = dict(type='int'), - linode_id = dict(type='int'), + plan = dict(type='int'), + distribution = dict(type='int'), + datacenter = dict(type='int'), + linode_id = dict(type='int', aliases=['lid']), payment_term = dict(default=1, choices=[1, 12, 24]), password = dict(type='str'), ssh_pub_key = dict(type='str'), - swap = dict(type='int', default=512) + swap = dict(type='int', default=512), wait = dict(type='bool', choices=BOOLEANS, default=True), wait_timeout = dict(default=500), ) @@ -435,9 +465,9 @@ def main(): state = module.params.get('state') api_key = module.params.get('api_key') name = module.params.get('name') - flavor = module.params.get('flavor') - image = module.params.get('image') - region = module.params.get('region') + plan = module.params.get('plan') + distribution = module.params.get('distribution') + datacenter = module.params.get('datacenter') linode_id = module.params.get('linode_id') payment_term = module.params.get('payment_term') password = module.params.get('password') @@ -460,7 +490,7 @@ def main(): except Exception, e: module.fail_json(msg = '%s' % e.value[0]['ERRORMESSAGE']) - linodeServers(module, api, state, name, flavor, image, region, linode_id, + linodeServers(module, api, state, name, plan, distribution, datacenter, linode_id, payment_term, password, ssh_pub_key, swap, wait, wait_timeout) # this is magic, see lib/ansible/module_common.py