def main(): argument_spec = ovirt_facts_full_argument_spec( pattern=dict(default='', required=False), ) module = AnsibleModule(argument_spec) if module._name == 'ovirt_clusters_facts': module.deprecate("The 'ovirt_clusters_facts' module is being renamed 'ovirt_cluster_facts'", version=2.8) check_sdk(module) try: auth = module.params.pop('auth') connection = create_connection(auth) clusters_service = connection.system_service().clusters_service() clusters = clusters_service.list(search=module.params['pattern']) module.exit_json( changed=False, ansible_facts=dict( ovirt_clusters=[ get_dict_of_struct( struct=c, connection=connection, fetch_nested=module.params.get('fetch_nested'), attributes=module.params.get('nested_attributes'), ) for c in clusters ], ), ) except Exception as e: module.fail_json(msg=str(e), exception=traceback.format_exc()) finally: connection.close(logout=auth.get('token') is None)
def main(): """ Main entry point for Ansible module execution """ argument_spec = dict( hostname=dict(), vrf=dict(type='str', default='default'), domain_name=dict(), domain_search=dict(type='list'), name_servers=dict(type='list'), lookup_source=dict(), lookup_enabled=dict(type='bool', default=True), state=dict(choices=['present', 'absent'], default='present') ) argument_spec.update(iosxr_argument_spec) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) config_object = None if is_cliconf(module): module.deprecate(msg="cli support for 'iosxr_system' is deprecated. Use transport netconf instead", version="4 releases from v2.5") config_object = CliConfiguration(module) elif is_netconf(module): config_object = NCConfiguration(module) result = None if config_object: result = config_object.run() module.exit_json(**result)
def main(): """ main entry point for module execution """ element_spec = dict( name=dict(type='str'), description=dict(type='str'), speed=dict(choices=['10', '100', '1000']), mtu=dict(), duplex=dict(choices=['full', 'half']), enabled=dict(default=True, type='bool'), active=dict(default='active', type='str', choices=['active', 'preconfigure']), tx_rate=dict(), rx_rate=dict(), delay=dict(default=10, type='int'), state=dict(default='present', choices=['present', 'absent', 'up', 'down']) ) aggregate_spec = deepcopy(element_spec) aggregate_spec['name'] = dict(required=True) # remove default in aggregate spec, to handle common arguments remove_default_spec(aggregate_spec) argument_spec = dict( aggregate=dict(type='list', elements='dict', options=aggregate_spec), ) argument_spec.update(element_spec) argument_spec.update(iosxr_argument_spec) required_one_of = [['name', 'aggregate']] mutually_exclusive = [['name', 'aggregate']] module = AnsibleModule(argument_spec=argument_spec, required_one_of=required_one_of, mutually_exclusive=mutually_exclusive, supports_check_mode=True) config_object = None if is_cliconf(module): module.deprecate("cli support for 'iosxr_interface' is deprecated. Use transport netconf instead", version='4 releases from v2.5') config_object = CliConfiguration(module) elif is_netconf(module): if module.params['active'] == 'preconfigure': module.fail_json(msg="Physical interface pre-configuration is not supported with transport 'netconf'") config_object = NCConfiguration(module) result = {} if config_object: result = config_object.run() module.exit_json(**result)
def main(): module = AnsibleModule( argument_spec={}, supports_check_mode=True, ) if module._name == 'ec2_facts': module.deprecate("The 'ec2_facts' module is being renamed 'ec2_metadata_facts'", version=2.7) ec2_metadata_facts = Ec2Metadata(module).run() ec2_metadata_facts_result = dict(changed=False, ansible_facts=ec2_metadata_facts) module.exit_json(**ec2_metadata_facts_result)
def main(): argument_spec = ovirt_full_argument_spec( state=dict( choices=['present', 'absent'], default='present', ), name=dict(default=None, required=True), description=dict(default=None), local=dict(type='bool'), compatibility_version=dict(default=None), quota_mode=dict(choices=['disabled', 'audit', 'enabled']), comment=dict(default=None), mac_pool=dict(default=None), force=dict(default=None, type='bool'), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) if module._name == 'ovirt_datacenters': module.deprecate("The 'ovirt_datacenters' module is being renamed 'ovirt_datacenter'", version=2.8) check_sdk(module) check_params(module) try: auth = module.params.pop('auth') connection = create_connection(auth) data_centers_service = connection.system_service().data_centers_service() clusters_module = DatacentersModule( connection=connection, module=module, service=data_centers_service, ) state = module.params['state'] if state == 'present': ret = clusters_module.create() elif state == 'absent': ret = clusters_module.remove(force=module.params['force']) module.exit_json(**ret) except Exception as e: module.fail_json(msg=str(e), exception=traceback.format_exc()) finally: connection.close(logout=auth.get('token') is None)
def main(): argument_spec = ovirt_full_argument_spec( state=dict( choices=['present', 'absent'], default='present', ), name=dict(required=True), authz_name=dict(required=True, aliases=['domain']), namespace=dict(default=None), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) if module._name == 'ovirt_groups': module.deprecate("The 'ovirt_groups' module is being renamed 'ovirt_group'", version=2.8) check_sdk(module) check_params(module) try: auth = module.params.pop('auth') connection = create_connection(auth) groups_service = connection.system_service().groups_service() groups_module = GroupsModule( connection=connection, module=module, service=groups_service, ) group = _group(connection, module) state = module.params['state'] if state == 'present': ret = groups_module.create(entity=group) elif state == 'absent': ret = groups_module.remove(entity=group) module.exit_json(**ret) except Exception as e: module.fail_json(msg=str(e), exception=traceback.format_exc()) finally: connection.close(logout=auth.get('token') is None)
def main(): module = AnsibleModule( argument_spec=dict( path=dict(type='path', required=True), passphrase=dict(type='str', no_log=True), return_private_key_data=dict(type='bool', default=False), select_crypto_backend=dict( type='str', default='auto', choices=['auto', 'cryptography', 'pyopenssl']), ), supports_check_mode=True, ) try: base_dir = os.path.dirname(module.params['path']) or '.' if not os.path.isdir(base_dir): module.fail_json( name=base_dir, msg= 'The directory %s does not exist or the file is not a directory' % base_dir) backend = module.params['select_crypto_backend'] if backend == 'auto': # Detect what backend we can use can_use_cryptography = CRYPTOGRAPHY_FOUND and CRYPTOGRAPHY_VERSION >= LooseVersion( MINIMAL_CRYPTOGRAPHY_VERSION) can_use_pyopenssl = PYOPENSSL_FOUND and PYOPENSSL_VERSION >= LooseVersion( MINIMAL_PYOPENSSL_VERSION) # If cryptography is available we'll use it if can_use_cryptography: backend = 'cryptography' elif can_use_pyopenssl: backend = 'pyopenssl' # Fail if no backend has been found if backend == 'auto': module.fail_json( msg=("Can't detect any of the required Python libraries " "cryptography (>= {0}) or PyOpenSSL (>= {1})" ).format(MINIMAL_CRYPTOGRAPHY_VERSION, MINIMAL_PYOPENSSL_VERSION)) if backend == 'pyopenssl': if not PYOPENSSL_FOUND: module.fail_json(msg=missing_required_lib( 'pyOpenSSL >= {0}'.format(MINIMAL_PYOPENSSL_VERSION)), exception=PYOPENSSL_IMP_ERR) module.deprecate( 'The module is using the PyOpenSSL backend. This backend has been deprecated', version='2.13') privatekey = PrivateKeyInfoPyOpenSSL(module) elif backend == 'cryptography': if not CRYPTOGRAPHY_FOUND: module.fail_json(msg=missing_required_lib( 'cryptography >= {0}'.format( MINIMAL_CRYPTOGRAPHY_VERSION)), exception=CRYPTOGRAPHY_IMP_ERR) privatekey = PrivateKeyInfoCryptography(module) result = privatekey.get_info() module.exit_json(**result) except crypto_utils.OpenSSLObjectError as exc: module.fail_json(msg=to_native(exc))
def main(): argument_spec = ovirt_full_argument_spec( state=dict( choices=['present', 'absent'], default='present', ), name=dict(required=True), data_center=dict(required=True), description=dict(default=None), cluster_threshold=dict(default=None, type='int', aliases=['cluster_soft_limit']), cluster_grace=dict(default=None, type='int', aliases=['cluster_hard_limit']), storage_threshold=dict(default=None, type='int', aliases=['storage_soft_limit']), storage_grace=dict(default=None, type='int', aliases=['storage_hard_limit']), clusters=dict(default=[], type='list'), storages=dict(default=[], type='list'), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) if module._name == 'ovirt_quotas': module.deprecate( "The 'ovirt_quotas' module is being renamed 'ovirt_quota'", version=2.8) check_sdk(module) try: auth = module.params.pop('auth') connection = create_connection(auth) datacenters_service = connection.system_service().data_centers_service( ) dc_name = module.params['data_center'] dc_id = getattr(search_by_name(datacenters_service, dc_name), 'id', None) if dc_id is None: raise Exception("Datacenter '%s' was not found." % dc_name) quotas_service = datacenters_service.service(dc_id).quotas_service() quotas_module = QuotasModule( connection=connection, module=module, service=quotas_service, ) state = module.params['state'] if state == 'present': ret = quotas_module.create() # Manage cluster limits: cl_limit_service = quotas_service.service( ret['id']).quota_cluster_limits_service() for cluster in module.params.get('clusters'): cl_limit_service.add(limit=otypes.QuotaClusterLimit( memory_limit=float(cluster.get('memory')), vcpu_limit=cluster.get('cpu'), cluster=search_by_name( connection.system_service().clusters_service(), cluster.get('name')), ), ) # Manage storage limits: sd_limit_service = quotas_service.service( ret['id']).quota_storage_limits_service() for storage in module.params.get('storages'): sd_limit_service.add(limit=otypes.QuotaStorageLimit( limit=storage.get('size'), storage_domain=search_by_name( connection.system_service().storage_domains_service(), storage.get('name')), )) elif state == 'absent': ret = quotas_module.remove() module.exit_json(**ret) except Exception as e: module.fail_json(msg=str(e), exception=traceback.format_exc()) finally: connection.close(logout=auth.get('token') is None)
def main(): """ main entry point for module execution """ backup_spec = dict(filename=dict(), dir_path=dict(type='path')) argument_spec = dict( content=dict(aliases=['xml']), target=dict(choices=['auto', 'candidate', 'running'], default='auto', aliases=['datastore']), source_datastore=dict(aliases=['source']), format=dict(choices=['xml', 'text'], default='xml'), lock=dict(choices=['never', 'always', 'if-supported'], default='always'), default_operation=dict(choices=['merge', 'replace', 'none']), confirm=dict(type='int', default=0), confirm_commit=dict(type='bool', default=False), error_option=dict(choices=[ 'stop-on-error', 'continue-on-error', 'rollback-on-error' ], default='stop-on-error'), backup=dict(type='bool', default=False), backup_options=dict(type='dict', options=backup_spec), save=dict(type='bool', default=False), delete=dict(type='bool', default=False), commit=dict(type='bool', default=True), validate=dict(type='bool', default=False), get_filter=dict(), ) # deprecated options netconf_top_spec = { 'src': dict(type='path', removed_in_version=2.11), 'host': dict(removed_in_version=2.11), 'port': dict(removed_in_version=2.11, type='int', default=830), 'username': dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME']), removed_in_version=2.11, no_log=True), 'password': dict(fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD']), removed_in_version=2.11, no_log=True), 'ssh_keyfile': dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), removed_in_version=2.11, type='path'), 'hostkey_verify': dict(removed_in_version=2.11, type='bool', default=True), 'look_for_keys': dict(removed_in_version=2.11, type='bool', default=True), 'timeout': dict(removed_in_version=2.11, type='int', default=10), } argument_spec.update(netconf_top_spec) mutually_exclusive = [('content', 'src', 'source', 'delete', 'confirm_commit')] required_one_of = [('content', 'src', 'source', 'delete', 'confirm_commit') ] module = AnsibleModule(argument_spec=argument_spec, required_one_of=required_one_of, mutually_exclusive=mutually_exclusive, supports_check_mode=True) if module.params['src']: module.deprecate( msg= "argument 'src' has been deprecated. Use file lookup plugin instead to read file contents.", version="2.11") config = module.params['content'] or module.params['src'] target = module.params['target'] lock = module.params['lock'] source = module.params['source_datastore'] delete = module.params['delete'] confirm_commit = module.params['confirm_commit'] confirm = module.params['confirm'] validate = module.params['validate'] save = module.params['save'] filter = module.params['get_filter'] filter_type = get_filter_type(filter) conn = Connection(module._socket_path) capabilities = get_capabilities(module) operations = capabilities['device_operations'] supports_commit = operations.get('supports_commit', False) supports_writable_running = operations.get('supports_writable_running', False) supports_startup = operations.get('supports_startup', False) # identify target datastore if target == 'candidate' and not supports_commit: module.fail_json( msg=':candidate is not supported by this netconf server') elif target == 'running' and not supports_writable_running: module.fail_json( msg=':writable-running is not supported by this netconf server') elif target == 'auto': if supports_commit: target = 'candidate' elif supports_writable_running: target = 'running' else: module.fail_json( msg= 'neither :candidate nor :writable-running are supported by this netconf server' ) # Netconf server capability validation against input options if save and not supports_startup: module.fail_json( msg= 'cannot copy <%s/> to <startup/>, while :startup is not supported' % target) if confirm_commit and not operations.get('supports_confirm_commit', False): module.fail_json( msg='confirm commit is not supported by Netconf server') if (confirm > 0) and not operations.get('supports_confirm_commit', False): module.fail_json( msg= 'confirm commit is not supported by this netconf server, given confirm timeout: %d' % confirm) if validate and not operations.get('supports_validate', False): module.fail_json( msg='validate is not supported by this netconf server') if filter_type == 'xpath' and not operations.get('supports_xpath', False): module.fail_json( msg= "filter value '%s' of type xpath is not supported on this device" % filter) filter_spec = (filter_type, filter) if filter_type else None if lock == 'never': execute_lock = False elif target in operations.get('lock_datastore', []): # lock is requested (always/if-support) and supported => lets do it execute_lock = True else: # lock is requested (always/if-supported) but not supported => issue warning module.warn( "lock operation on '%s' source is not supported on this device" % target) execute_lock = (lock == 'always') result = { 'changed': False, 'server_capabilities': capabilities.get('server_capabilities', []) } before = None after = None locked = False try: if module.params['backup']: response = get_config(module, target, filter_spec, lock=execute_lock) before = to_text(tostring(response), errors='surrogate_then_replace').strip() result['__backup__'] = before.strip() if validate: conn.validate(target) if source: if not module.check_mode: conn.copy(source, target) result['changed'] = True elif delete: if not module.check_mode: conn.delete(target) result['changed'] = True elif confirm_commit: if not module.check_mode: conn.commit() result['changed'] = True elif config: if module.check_mode and not supports_commit: module.warn( "check mode not supported as Netconf server doesn't support candidate capability" ) result['changed'] = True module.exit_json(**result) if execute_lock: conn.lock(target=target) locked = True if before is None: before = to_text(conn.get_config(source=target, filter=filter_spec), errors='surrogate_then_replace').strip() kwargs = { 'config': config, 'target': target, 'default_operation': module.params['default_operation'], 'error_option': module.params['error_option'], 'format': module.params['format'], } conn.edit_config(**kwargs) if supports_commit and module.params['commit']: after = to_text(conn.get_config(source='candidate', filter=filter_spec), errors='surrogate_then_replace').strip() if not module.check_mode: confirm_timeout = confirm if confirm > 0 else None confirmed_commit = True if confirm_timeout else False conn.commit(confirmed=confirmed_commit, timeout=confirm_timeout) else: conn.discard_changes() if after is None: after = to_text(conn.get_config(source='running', filter=filter_spec), errors='surrogate_then_replace').strip() sanitized_before = sanitize_xml(before) sanitized_after = sanitize_xml(after) if sanitized_before != sanitized_after: result['changed'] = True if result['changed']: if save and not module.check_mode: conn.copy_config(target, 'startup') if module._diff: result['diff'] = { 'before': sanitized_before, 'after': sanitized_after } except ConnectionError as e: module.fail_json( msg=to_text(e, errors='surrogate_then_replace').strip()) finally: if locked: conn.unlock(target=target) module.exit_json(**result)
def main(): helper = get_connection( vsys=True, rulebase=True, with_classic_provider_spec=True, panorama_error='Panorama is not supported', argument_spec=dict( rule_type=dict(default='security', choices=['security', 'nat']), source_zone=dict(), source_ip=dict(required=True), source_port=dict(type='int'), source_user=dict(), to_interface=dict(), destination_zone=dict(), destination_ip=dict(required=True), destination_port=dict(required=True, type='int'), application=dict(), protocol=dict(required=True, type='int'), category=dict(), # TODO(gfreeman) - Remove this in the next role release. vsys_id=dict(), ), ) module = AnsibleModule( argument_spec=helper.argument_spec, supports_check_mode=False, required_one_of=helper.required_one_of, ) # TODO(gfreeman) - Remove this in the next role release. if not HAS_LIB: module.fail_json(msg='Missing xmltodict library') if module.params['vsys_id'] is not None: module.fail_json(msg='Param "vsys_id" is removed; use vsys') parent = helper.get_pandevice_parent(module) params = ( ('application', 'application', [ 'security', ]), ('category', 'category', [ 'security', ]), ('destination_ip', 'destination', ['security', 'nat']), ('destination_port', 'destination-port', ['security', 'nat']), ('source_zone', 'from', ['security', 'nat']), ('protocol', 'protocol', ['security', 'nat']), ('source_ip', 'source', ['security', 'nat']), ('source_user', 'source-user', [ 'security', ]), ('destination_zone', 'to', ['security', 'nat']), ('to_interface', 'to-interface', [ 'nat', ]), ) cmd = [] rtype = module.params['rule_type'] if rtype == 'security': cmd.append('test security-policy-match') listing = SecurityRule.refreshall(parent) else: cmd.append('test nat-policy-match') listing = NatRule.refreshall(parent) for ansible_param, cmd_param, rule_types in params: if rtype not in rule_types or module.params[ansible_param] is None: continue cmd.append('{0} "{1}"'.format(cmd_param, module.params[ansible_param])) # Submit the op command with the appropriate test string test_string = ' '.join(cmd) try: response = helper.device.op(cmd=test_string, vsys=parent.vsys) except PanDeviceError as e: module.fail_json(msg='Failed "{0}": {1}'.format(test_string, e)) elm = response.find('./result/rules/entry') if elm is not None: try: rule_name = elm.attrib['name'] except KeyError: rule_name = elm.text else: module.exit_json(msg='No matching {0} rule.'.format(rtype)) for x in listing: if x.name != rule_name: continue module.deprecate( 'The "stdout_lines" output is deprecated; use "rule" instead', '2.12') module.exit_json( stdout_lines=json.dumps(xmltodict.parse(x.element_str()), indent=2), msg='Rule matched', rule=x.about(), ) module.fail_json( msg='Matched "{0}" with "{1}", but wasn\'t in rulebase'.format( rule_name, test_string))
def main(): argument_spec = ovirt_full_argument_spec( state=dict( choices=['present', 'absent'], default='present', ), cluster=dict(default=None, required=True), name=dict(default=None, required=True), description=dict(default=None), vm_enforcing=dict(default=None, type='bool'), vm_rule=dict(default=None, choices=['positive', 'negative', 'disabled']), host_enforcing=dict(default=None, type='bool'), host_rule=dict(default=None, choices=['positive', 'negative']), vms=dict(default=None, type='list'), hosts=dict(default=None, type='list'), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) if module._name == 'ovirt_affinity_groups': module.deprecate("The 'ovirt_affinity_groups' module is being renamed 'ovirt_affinity_group'", version=2.8) check_sdk(module) try: auth = module.params.pop('auth') connection = create_connection(auth) # Check if unsupported parameters were passed: supported_41 = ('host_enforcing', 'host_rule', 'hosts') if not check_support( version='4.1', connection=connection, module=module, params=supported_41, ): module.fail_json( msg='Following parameters are supported since 4.1: {params}'.format( params=supported_41, ) ) clusters_service = connection.system_service().clusters_service() vms_service = connection.system_service().vms_service() hosts_service = connection.system_service().hosts_service() cluster_name = module.params['cluster'] cluster = search_by_name(clusters_service, cluster_name) if cluster is None: raise Exception("Cluster '%s' was not found." % cluster_name) cluster_service = clusters_service.cluster_service(cluster.id) affinity_groups_service = cluster_service.affinity_groups_service() # Fetch VM ids which should be assigned to affinity group: vm_ids = sorted([ get_id_by_name(vms_service, vm_name) for vm_name in module.params['vms'] ]) if module.params['vms'] is not None else None # Fetch host ids which should be assigned to affinity group: host_ids = sorted([ get_id_by_name(hosts_service, host_name) for host_name in module.params['hosts'] ]) if module.params['hosts'] is not None else None affinity_groups_module = AffinityGroupsModule( connection=connection, module=module, service=affinity_groups_service, vm_ids=vm_ids, host_ids=host_ids, ) state = module.params['state'] if state == 'present': ret = affinity_groups_module.create() elif state == 'absent': ret = affinity_groups_module.remove() module.exit_json(**ret) except Exception as e: module.fail_json(msg=str(e), exception=traceback.format_exc()) finally: connection.close(logout=auth.get('token') is None)
def main(): argument_spec = ovirt_full_argument_spec( state=dict( choices=['present', 'absent', 'attached', 'detached', 'exported'], default='present' ), id=dict(default=None), name=dict(default=None, aliases=['alias']), description=dict(default=None), vm_name=dict(default=None), vm_id=dict(default=None), size=dict(default=None), interface=dict(default=None,), storage_domain=dict(default=None), storage_domains=dict(default=None, type='list'), profile=dict(default=None), quota_id=dict(default=None), format=dict(default='cow', choices=['raw', 'cow']), sparse=dict(default=None, type='bool'), bootable=dict(default=None, type='bool'), shareable=dict(default=None, type='bool'), logical_unit=dict(default=None, type='dict'), download_image_path=dict(default=None), upload_image_path=dict(default=None, aliases=['image_path']), force=dict(default=False, type='bool'), sparsify=dict(default=None, type='bool'), openstack_volume_type=dict(default=None), image_provider=dict(default=None), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) if module._name == 'ovirt_disks': module.deprecate("The 'ovirt_disks' module is being renamed 'ovirt_disk'", version=2.8) check_sdk(module) check_params(module) try: disk = None state = module.params['state'] auth = module.params.get('auth') connection = create_connection(auth) disks_service = connection.system_service().disks_service() disks_module = DisksModule( connection=connection, module=module, service=disks_service, ) lun = module.params.get('logical_unit') if lun: disk = _search_by_lun(disks_service, lun.get('id')) ret = None # First take care of creating the VM, if needed: if state in ('present', 'detached', 'attached'): ret = disks_module.create( entity=disk, result_state=otypes.DiskStatus.OK if lun is None else None, fail_condition=lambda d: d.status == otypes.DiskStatus.ILLEGAL if lun is None else False, ) is_new_disk = ret['changed'] ret['changed'] = ret['changed'] or disks_module.update_storage_domains(ret['id']) # We need to pass ID to the module, so in case we want detach/attach disk # we have this ID specified to attach/detach method: module.params['id'] = ret['id'] if disk is None else disk.id # Upload disk image in case it's new disk or force parameter is passed: if module.params['upload_image_path'] and (is_new_disk or module.params['force']): uploaded = upload_disk_image(connection, module) ret['changed'] = ret['changed'] or uploaded # Download disk image in case it's file don't exist or force parameter is passed: if ( module.params['download_image_path'] and (not os.path.isfile(module.params['download_image_path']) or module.params['force']) ): downloaded = download_disk_image(connection, module) ret['changed'] = ret['changed'] or downloaded # Disk sparsify, only if disk is of image type: disk = disks_service.disk_service(module.params['id']).get() if disk.storage_type == otypes.DiskStorageType.IMAGE: ret = disks_module.action( action='sparsify', action_condition=lambda d: module.params['sparsify'], wait_condition=lambda d: d.status == otypes.DiskStatus.OK, ) # Export disk as image to glance domain elif state == 'exported': disk = disks_module.search_entity() if disk is None: module.fail_json( msg="Can not export given disk '%s', it doesn't exist" % module.params.get('name') or module.params.get('id') ) if disk.storage_type == otypes.DiskStorageType.IMAGE: ret = disks_module.action( action='export', action_condition=lambda d: module.params['image_provider'], wait_condition=lambda d: d.status == otypes.DiskStatus.OK, storage_domain=otypes.StorageDomain(name=module.params['image_provider']), ) elif state == 'absent': ret = disks_module.remove() # If VM was passed attach/detach disks to/from the VM: if module.params.get('vm_id') is not None or module.params.get('vm_name') is not None and state != 'absent': vms_service = connection.system_service().vms_service() # If `vm_id` isn't specified, find VM by name: vm_id = module.params['vm_id'] if vm_id is None: vm_id = getattr(search_by_name(vms_service, module.params['vm_name']), 'id', None) if vm_id is None: module.fail_json( msg="VM don't exists, please create it first." ) disk_attachments_service = vms_service.vm_service(vm_id).disk_attachments_service() disk_attachments_module = DiskAttachmentsModule( connection=connection, module=module, service=disk_attachments_service, changed=ret['changed'] if ret else False, ) if state == 'present' or state == 'attached': ret = disk_attachments_module.create() if lun is None: wait( service=disk_attachments_service.service(ret['id']), condition=lambda d: follow_link(connection, d.disk).status == otypes.DiskStatus.OK, wait=module.params['wait'], timeout=module.params['timeout'], ) elif state == 'detached': ret = disk_attachments_module.remove() module.exit_json(**ret) except Exception as e: module.fail_json(msg=str(e), exception=traceback.format_exc()) finally: connection.close(logout=auth.get('token') is None)
def main(): """ main entry point for module execution """ element_spec = dict( name=dict(), configured_password=dict(no_log=True), update_password=dict(default='always', choices=['on_create', 'always']), public_key=dict(), public_key_contents=dict(), group=dict(aliases=['role']), groups=dict(type='list', elements='dict'), state=dict(default='present', choices=['present', 'absent']) ) aggregate_spec = deepcopy(element_spec) aggregate_spec['name'] = dict(required=True) # remove default in aggregate spec, to handle common arguments remove_default_spec(aggregate_spec) mutually_exclusive = [('name', 'aggregate'), ('public_key', 'public_key_contents'), ('group', 'groups')] argument_spec = dict( aggregate=dict(type='list', elements='dict', options=aggregate_spec, aliases=['users', 'collection'], mutually_exclusive=mutually_exclusive), purge=dict(type='bool', default=False) ) argument_spec.update(element_spec) argument_spec.update(iosxr_argument_spec) module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=mutually_exclusive, supports_check_mode=True) if (module.params['public_key_contents'] or module.params['public_key']): if not HAS_B64: module.fail_json( msg='library base64 is required but does not appear to be ' 'installed. It can be installed using `pip install base64`' ) if not HAS_PARAMIKO: module.fail_json( msg='library paramiko is required but does not appear to be ' 'installed. It can be installed using `pip install paramiko`' ) result = {'changed': False, 'warnings': []} if module.params['password'] and not module.params['configured_password']: result['warnings'].append( 'The "password" argument is used to authenticate the current connection. ' + 'To set a user password use "configured_password" instead.' ) config_object = None if is_cliconf(module): module.deprecate(msg="cli support for 'iosxr_user' is deprecated. Use transport netconf instead", version="4 releases from v2.5") config_object = CliConfiguration(module, result) elif is_netconf(module): config_object = NCConfiguration(module, result) if config_object: result = config_object.run() if module.params['public_key_contents'] or module.params['public_key']: pubkey_object = PublicKeyManager(module, result) result = pubkey_object.run() module.exit_json(**result)
def main(): module = AnsibleModule( argument_spec=dict( path=dict(required=True, type='path'), follow=dict(type='bool', default='no'), get_md5=dict(type='bool'), get_checksum=dict(type='bool', default='yes'), get_mime=dict(type='bool', default='yes', aliases=['mime', 'mime_type', 'mime-type']), get_attributes=dict(type='bool', default='yes', aliases=['attr', 'attributes']), checksum_algorithm=dict(type='str', default='sha1', choices=['md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512'], aliases=['checksum', 'checksum_algo']), ), supports_check_mode=True, ) path = module.params.get('path') b_path = to_bytes(path, errors='surrogate_or_strict') follow = module.params.get('follow') get_mime = module.params.get('get_mime') get_attr = module.params.get('get_attributes') get_md5 = module.params.get('get_md5') # get_md5 will be an undocumented option in 2.9 to be removed at a later # date if possible (3.0+) if get_md5: module.deprecate("get_md5 has been deprecated along with the md5 return value, use " "get_checksum=True and checksum_algorithm=md5 instead", 2.9) else: get_md5 = False get_checksum = module.params.get('get_checksum') checksum_algorithm = module.params.get('checksum_algorithm') # main stat data try: if follow: st = os.stat(b_path) else: st = os.lstat(b_path) except OSError as e: if e.errno == errno.ENOENT: output = {'exists': False} module.exit_json(changed=False, stat=output) module.fail_json(msg=e.strerror) # process base results output = format_output(module, path, st) # resolved permissions for perm in [('readable', os.R_OK), ('writeable', os.W_OK), ('executable', os.X_OK)]: output[perm[0]] = os.access(b_path, perm[1]) # symlink info if output.get('islnk'): output['lnk_source'] = os.path.realpath(b_path) output['lnk_target'] = os.readlink(b_path) try: # user data pw = pwd.getpwuid(st.st_uid) output['pw_name'] = pw.pw_name except: pass try: # group data grp_info = grp.getgrgid(st.st_gid) output['gr_name'] = grp_info.gr_name except: pass # checksums if output.get('isreg') and output.get('readable'): if get_md5: # Will fail on FIPS-140 compliant systems try: output['md5'] = module.md5(b_path) except ValueError: output['md5'] = None if get_checksum: output['checksum'] = module.digest_from_file(b_path, checksum_algorithm) # try to get mime data if requested if get_mime: output['mimetype'] = output['charset'] = 'unknown' mimecmd = module.get_bin_path('file') if mimecmd: mimecmd = [mimecmd, '-i', b_path] try: rc, out, err = module.run_command(mimecmd) if rc == 0: mimetype, charset = out.split(':')[1].split(';') output['mimetype'] = mimetype.strip() output['charset'] = charset.split('=')[1].strip() except: pass # try to get attr data if get_attr: output['version'] = None output['attributes'] = [] output['attr_flags'] = '' out = module.get_file_attributes(b_path) for x in ('version', 'attributes', 'attr_flags'): if x in out: output[x] = out[x] module.exit_json(changed=False, stat=output)
def main(): module = AnsibleModule( argument_spec=dict( cluster=dict(default='localhost'), port=dict(default='5433'), db=dict(default=None), login_user=dict(default='dbadmin'), login_password=dict(default=None, no_log=True), ), supports_check_mode=True) is_old_facts = module._name in ('vertica_facts', 'community.general.vertica_facts') if is_old_facts: module.deprecate("The 'vertica_facts' module has been renamed to 'vertica_info', " "and the renamed one no longer returns ansible_facts", version='2.13') if not pyodbc_found: module.fail_json(msg=missing_required_lib('pyodbc'), exception=PYODBC_IMP_ERR) db = '' if module.params['db']: db = module.params['db'] try: dsn = ( "Driver=Vertica;" "Server=%s;" "Port=%s;" "Database=%s;" "User=%s;" "Password=%s;" "ConnectionLoadBalance=%s" ) % (module.params['cluster'], module.params['port'], db, module.params['login_user'], module.params['login_password'], 'true') db_conn = pyodbc.connect(dsn, autocommit=True) cursor = db_conn.cursor() except Exception as e: module.fail_json(msg="Unable to connect to database: %s." % to_native(e), exception=traceback.format_exc()) try: schema_facts = get_schema_facts(cursor) user_facts = get_user_facts(cursor) role_facts = get_role_facts(cursor) configuration_facts = get_configuration_facts(cursor) node_facts = get_node_facts(cursor) if is_old_facts: module.exit_json(changed=False, ansible_facts={'vertica_schemas': schema_facts, 'vertica_users': user_facts, 'vertica_roles': role_facts, 'vertica_configuration': configuration_facts, 'vertica_nodes': node_facts}) else: module.exit_json(changed=False, vertica_schemas=schema_facts, vertica_users=user_facts, vertica_roles=role_facts, vertica_configuration=configuration_facts, vertica_nodes=node_facts) except NotSupportedError as e: module.fail_json(msg=to_native(e), exception=traceback.format_exc()) except SystemExit: # avoid catching this on python 2.4 raise except Exception as e: module.fail_json(msg=to_native(e), exception=traceback.format_exc())
def main(): argument_spec = ovirt_info_full_argument_spec( name=dict(default=None), host=dict(default=None), vm=dict(default=None), ) module = AnsibleModule(argument_spec) is_old_facts = module._name in ('ovirt_affinity_label_facts', 'community.general.ovirt_affinity_label_facts') if is_old_facts: module.deprecate("The 'ovirt_affinity_label_facts' module has been renamed to 'ovirt_affinity_label_info', " "and the renamed one no longer returns ansible_facts", version='3.0.0', collection_name='community.general') # was Ansible 2.13 check_sdk(module) try: auth = module.params.pop('auth') connection = create_connection(auth) affinity_labels_service = connection.system_service().affinity_labels_service() labels = [] all_labels = affinity_labels_service.list() if module.params['name']: labels.extend([ l for l in all_labels if fnmatch.fnmatch(l.name, module.params['name']) ]) if module.params['host']: hosts_service = connection.system_service().hosts_service() if search_by_name(hosts_service, module.params['host']) is None: raise Exception("Host '%s' was not found." % module.params['host']) labels.extend([ label for label in all_labels for host in connection.follow_link(label.hosts) if fnmatch.fnmatch(hosts_service.service(host.id).get().name, module.params['host']) ]) if module.params['vm']: vms_service = connection.system_service().vms_service() if search_by_name(vms_service, module.params['vm']) is None: raise Exception("Vm '%s' was not found." % module.params['vm']) labels.extend([ label for label in all_labels for vm in connection.follow_link(label.vms) if fnmatch.fnmatch(vms_service.service(vm.id).get().name, module.params['vm']) ]) if not (module.params['vm'] or module.params['host'] or module.params['name']): labels = all_labels result = dict( ovirt_affinity_labels=[ get_dict_of_struct( struct=l, connection=connection, fetch_nested=module.params.get('fetch_nested'), attributes=module.params.get('nested_attributes'), ) for l in labels ], ) if is_old_facts: module.exit_json(changed=False, ansible_facts=result) else: module.exit_json(changed=False, **result) except Exception as e: module.fail_json(msg=str(e), exception=traceback.format_exc()) finally: connection.close(logout=auth.get('token') is None)
def main(): argument_spec = dict(ip_address=dict(required=True), password=dict(no_log=True), username=dict(default='admin'), api_key=dict(no_log=True), sag_match_filter=dict(type='list', elements='str', required=False), sag_name=dict(required=True), commit=dict(type='bool', default=False), devicegroup=dict(default=None), description=dict(default=None), tags=dict(type='list', elements='str', default=[]), operation=dict(type='str', required=True, choices=['add', 'list', 'delete'])) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, required_one_of=[['api_key', 'password']]) module.deprecate( 'This module has been deprecated; use panos_address_group', version='3.0.0', collection_name='paloaltonetworks.panos') if not HAS_LIB: module.fail_json(msg='pan-python is required for this module') ip_address = module.params["ip_address"] password = module.params["password"] username = module.params['username'] api_key = module.params['api_key'] operation = module.params['operation'] ag_object = create_address_group_object( address_gp_name=module.params.get('sag_name', None), sag_match_filter=module.params.get('sag_match_filter', None), description=module.params.get('description', None), tag_name=module.params.get('tags', None)) commit = module.params['commit'] devicegroup = module.params['devicegroup'] # Create the device with the appropriate pandevice type device = base.PanDevice.create_from_device(ip_address, username, password, api_key=api_key) # If Panorama, validate the devicegroup dev_group = None if devicegroup and isinstance(device, panorama.Panorama): dev_group = get_devicegroup(device, devicegroup) if dev_group: device.add(dev_group) else: module.fail_json( msg= '\'%s\' device group not found in Panorama. Is the name correct?' % devicegroup) if operation == 'add': result, exc = add_address_group(device, dev_group, ag_object) if result and commit: try: device.commit(sync=True) except Exception: exc = get_exception() module.fail_json(msg=exc.message) elif operation == 'list': result, exc = get_all_address_group(device) if not exc: module.exit_json(msg=result) else: module.fail_json(msg=exc.message) elif operation == 'delete': obj_name = module.params.get('sag_name', None) result, exc = delete_address_group(device, dev_group, obj_name) if not result and exc: module.fail_json(msg=exc.message) elif not result: module.fail_json(msg="Specified object not found.") else: module.fail_json(changed=False, msg="Unsupported option.") module.exit_json(changed=True, msg="Address Group Operation Completed.")
def main(): argument_spec = ovirt_info_full_argument_spec( name=dict(default=None), host=dict(default=None), vm=dict(default=None), ) module = AnsibleModule(argument_spec) check_sdk(module) if module.params['fetch_nested'] or module.params['nested_attributes']: module.deprecate( "The 'fetch_nested' and 'nested_attributes' are deprecated please use 'follow' parameter", version='2.0.0', collection_name='ovirt.ovirt' ) try: auth = module.params.pop('auth') connection = create_connection(auth) affinity_labels_service = connection.system_service().affinity_labels_service() labels = [] all_labels = affinity_labels_service.list() if module.params['name']: labels.extend([ l for l in all_labels if fnmatch.fnmatch(l.name, module.params['name']) ]) if module.params['host']: hosts_service = connection.system_service().hosts_service() if search_by_name(hosts_service, module.params['host']) is None: raise Exception("Host '%s' was not found." % module.params['host']) labels.extend([ label for label in all_labels for host in connection.follow_link(label.hosts) if fnmatch.fnmatch(hosts_service.service(host.id).get().name, module.params['host']) ]) if module.params['vm']: vms_service = connection.system_service().vms_service() if search_by_name(vms_service, module.params['vm']) is None: raise Exception("Vm '%s' was not found." % module.params['vm']) labels.extend([ label for label in all_labels for vm in connection.follow_link(label.vms) if fnmatch.fnmatch(vms_service.service(vm.id).get().name, module.params['vm']) ]) if not (module.params['vm'] or module.params['host'] or module.params['name']): labels = all_labels result = dict( ovirt_affinity_labels=[ get_dict_of_struct( struct=l, connection=connection, fetch_nested=module.params.get('fetch_nested'), attributes=module.params.get('nested_attributes'), ) for l in labels ], ) module.exit_json(changed=False, **result) except Exception as e: module.fail_json(msg=str(e), exception=traceback.format_exc()) finally: connection.close(logout=auth.get('token') is None)
def main(): module = AnsibleModule( argument_spec=dict( name=dict(type='str', required=True), state=dict(type='str', required=True, choices=['absent', 'present']), # No longer used. Deprecated and due for removal createparent=dict(type='bool', default=None), extra_zfs_properties=dict(type='dict', default={}), ), supports_check_mode=True, # Remove this in Ansible 2.9 check_invalid_arguments=False, ) state = module.params.pop('state') name = module.params.pop('name') # The following is deprecated. Remove in Ansible 2.9 # Get all valid zfs-properties properties = dict() for prop, value in module.params.items(): # All freestyle params are zfs properties if prop not in module.argument_spec: if isinstance(value, bool): if value is True: properties[prop] = 'on' else: properties[prop] = 'off' else: properties[prop] = value if properties: module.deprecate('Passing zfs properties as arbitrary parameters to the zfs module is' ' deprecated. Send them as a dictionary in the extra_zfs_properties' ' parameter instead.', version='2.9') # Merge, giving the module_params precedence for prop, value in module.params['extra_zfs_properties'].items(): properties[prop] = value module.params['extras_zfs_properties'] = properties # End deprecated section # Reverse the boolification of zfs properties for prop, value in module.params['extra_zfs_properties'].items(): if isinstance(value, bool): if value is True: module.params['extra_zfs_properties'][prop] = 'on' else: module.params['extra_zfs_properties'][prop] = 'off' else: module.params['extra_zfs_properties'][prop] = value result = dict( name=name, state=state, ) zfs = Zfs(module, name, module.params['extra_zfs_properties']) if state == 'present': if zfs.exists(): zfs.set_properties_if_changed() else: zfs.create() elif state == 'absent': if zfs.exists(): zfs.destroy() result.update(zfs.properties) result['changed'] = zfs.changed module.exit_json(**result)
def main(): module = AnsibleModule( argument_spec=dict( path=dict(type='path', aliases=['dest', 'file']), xmlstring=dict(type='str'), xpath=dict(type='str'), namespaces=dict(type='dict', default={}), state=dict(type='str', default='present', choices=['absent', 'present'], aliases=['ensure']), value=dict(type='raw'), attribute=dict(type='raw'), add_children=dict(type='list'), set_children=dict(type='list'), count=dict(type='bool', default=False), print_match=dict(type='bool', default=False), pretty_print=dict(type='bool', default=False), content=dict(type='str', choices=['attribute', 'text']), input_type=dict(type='str', default='yaml', choices=['xml', 'yaml']), backup=dict(type='bool', default=False), strip_cdata_tags=dict(type='bool', default=False), insertbefore=dict(type='bool', default=False), insertafter=dict(type='bool', default=False), ), supports_check_mode=True, required_by=dict( add_children=['xpath'], # TODO: Reinstate this in Ansible v2.12 when we have deprecated the incorrect use below # attribute=['value'], content=['xpath'], set_children=['xpath'], value=['xpath'], ), required_if=[ ['count', True, ['xpath']], ['print_match', True, ['xpath']], ['insertbefore', True, ['xpath']], ['insertafter', True, ['xpath']], ], required_one_of=[ ['path', 'xmlstring'], [ 'add_children', 'content', 'count', 'pretty_print', 'print_match', 'set_children', 'value' ], ], mutually_exclusive=[ [ 'add_children', 'content', 'count', 'print_match', 'set_children', 'value' ], ['path', 'xmlstring'], ['insertbefore', 'insertafter'], ], ) xml_file = module.params['path'] xml_string = module.params['xmlstring'] xpath = module.params['xpath'] namespaces = module.params['namespaces'] state = module.params['state'] value = json_dict_bytes_to_unicode(module.params['value']) attribute = module.params['attribute'] set_children = json_dict_bytes_to_unicode(module.params['set_children']) add_children = json_dict_bytes_to_unicode(module.params['add_children']) pretty_print = module.params['pretty_print'] content = module.params['content'] input_type = module.params['input_type'] print_match = module.params['print_match'] count = module.params['count'] backup = module.params['backup'] strip_cdata_tags = module.params['strip_cdata_tags'] insertbefore = module.params['insertbefore'] insertafter = module.params['insertafter'] # Check if we have lxml 2.3.0 or newer installed if not HAS_LXML: module.fail_json(msg=missing_required_lib("lxml"), exception=LXML_IMP_ERR) elif LooseVersion('.'.join( to_native(f) for f in etree.LXML_VERSION)) < LooseVersion('2.3.0'): module.fail_json( msg= 'The xml ansible module requires lxml 2.3.0 or newer installed on the managed machine' ) elif LooseVersion('.'.join( to_native(f) for f in etree.LXML_VERSION)) < LooseVersion('3.0.0'): module.warn( 'Using lxml version lower than 3.0.0 does not guarantee predictable element attribute order.' ) # Report wrongly used attribute parameter when using content=attribute # TODO: Remove this in Ansible v2.12 (and reinstate strict parameter test above) and remove the integration test example if content == 'attribute' and attribute is not None: module.deprecate( "Parameter 'attribute=%s' is ignored when using 'content=attribute' only 'xpath' is used. Please remove entry." % attribute, 'ansible.builtin:2.12') # Check if the file exists if xml_string: infile = BytesIO(to_bytes(xml_string, errors='surrogate_or_strict')) elif os.path.isfile(xml_file): infile = open(xml_file, 'rb') else: module.fail_json(msg="The target XML source '%s' does not exist." % xml_file) # Parse and evaluate xpath expression if xpath is not None: try: etree.XPath(xpath) except etree.XPathSyntaxError as e: module.fail_json(msg="Syntax error in xpath expression: %s (%s)" % (xpath, e)) except etree.XPathEvalError as e: module.fail_json( msg="Evaluation error in xpath expression: %s (%s)" % (xpath, e)) # Try to parse in the target XML file try: parser = etree.XMLParser(remove_blank_text=pretty_print, strip_cdata=strip_cdata_tags) doc = etree.parse(infile, parser) except etree.XMLSyntaxError as e: module.fail_json(msg="Error while parsing document: %s (%s)" % (xml_file or 'xml_string', e)) # Ensure we have the original copy to compare global orig_doc orig_doc = copy.deepcopy(doc) if print_match: do_print_match(module, doc, xpath, namespaces) if count: count_nodes(module, doc, xpath, namespaces) if content == 'attribute': get_element_attr(module, doc, xpath, namespaces) elif content == 'text': get_element_text(module, doc, xpath, namespaces) # File exists: if state == 'absent': # - absent: delete xpath target delete_xpath_target(module, doc, xpath, namespaces) # - present: carry on # children && value both set?: should have already aborted by now # add_children && set_children both set?: should have already aborted by now # set_children set? if set_children: set_target_children(module, doc, xpath, namespaces, set_children, input_type) # add_children set? if add_children: add_target_children(module, doc, xpath, namespaces, add_children, input_type, insertbefore, insertafter) # No?: Carry on # Is the xpath target an attribute selector? if value is not None: set_target(module, doc, xpath, namespaces, attribute, value) # If an xpath was provided, we need to do something with the data if xpath is not None: ensure_xpath_exists(module, doc, xpath, namespaces) # Otherwise only reformat the xml data? if pretty_print: make_pretty(module, doc) module.fail_json(msg="Don't know what to do")
def main(): module = AnsibleModule( argument_spec=dict( state=dict(type='str', default='present', choices=['absent', 'build-dep', 'installed', 'latest', 'present', 'removed', 'present']), update_cache=dict(type='bool', aliases=['update-cache']), cache_valid_time=dict(type='int', default=0), purge=dict(type='bool', default=False), package=dict(type='list', aliases=['pkg', 'name']), deb=dict(type='path'), default_release=dict(type='str', aliases=['default-release']), install_recommends=dict(type='bool', aliases=['install-recommends']), force=dict(type='bool', default=False), upgrade=dict(type='str', choices=['dist', 'full', 'no', 'safe', 'yes']), dpkg_options=dict(type='str', default=DPKG_OPTIONS), autoremove=dict(type='bool', default=False), autoclean=dict(type='bool', default=False), only_upgrade=dict(type='bool', default=False), force_apt_get=dict(type='bool', default=False), allow_unauthenticated=dict(type='bool', default=False, aliases=['allow-unauthenticated']), ), mutually_exclusive=[['deb', 'package', 'upgrade']], required_one_of=[['autoremove', 'deb', 'package', 'update_cache', 'upgrade']], supports_check_mode=True, ) module.run_command_environ_update = APT_ENV_VARS if not HAS_PYTHON_APT: if module.check_mode: module.fail_json(msg="%s must be installed to use check mode. " "If run normally this module can auto-install it." % PYTHON_APT) try: module.run_command(['apt-get', 'update'], check_rc=True) module.run_command(['apt-get', 'install', '--no-install-recommends', PYTHON_APT, '-y', '-q'], check_rc=True) global apt, apt_pkg import apt import apt.debfile import apt_pkg except ImportError: module.fail_json(msg="Could not import python modules: apt, apt_pkg. " "Please install %s package." % PYTHON_APT) global APTITUDE_CMD APTITUDE_CMD = module.get_bin_path("aptitude", False) global APT_GET_CMD APT_GET_CMD = module.get_bin_path("apt-get") p = module.params if p['upgrade'] == 'no': p['upgrade'] = None use_apt_get = p['force_apt_get'] if not use_apt_get and not APTITUDE_CMD and p.get('upgrade', None) in ['full', 'safe', 'yes']: module.warn("Could not find aptitude. Using apt-get instead.") use_apt_get = True updated_cache = False updated_cache_time = 0 install_recommends = p['install_recommends'] allow_unauthenticated = p['allow_unauthenticated'] dpkg_options = expand_dpkg_options(p['dpkg_options']) autoremove = p['autoremove'] autoclean = p['autoclean'] # Deal with deprecated aliases if p['state'] == 'installed': module.deprecate("State 'installed' is deprecated. Using state 'present' instead.", version="2.9") p['state'] = 'present' if p['state'] == 'removed': module.deprecate("State 'removed' is deprecated. Using state 'absent' instead.", version="2.9") p['state'] = 'absent' # Get the cache object cache = get_cache(module) try: if p['default_release']: try: apt_pkg.config['APT::Default-Release'] = p['default_release'] except AttributeError: apt_pkg.Config['APT::Default-Release'] = p['default_release'] # reopen cache w/ modified config cache.open(progress=None) mtimestamp, updated_cache_time = get_updated_cache_time() # Cache valid time is default 0, which will update the cache if # needed and `update_cache` was set to true updated_cache = False if p['update_cache'] or p['cache_valid_time']: now = datetime.datetime.now() tdelta = datetime.timedelta(seconds=p['cache_valid_time']) if not mtimestamp + tdelta >= now: # Retry to update the cache up to 3 times err = '' for retry in range(3): try: cache.update() break except apt.cache.FetchFailedException as e: err = to_native(e) else: module.fail_json(msg='Failed to update apt cache: %s' % err) cache.open(progress=None) mtimestamp, post_cache_update_time = get_updated_cache_time() if updated_cache_time != post_cache_update_time: updated_cache = True updated_cache_time = post_cache_update_time # If there is nothing else to do exit. This will set state as # changed based on if the cache was updated. if not p['package'] and not p['upgrade'] and not p['deb']: module.exit_json( changed=updated_cache, cache_updated=updated_cache, cache_update_time=updated_cache_time ) force_yes = p['force'] if p['upgrade']: upgrade(module, p['upgrade'], force_yes, p['default_release'], use_apt_get, dpkg_options, autoremove, allow_unauthenticated) if p['deb']: if p['state'] != 'present': module.fail_json(msg="deb only supports state=present") if '://' in p['deb']: p['deb'] = download(module, p['deb']) install_deb(module, p['deb'], cache, install_recommends=install_recommends, allow_unauthenticated=allow_unauthenticated, force=force_yes, dpkg_options=p['dpkg_options']) unfiltered_packages = p['package'] or () packages = [package for package in unfiltered_packages if package != '*'] all_installed = '*' in unfiltered_packages latest = p['state'] == 'latest' if latest and all_installed: if packages: module.fail_json(msg='unable to install additional packages when upgrading all installed packages') upgrade(module, 'yes', force_yes, p['default_release'], use_apt_get, dpkg_options, autoremove, allow_unauthenticated) if packages: for package in packages: if package.count('=') > 1: module.fail_json(msg="invalid package spec: %s" % package) if latest and '=' in package: module.fail_json(msg='version number inconsistent with state=latest: %s' % package) if not packages: if autoclean: cleanup(module, p['purge'], force=force_yes, operation='autoclean', dpkg_options=dpkg_options) if autoremove: cleanup(module, p['purge'], force=force_yes, operation='autoremove', dpkg_options=dpkg_options) if p['state'] in ('latest', 'present', 'build-dep'): state_upgrade = False state_builddep = False if p['state'] == 'latest': state_upgrade = True if p['state'] == 'build-dep': state_builddep = True success, retvals = install( module, packages, cache, upgrade=state_upgrade, default_release=p['default_release'], install_recommends=install_recommends, force=force_yes, dpkg_options=dpkg_options, build_dep=state_builddep, autoremove=autoremove, only_upgrade=p['only_upgrade'], allow_unauthenticated=allow_unauthenticated ) # Store if the cache has been updated retvals['cache_updated'] = updated_cache # Store when the update time was last retvals['cache_update_time'] = updated_cache_time if success: module.exit_json(**retvals) else: module.fail_json(**retvals) elif p['state'] == 'absent': remove(module, packages, cache, p['purge'], force=force_yes, dpkg_options=dpkg_options, autoremove=autoremove) except apt.cache.LockFailedException: module.fail_json(msg="Failed to lock apt for exclusive operation") except apt.cache.FetchFailedException: module.fail_json(msg="Could not fetch updated apt files")
def main(): argument_spec = ec2_argument_spec() argument_spec.update( dict(bucket=dict(required=True), dest=dict(default=None, type='path'), encrypt=dict(default=True, type='bool'), expiry=dict(default=600, type='int', aliases=['expiration']), headers=dict(type='dict'), marker=dict(default=""), max_keys=dict(default=1000, type='int'), metadata=dict(type='dict'), mode=dict(choices=[ 'get', 'put', 'delete', 'create', 'geturl', 'getstr', 'delobj', 'list' ], required=True), object=dict(), permission=dict(type='list', default=['private']), version=dict(default=None), overwrite=dict(aliases=['force'], default='always'), prefix=dict(default=""), retries=dict(aliases=['retry'], type='int', default=0), s3_url=dict(aliases=['S3_URL']), rgw=dict(default='no', type='bool'), src=dict(), ignore_nonexistent_bucket=dict(default=False, type='bool')), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, required_if=[('mode', 'put', ('src', ))], ) if module._name == 's3': module.deprecate("The 's3' module is being renamed 'aws_s3'", version=2.7) if not HAS_BOTO3: module.fail_json(msg='boto3 and botocore required for this module') bucket = module.params.get('bucket') encrypt = module.params.get('encrypt') expiry = module.params.get('expiry') dest = module.params.get('dest', '') headers = module.params.get('headers') marker = module.params.get('marker') max_keys = module.params.get('max_keys') metadata = module.params.get('metadata') mode = module.params.get('mode') obj = module.params.get('object') version = module.params.get('version') overwrite = module.params.get('overwrite') prefix = module.params.get('prefix') retries = module.params.get('retries') s3_url = module.params.get('s3_url') rgw = module.params.get('rgw') src = module.params.get('src') ignore_nonexistent_bucket = module.params.get('ignore_nonexistent_bucket') object_canned_acl = [ "private", "public-read", "public-read-write", "aws-exec-read", "authenticated-read", "bucket-owner-read", "bucket-owner-full-control" ] bucket_canned_acl = [ "private", "public-read", "public-read-write", "authenticated-read" ] if overwrite not in ['always', 'never', 'different']: if module.boolean(overwrite): overwrite = 'always' else: overwrite = 'never' region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True) if region in ('us-east-1', '', None): # default to US Standard region location = 'us-east-1' else: # Boto uses symbolic names for locations but region strings will # actually work fine for everything except us-east-1 (US Standard) location = region if module.params.get('object'): obj = module.params['object'] # If there is a top level object, do nothing - if the object starts with / # remove the leading character to maintain compatibility with Ansible versions < 2.4 if obj.startswith('/'): obj = obj[1:] # Bucket deletion does not require obj. Prevents ambiguity with delobj. if obj and mode == "delete": module.fail_json(msg='Parameter obj cannot be used with mode=delete') # allow eucarc environment variables to be used if ansible vars aren't set if not s3_url and 'S3_URL' in os.environ: s3_url = os.environ['S3_URL'] # rgw requires an explicit url if rgw and not s3_url: module.fail_json(msg='rgw flavour requires s3_url') # Look at s3_url and tweak connection settings # if connecting to RGW, Walrus or fakes3 if s3_url: for key in ['validate_certs', 'security_token', 'profile_name']: aws_connect_kwargs.pop(key, None) try: s3 = get_s3_connection(module, aws_connect_kwargs, location, rgw, s3_url) except botocore.exceptions.ProfileNotFound as e: module.fail_json(msg=to_native(e)) validate = not ignore_nonexistent_bucket # separate types of ACLs bucket_acl = [ acl for acl in module.params.get('permission') if acl in bucket_canned_acl ] object_acl = [ acl for acl in module.params.get('permission') if acl in object_canned_acl ] error_acl = [ acl for acl in module.params.get('permission') if acl not in bucket_canned_acl and acl not in object_canned_acl ] if error_acl: module.fail_json(msg='Unknown permission specified: %s' % error_acl) # First, we check to see if the bucket exists, we get "bucket" returned. bucketrtn = bucket_check(module, s3, bucket, validate=validate) if validate and mode not in ('create', 'put', 'delete') and not bucketrtn: module.fail_json(msg="Source bucket cannot be found.") # If our mode is a GET operation (download), go through the procedure as appropriate ... if mode == 'get': # Next, we check to see if the key in the bucket exists. If it exists, it also returns key_matches md5sum check. keyrtn = key_check(module, s3, bucket, obj, version=version, validate=validate) if keyrtn is False: if version: module.fail_json( msg="Key %s with version id %s does not exist." % (obj, version)) else: module.fail_json(msg="Key %s does not exist." % obj) # If the destination path doesn't exist or overwrite is True, no need to do the md5um etag check, so just download. # Compare the remote MD5 sum of the object with the local dest md5sum, if it already exists. if path_check(dest): # Determine if the remote and local object are identical if keysum(module, s3, bucket, obj, version=version) == module.md5(dest): sum_matches = True if overwrite == 'always': download_s3file(module, s3, bucket, obj, dest, retries, version=version) else: module.exit_json( msg= "Local and remote object are identical, ignoring. Use overwrite=always parameter to force.", changed=False) else: sum_matches = False if overwrite in ('always', 'different'): download_s3file(module, s3, bucket, obj, dest, retries, version=version) else: module.exit_json( msg= "WARNING: Checksums do not match. Use overwrite parameter to force download." ) else: download_s3file(module, s3, bucket, obj, dest, retries, version=version) # if our mode is a PUT operation (upload), go through the procedure as appropriate ... if mode == 'put': # if putting an object in a bucket yet to be created, acls for the bucket and/or the object may be specified # these were separated into the variables bucket_acl and object_acl above # Lets check the src path. if not path_check(src): module.fail_json(msg="Local object for PUT does not exist") # Lets check to see if bucket exists to get ground truth. if bucketrtn: keyrtn = key_check(module, s3, bucket, obj, version=version, validate=validate) # Lets check key state. Does it exist and if it does, compute the etag md5sum. if bucketrtn and keyrtn: # Compare the local and remote object if module.md5(src) == keysum(module, s3, bucket, obj): sum_matches = True if overwrite == 'always': # only use valid object acls for the upload_s3file function module.params['permission'] = object_acl upload_s3file(module, s3, bucket, obj, src, expiry, metadata, encrypt, headers) else: get_download_url(module, s3, bucket, obj, expiry, changed=False) else: sum_matches = False if overwrite in ('always', 'different'): # only use valid object acls for the upload_s3file function module.params['permission'] = object_acl upload_s3file(module, s3, bucket, obj, src, expiry, metadata, encrypt, headers) else: module.exit_json( msg= "WARNING: Checksums do not match. Use overwrite parameter to force upload." ) # If neither exist (based on bucket existence), we can create both. if not bucketrtn: # only use valid bucket acls for create_bucket function module.params['permission'] = bucket_acl create_bucket(module, s3, bucket, location) # only use valid object acls for the upload_s3file function module.params['permission'] = object_acl upload_s3file(module, s3, bucket, obj, src, expiry, metadata, encrypt, headers) # If bucket exists but key doesn't, just upload. if bucketrtn and not keyrtn: # only use valid object acls for the upload_s3file function module.params['permission'] = object_acl upload_s3file(module, s3, bucket, obj, src, expiry, metadata, encrypt, headers) # Delete an object from a bucket, not the entire bucket if mode == 'delobj': if obj is None: module.fail_json(msg="object parameter is required") if bucket: deletertn = delete_key(module, s3, bucket, obj) if deletertn is True: module.exit_json(msg="Object deleted from bucket %s." % bucket, changed=True) else: module.fail_json(msg="Bucket parameter is required.") # Delete an entire bucket, including all objects in the bucket if mode == 'delete': if bucket: deletertn = delete_bucket(module, s3, bucket) if deletertn is True: module.exit_json( msg="Bucket %s and all keys have been deleted." % bucket, changed=True) else: module.fail_json(msg="Bucket parameter is required.") # Support for listing a set of keys if mode == 'list': exists = bucket_check(module, s3, bucket) # If the bucket does not exist then bail out if not exists: module.fail_json(msg="Target bucket (%s) cannot be found" % bucket) list_keys(module, s3, bucket, prefix, marker, max_keys) # Need to research how to create directories without "populating" a key, so this should just do bucket creation for now. # WE SHOULD ENABLE SOME WAY OF CREATING AN EMPTY KEY TO CREATE "DIRECTORY" STRUCTURE, AWS CONSOLE DOES THIS. if mode == 'create': # if both creating a bucket and putting an object in it, acls for the bucket and/or the object may be specified # these were separated above into the variables bucket_acl and object_acl if bucket and not obj: if bucketrtn: module.exit_json(msg="Bucket already exists.", changed=False) else: # only use valid bucket acls when creating the bucket module.params['permission'] = bucket_acl module.exit_json(msg="Bucket created successfully", changed=create_bucket(module, s3, bucket, location)) if bucket and obj: if obj.endswith('/'): dirobj = obj else: dirobj = obj + "/" if bucketrtn: if key_check(module, s3, bucket, dirobj): module.exit_json( msg="Bucket %s and key %s already exists." % (bucket, obj), changed=False) else: # setting valid object acls for the create_dirkey function module.params['permission'] = object_acl create_dirkey(module, s3, bucket, dirobj) else: # only use valid bucket acls for the create_bucket function module.params['permission'] = bucket_acl created = create_bucket(module, s3, bucket, location) # only use valid object acls for the create_dirkey function module.params['permission'] = object_acl create_dirkey(module, s3, bucket, dirobj) # Support for grabbing the time-expired URL for an object in S3/Walrus. if mode == 'geturl': if not bucket and not obj: module.fail_json(msg="Bucket and Object parameters must be set") keyrtn = key_check(module, s3, bucket, obj, version=version, validate=validate) if keyrtn: get_download_url(module, s3, bucket, obj, expiry) else: module.fail_json(msg="Key %s does not exist." % obj) if mode == 'getstr': if bucket and obj: keyrtn = key_check(module, s3, bucket, obj, version=version, validate=validate) if keyrtn: download_s3str(module, s3, bucket, obj, version=version) elif version is not None: module.fail_json( msg="Key %s with version id %s does not exist." % (obj, version)) else: module.fail_json(msg="Key %s does not exist." % obj) module.exit_json(failed=False)
def main(): argument_spec = ec2_argument_spec() argument_spec.update(dict( dhcp_options_id=dict(type='str', default=None), domain_name=dict(type='str', default=None), dns_servers=dict(type='list', default=None), ntp_servers=dict(type='list', default=None), netbios_name_servers=dict(type='list', default=None), netbios_node_type=dict(type='int', default=None), vpc_id=dict(type='str', default=None), delete_old=dict(type='bool', default=True), inherit_existing=dict(type='bool', default=False), tags=dict(type='dict', default=None, aliases=['resource_tags']), state=dict(type='str', default='present', choices=['present', 'absent']) ) ) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) if module._name == 'ec2_vpc_dhcp_options': module.deprecate("The 'ec2_vpc_dhcp_options' module has been renamed " "'ec2_vpc_dhcp_option' (option is no longer plural)", version=2.8) params = module.params found = False changed = False new_options = collections.defaultdict(lambda: None) if not HAS_BOTO: module.fail_json(msg='boto is required for this module') region, ec2_url, boto_params = get_aws_connection_info(module) connection = connect_to_aws(boto.vpc, region, **boto_params) existing_options = None # First check if we were given a dhcp_options_id if not params['dhcp_options_id']: # No, so create new_options from the parameters if params['dns_servers'] is not None: new_options['domain-name-servers'] = params['dns_servers'] if params['netbios_name_servers'] is not None: new_options['netbios-name-servers'] = params['netbios_name_servers'] if params['ntp_servers'] is not None: new_options['ntp-servers'] = params['ntp_servers'] if params['domain_name'] is not None: # needs to be a list for comparison with boto objects later new_options['domain-name'] = [params['domain_name']] if params['netbios_node_type'] is not None: # needs to be a list for comparison with boto objects later new_options['netbios-node-type'] = [str(params['netbios_node_type'])] # If we were given a vpc_id then we need to look at the options on that if params['vpc_id']: existing_options = fetch_dhcp_options_for_vpc(connection, params['vpc_id']) # if we've been asked to inherit existing options, do that now if params['inherit_existing']: if existing_options: for option in ['domain-name-servers', 'netbios-name-servers', 'ntp-servers', 'domain-name', 'netbios-node-type']: if existing_options.options.get(option) and new_options[option] != [] and (not new_options[option] or [''] == new_options[option]): new_options[option] = existing_options.options.get(option) # Do the vpc's dhcp options already match what we're asked for? if so we are done if existing_options and new_options == existing_options.options: module.exit_json(changed=changed, new_options=new_options, dhcp_options_id=existing_options.id) # If no vpc_id was given, or the options don't match then look for an existing set using tags found, dhcp_option = match_dhcp_options(connection, params['tags'], new_options) # Now let's cover the case where there are existing options that we were told about by id # If a dhcp_options_id was supplied we don't look at options inside, just set tags (if given) else: supplied_options = connection.get_all_dhcp_options(filters={'dhcp-options-id': params['dhcp_options_id']}) if len(supplied_options) != 1: if params['state'] != 'absent': module.fail_json(msg=" a dhcp_options_id was supplied, but does not exist") else: found = True dhcp_option = supplied_options[0] if params['state'] != 'absent' and params['tags']: ensure_tags(module, connection, dhcp_option.id, params['tags'], False, module.check_mode) # Now we have the dhcp options set, let's do the necessary # if we found options we were asked to remove then try to do so if params['state'] == 'absent': if not module.check_mode: if found: changed = remove_dhcp_options_by_id(connection, dhcp_option.id) module.exit_json(changed=changed, new_options={}) # otherwise if we haven't found the required options we have something to do elif not module.check_mode and not found: # create some dhcp options if we weren't able to use existing ones if not found: # Convert netbios-node-type and domain-name back to strings if new_options['netbios-node-type']: new_options['netbios-node-type'] = new_options['netbios-node-type'][0] if new_options['domain-name']: new_options['domain-name'] = new_options['domain-name'][0] # create the new dhcp options set requested dhcp_option = connection.create_dhcp_options( new_options['domain-name'], new_options['domain-name-servers'], new_options['ntp-servers'], new_options['netbios-name-servers'], new_options['netbios-node-type']) # wait for dhcp option to be accessible found_dhcp_opt = False start_time = time() try: found_dhcp_opt = retry_not_found(connection.get_all_dhcp_options, dhcp_options_ids=[dhcp_option.id]) except EC2ResponseError as e: module.fail_json(msg="Failed to describe DHCP options", exception=traceback.format_exc) if not found_dhcp_opt: module.fail_json(msg="Failed to wait for {0} to be available.".format(dhcp_option.id)) changed = True if params['tags']: ensure_tags(module, connection, dhcp_option.id, params['tags'], False, module.check_mode) # If we were given a vpc_id, then attach the options we now have to that before we finish if params['vpc_id'] and not module.check_mode: changed = True connection.associate_dhcp_options(dhcp_option.id, params['vpc_id']) # and remove old ones if that was requested if params['delete_old'] and existing_options: remove_dhcp_options_by_id(connection, existing_options.id) module.exit_json(changed=changed, new_options=new_options, dhcp_options_id=dhcp_option.id)
def main(): global module module = AnsibleModule( # not checking because of daisy chain to file module argument_spec=dict( src=dict(type='path'), _original_basename=dict( type='str' ), # used to handle 'dest is a directory' via template, a slight hack content=dict(type='str', no_log=True), dest=dict(type='path', required=True), backup=dict(type='bool', default=False), force=dict(type='bool', default=True, aliases=['thirsty']), validate=dict(type='str'), directory_mode=dict(type='raw'), remote_src=dict(type='bool'), local_follow=dict(type='bool'), checksum=dict(type='str'), ), add_file_common_args=True, supports_check_mode=True, ) if module.params.get('thirsty'): module.deprecate( 'The alias "thirsty" has been deprecated and will be removed, use "force" instead', version='2.13') src = module.params['src'] b_src = to_bytes(src, errors='surrogate_or_strict') dest = module.params['dest'] # Make sure we always have a directory component for later processing if os.path.sep not in dest: dest = '.{0}{1}'.format(os.path.sep, dest) b_dest = to_bytes(dest, errors='surrogate_or_strict') backup = module.params['backup'] force = module.params['force'] _original_basename = module.params.get('_original_basename', None) validate = module.params.get('validate', None) follow = module.params['follow'] local_follow = module.params['local_follow'] mode = module.params['mode'] owner = module.params['owner'] group = module.params['group'] remote_src = module.params['remote_src'] checksum = module.params['checksum'] if not os.path.exists(b_src): module.fail_json(msg="Source %s not found" % (src)) if not os.access(b_src, os.R_OK): module.fail_json(msg="Source %s not readable" % (src)) # Preserve is usually handled in the action plugin but mode + remote_src has to be done on the # remote host if module.params['mode'] == 'preserve': module.params['mode'] = '0%03o' % stat.S_IMODE(os.stat(b_src).st_mode) mode = module.params['mode'] checksum_dest = None if os.path.isfile(src): checksum_src = module.sha1(src) else: checksum_src = None # Backwards compat only. This will be None in FIPS mode try: if os.path.isfile(src): md5sum_src = module.md5(src) else: md5sum_src = None except ValueError: md5sum_src = None changed = False if checksum and checksum_src != checksum: module.fail_json( msg= 'Copied file does not match the expected checksum. Transfer failed.', checksum=checksum_src, expected_checksum=checksum) # Special handling for recursive copy - create intermediate dirs if _original_basename and dest.endswith(os.sep): dest = os.path.join(dest, _original_basename) b_dest = to_bytes(dest, errors='surrogate_or_strict') dirname = os.path.dirname(dest) b_dirname = to_bytes(dirname, errors='surrogate_or_strict') if not os.path.exists(b_dirname): try: (pre_existing_dir, new_directory_list) = split_pre_existing_dir(dirname) except AnsibleModuleError as e: e.result['msg'] += ' Could not copy to {0}'.format(dest) module.fail_json(**e.results) os.makedirs(b_dirname) directory_args = module.load_file_common_arguments(module.params) directory_mode = module.params["directory_mode"] if directory_mode is not None: directory_args['mode'] = directory_mode else: directory_args['mode'] = None adjust_recursive_directory_permissions(pre_existing_dir, new_directory_list, module, directory_args, changed) if os.path.isdir(b_dest): basename = os.path.basename(src) if _original_basename: basename = _original_basename dest = os.path.join(dest, basename) b_dest = to_bytes(dest, errors='surrogate_or_strict') if os.path.exists(b_dest): if os.path.islink(b_dest) and follow: b_dest = os.path.realpath(b_dest) dest = to_native(b_dest, errors='surrogate_or_strict') if not force: module.exit_json(msg="file already exists", src=src, dest=dest, changed=False) if os.access(b_dest, os.R_OK) and os.path.isfile(b_dest): checksum_dest = module.sha1(dest) else: if not os.path.exists(os.path.dirname(b_dest)): try: # os.path.exists() can return false in some # circumstances where the directory does not have # the execute bit for the current user set, in # which case the stat() call will raise an OSError os.stat(os.path.dirname(b_dest)) except OSError as e: if "permission denied" in to_native(e).lower(): module.fail_json( msg="Destination directory %s is not accessible" % (os.path.dirname(dest))) module.fail_json(msg="Destination directory %s does not exist" % (os.path.dirname(dest))) if not os.access(os.path.dirname(b_dest), os.W_OK) and not module.params['unsafe_writes']: module.fail_json(msg="Destination %s not writable" % (os.path.dirname(dest))) backup_file = None if checksum_src != checksum_dest or os.path.islink(b_dest): if not module.check_mode: try: if backup: if os.path.exists(b_dest): backup_file = module.backup_local(dest) # allow for conversion from symlink. if os.path.islink(b_dest): os.unlink(b_dest) open(b_dest, 'w').close() if validate: # if we have a mode, make sure we set it on the temporary # file source as some validations may require it if mode is not None: module.set_mode_if_different(src, mode, False) if owner is not None: module.set_owner_if_different(src, owner, False) if group is not None: module.set_group_if_different(src, group, False) if "%s" not in validate: module.fail_json(msg="validate must contain %%s: %s" % (validate)) (rc, out, err) = module.run_command(validate % src) if rc != 0: module.fail_json(msg="failed to validate", exit_status=rc, stdout=out, stderr=err) b_mysrc = b_src if remote_src and os.path.isfile(b_src): _, b_mysrc = tempfile.mkstemp(dir=os.path.dirname(b_dest)) shutil.copyfile(b_src, b_mysrc) try: shutil.copystat(b_src, b_mysrc) except OSError as err: if err.errno == errno.ENOSYS and mode == "preserve": module.warn("Unable to copy stats {0}".format( to_native(b_src))) else: raise # might be needed below if PY3 and hasattr(os, 'listxattr'): try: src_has_acls = 'system.posix_acl_access' in os.listxattr( src) except Exception as e: # assume unwanted ACLs by default src_has_acls = True module.atomic_move( b_mysrc, dest, unsafe_writes=module.params['unsafe_writes']) if PY3 and hasattr(os, 'listxattr') and platform.system( ) == 'Linux' and not remote_src: # atomic_move used above to copy src into dest might, in some cases, # use shutil.copy2 which in turn uses shutil.copystat. # Since Python 3.3, shutil.copystat copies file extended attributes: # https://docs.python.org/3/library/shutil.html#shutil.copystat # os.listxattr (along with others) was added to handle the operation. # This means that on Python 3 we are copying the extended attributes which includes # the ACLs on some systems - further limited to Linux as the documentation above claims # that the extended attributes are copied only on Linux. Also, os.listxattr is only # available on Linux. # If not remote_src, then the file was copied from the controller. In that # case, any filesystem ACLs are artifacts of the copy rather than preservation # of existing attributes. Get rid of them: if src_has_acls: # FIXME If dest has any default ACLs, there are not applied to src now because # they were overridden by copystat. Should/can we do anything about this? # 'system.posix_acl_default' in os.listxattr(os.path.dirname(b_dest)) try: clear_facls(dest) except ValueError as e: if 'setfacl' in to_native(e): # No setfacl so we're okay. The controller couldn't have set a facl # without the setfacl command pass else: raise except RuntimeError as e: # setfacl failed. if 'Operation not supported' in to_native(e): # The file system does not support ACLs. pass else: raise except (IOError, OSError): module.fail_json(msg="failed to copy: %s to %s" % (src, dest), traceback=traceback.format_exc()) changed = True else: changed = False if checksum_src is None and checksum_dest is None: if remote_src and os.path.isdir(module.params['src']): b_src = to_bytes(module.params['src'], errors='surrogate_or_strict') b_dest = to_bytes(module.params['dest'], errors='surrogate_or_strict') if src.endswith(os.path.sep) and os.path.isdir( module.params['dest']): diff_files_changed = copy_diff_files(b_src, b_dest, module) left_only_changed = copy_left_only(b_src, b_dest, module) common_dirs_changed = copy_common_dirs(b_src, b_dest, module) owner_group_changed = chown_recursive(b_dest, module) if diff_files_changed or left_only_changed or common_dirs_changed or owner_group_changed: changed = True if src.endswith( os.path.sep) and not os.path.exists(module.params['dest']): b_basename = to_bytes(os.path.basename(src), errors='surrogate_or_strict') b_dest = to_bytes(os.path.join(b_dest, b_basename), errors='surrogate_or_strict') b_src = to_bytes(os.path.join(module.params['src'], ""), errors='surrogate_or_strict') if not module.check_mode: shutil.copytree(b_src, b_dest, symlinks=not (local_follow)) chown_recursive(dest, module) changed = True if not src.endswith(os.path.sep) and os.path.isdir( module.params['dest']): b_basename = to_bytes(os.path.basename(src), errors='surrogate_or_strict') b_dest = to_bytes(os.path.join(b_dest, b_basename), errors='surrogate_or_strict') b_src = to_bytes(os.path.join(module.params['src'], ""), errors='surrogate_or_strict') if not module.check_mode and not os.path.exists(b_dest): shutil.copytree(b_src, b_dest, symlinks=not (local_follow)) changed = True chown_recursive(dest, module) if module.check_mode and not os.path.exists(b_dest): changed = True if os.path.exists(b_dest): diff_files_changed = copy_diff_files(b_src, b_dest, module) left_only_changed = copy_left_only(b_src, b_dest, module) common_dirs_changed = copy_common_dirs( b_src, b_dest, module) owner_group_changed = chown_recursive(b_dest, module) if diff_files_changed or left_only_changed or common_dirs_changed or owner_group_changed: changed = True if not src.endswith(os.path.sep) and not os.path.exists( module.params['dest']): b_basename = to_bytes(os.path.basename(module.params['src']), errors='surrogate_or_strict') b_dest = to_bytes(os.path.join(b_dest, b_basename), errors='surrogate_or_strict') if not module.check_mode and not os.path.exists(b_dest): os.makedirs(b_dest) b_src = to_bytes(os.path.join(module.params['src'], ""), errors='surrogate_or_strict') diff_files_changed = copy_diff_files(b_src, b_dest, module) left_only_changed = copy_left_only(b_src, b_dest, module) common_dirs_changed = copy_common_dirs( b_src, b_dest, module) owner_group_changed = chown_recursive(b_dest, module) if diff_files_changed or left_only_changed or common_dirs_changed or owner_group_changed: changed = True if module.check_mode and not os.path.exists(b_dest): changed = True res_args = dict(dest=dest, src=src, md5sum=md5sum_src, checksum=checksum_src, changed=changed) if backup_file: res_args['backup_file'] = backup_file module.params['dest'] = dest if not module.check_mode: file_args = module.load_file_common_arguments(module.params) res_args['changed'] = module.set_fs_attributes_if_different( file_args, res_args['changed']) module.exit_json(**res_args)
def main(): argument_spec = dict( ip_address=dict(required=True), password=dict(required=True, no_log=True), username=dict(default='admin'), rule_name=dict(required=True), from_zone=dict(type='list', required=True), to_zone=dict(required=True), source=dict(type='list', default=["any"]), destination=dict(type='list', default=["any"]), service=dict(default="any"), snat_type=dict(), snat_address=dict(), snat_interface=dict(), snat_interface_address=dict(), snat_bidirectional=dict(default=False), dnat_address=dict(), dnat_port=dict(), override=dict(type='bool', default=False), commit=dict(type='bool', default=True) ) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False) if module._name == 'panos_nat_policy': module.deprecate("The 'panos_nat_policy' module is being renamed 'panos_nat_rule'", version=2.8) if not HAS_LIB: module.fail_json(msg='pan-python is required for this module') ip_address = module.params["ip_address"] password = module.params["password"] username = module.params['username'] xapi = pan.xapi.PanXapi( hostname=ip_address, api_username=username, api_password=password ) rule_name = module.params['rule_name'] from_zone = module.params['from_zone'] to_zone = module.params['to_zone'] source = module.params['source'] destination = module.params['destination'] service = module.params['service'] snat_type = module.params['snat_type'] snat_address = module.params['snat_address'] snat_interface = module.params['snat_interface'] snat_interface_address = module.params['snat_interface_address'] snat_bidirectional = module.params['snat_bidirectional'] dnat_address = module.params['dnat_address'] dnat_port = module.params['dnat_port'] commit = module.params['commit'] override = module.params["override"] if not override and nat_rule_exists(xapi, rule_name): module.exit_json(changed=False, msg="rule exists") try: changed = add_nat( xapi, module, rule_name, from_zone, to_zone, source, destination, service, dnatxml=dnat_xml(module, dnat_address, dnat_port), snatxml=snat_xml(module, snat_type, snat_address, snat_interface, snat_interface_address, snat_bidirectional) ) if changed and commit: xapi.commit(cmd="<commit></commit>", sync=True, interval=1) module.exit_json(changed=changed, msg="okey dokey") except PanXapiError as exc: module.fail_json(msg=to_native(exc))
def main(): helper = get_connection( vsys=True, device_group=True, rulebase=True, with_state=True, with_classic_provider_spec=True, error_on_shared=True, argument_spec=dict( rule_name=dict(required=True), source_zone=dict(type='list', default=['any']), source_ip=dict(type='list', default=["any"]), source_user=dict(type='list', default=['any']), hip_profiles=dict(type='list', default=['any']), destination_zone=dict(type='list', default=['any']), destination_ip=dict(type='list', default=["any"]), application=dict(type='list', default=['any']), service=dict(type='list', default=['application-default']), category=dict(type='list', default=['any']), action=dict( default='allow', choices=[ 'allow', 'deny', 'drop', 'reset-client', 'reset-server', 'reset-both' ], ), log_setting=dict(), log_start=dict(type='bool', default=False), log_end=dict(type='bool', default=True), description=dict(), rule_type=dict(default='universal', choices=['universal', 'intrazone', 'interzone']), tag_name=dict(type='list'), negate_source=dict(type='bool', default=False), negate_destination=dict(type='bool', default=False), disabled=dict(type='bool', default=False), schedule=dict(), icmp_unreachable=dict(type='bool'), disable_server_response_inspection=dict(type='bool', default=False), group_profile=dict(), antivirus=dict(), spyware=dict(), vulnerability=dict(), url_filtering=dict(), file_blocking=dict(), wildfire_analysis=dict(), data_filtering=dict(), target=dict(type='list'), negate_target=dict(type='bool'), location=dict(choices=['top', 'bottom', 'before', 'after']), existing_rule=dict(), commit=dict(type='bool', default=True), # TODO(gfreeman) - remove this in the next role release. operation=dict(), # TODO(gfreeman) - remove this in the next role release. devicegroup=dict(), ), ) module = AnsibleModule( argument_spec=helper.argument_spec, supports_check_mode=True, required_one_of=helper.required_one_of, ) # TODO(gfreeman) - removed when operation is removed. if module.params['operation'] is not None: module.fail_json( msg='Param "operation" is removed; use "state" instead') # TODO(gfreeman) - remove when devicegroup is removed. if module.params['devicegroup'] is not None: module.deprecate( 'Param "devicegroup" is deprecated; use "device_group"', '2.12') if module.params['device_group'] is not None: msg = [ 'Both "devicegroup" and "device_group" are specified', 'Specify one or the other, not both.', ] module.fail_json(msg='. '.join(msg)) module.params['device_group'] = module.params['devicegroup'] # Verify imports, build pandevice object tree. parent = helper.get_pandevice_parent(module) # Set the SecurityRule object params. rule_spec = { 'name': module.params['rule_name'], 'fromzone': module.params['source_zone'], 'tozone': module.params['destination_zone'], 'source': module.params['source_ip'], 'source_user': module.params['source_user'], 'hip_profiles': module.params['hip_profiles'], 'destination': module.params['destination_ip'], 'application': module.params['application'], 'service': module.params['service'], 'category': module.params['category'], 'action': module.params['action'], 'log_setting': module.params['log_setting'], 'log_start': module.params['log_start'], 'log_end': module.params['log_end'], 'description': module.params['description'], 'type': module.params['rule_type'], 'tag': module.params['tag_name'], 'negate_source': module.params['negate_source'], 'negate_destination': module.params['negate_destination'], 'disabled': module.params['disabled'], 'schedule': module.params['schedule'], 'icmp_unreachable': module.params['icmp_unreachable'], 'disable_server_response_inspection': module.params['disable_server_response_inspection'], 'group': module.params['group_profile'], 'virus': module.params['antivirus'], 'spyware': module.params['spyware'], 'vulnerability': module.params['vulnerability'], 'url_filtering': module.params['url_filtering'], 'file_blocking': module.params['file_blocking'], 'wildfire_analysis': module.params['wildfire_analysis'], 'data_filtering': module.params['data_filtering'], 'target': module.params['target'], 'negate_target': module.params['negate_target'], } # Other module info. location = module.params['location'] existing_rule = module.params['existing_rule'] commit = module.params['commit'] # Retrieve the current rules. try: rules = SecurityRule.refreshall(parent, add=False) except PanDeviceError as e: module.fail_json(msg='Failed refresh: {0}'.format(e)) # Create new rule object from the params. new_rule = SecurityRule(**rule_spec) parent.add(new_rule) # Which action shall we take on the rule object? changed = helper.apply_state(new_rule, rules, module) # Move the rule to the correct spot, if applicable. if module.params['state'] == 'present': changed |= helper.apply_position(new_rule, location, existing_rule, module) # Optional commit. if changed and commit: helper.commit(module) # Done. module.exit_json(changed=changed, msg='Done')
def main(): argument_spec = ovirt_full_argument_spec( state=dict( choices=['present', 'absent'], default='present', ), name=dict(default=None), description=dict(default=None), type=dict( default=None, required=True, choices=[ 'os_image', 'network', 'os_volume', 'foreman', ], aliases=['provider'], ), url=dict(default=None), username=dict(default=None), password=dict(default=None, no_log=True), tenant_name=dict(default=None, aliases=['tenant']), authentication_url=dict(default=None, aliases=['auth_url']), data_center=dict(default=None), read_only=dict(default=None, type='bool'), network_type=dict( default='external', choices=['external', 'neutron'], ), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) if module._name == 'ovirt_external_providers': module.deprecate( "The 'ovirt_external_providers' module is being renamed 'ovirt_external_provider'", version=2.8) check_sdk(module) check_params(module) try: auth = module.params.pop('auth') connection = create_connection(auth) provider_type, external_providers_service = _external_provider_service( provider_type=module.params.get('type'), system_service=connection.system_service(), ) external_providers_module = ExternalProviderModule( connection=connection, module=module, service=external_providers_service, ) external_providers_module.provider_type(provider_type) state = module.params.pop('state') if state == 'absent': ret = external_providers_module.remove() elif state == 'present': ret = external_providers_module.create() module.exit_json(**ret) except Exception as e: module.fail_json(msg=str(e), exception=traceback.format_exc()) finally: connection.close(logout=auth.get('token') is None)
def main(): argument_spec = vmware_argument_spec() argument_spec.update( dict(hostname=dict(required=False, aliases=['host']), username=dict(required=False, aliases=['login']), src=dict(required=True, aliases=['name']), datacenter=dict(required=False), datastore=dict(required=True), dest=dict(required=True, aliases=['path']), timeout=dict(default=10, type='int'))) module = AnsibleModule( argument_spec=argument_spec, # Implementing check-mode using HEAD is impossible, since size/date is not 100% reliable supports_check_mode=False, ) if module.params.get('host'): module.deprecate("The 'host' option is being replaced by 'hostname'", version='2.12') if module.params.get('login'): module.deprecate("The 'login' option is being replaced by 'username'", version='2.12') hostname = module.params['hostname'] username = module.params['username'] password = module.params.get('password') src = module.params.get('src') datacenter = module.params.get('datacenter') datastore = module.params.get('datastore') dest = module.params.get('dest') validate_certs = module.params.get('validate_certs') timeout = module.params.get('timeout') try: fd = open(src, "rb") atexit.register(fd.close) except Exception as e: module.fail_json(msg="Failed to open src file %s" % to_native(e)) if os.stat(src).st_size == 0: data = '' else: data = mmap.mmap(fd.fileno(), 0, access=mmap.ACCESS_READ) atexit.register(data.close) remote_path = vmware_path(datastore, datacenter, dest) if not all([hostname, username, password]): module.fail_json( msg= "One of following parameter is missing - hostname, username, password" ) url = 'https://%s%s' % (hostname, remote_path) headers = { "Content-Type": "application/octet-stream", "Content-Length": str(len(data)), } try: r = open_url(url, data=data, headers=headers, method='PUT', timeout=timeout, url_username=username, url_password=password, validate_certs=validate_certs, force_basic_auth=True) except socket.error as e: if isinstance(e.args, tuple): if len(e.args) > 0: if e[0] == errno.ECONNRESET: # vSphere resets connection if the file is in use and cannot be replaced module.fail_json( msg='Failed to upload, image probably in use', status=None, errno=e[0], reason=to_native(e), url=url) else: module.fail_json(msg=to_native(e)) else: module.fail_json(msg=str(e), status=None, errno=e[0], reason=str(e), url=url, exception=traceback.format_exc()) except Exception as e: error_code = -1 try: if isinstance(e[0], int): error_code = e[0] except (KeyError, TypeError): pass module.fail_json(msg=to_native(e), status=None, errno=error_code, reason=to_native(e), url=url, exception=traceback.format_exc()) status = r.getcode() if 200 <= status < 300: module.exit_json(changed=True, status=status, reason=r.msg, url=url) else: length = r.headers.get('content-length', None) if r.headers.get('transfer-encoding', '').lower() == 'chunked': chunked = 1 else: chunked = 0 module.fail_json(msg='Failed to upload', errno=None, status=status, reason=r.msg, length=length, headers=dict(r.headers), chunked=chunked, url=url)
def main(): argument_spec = url_argument_spec() argument_spec.update(dict( dest=dict(type='path'), url_username=dict(type='str', aliases=['user']), url_password=dict(type='str', aliases=['password'], no_log=True), body=dict(type='raw'), body_format=dict(type='str', default='raw', choices=['raw', 'json']), method=dict(type='str', default='GET', choices=['GET', 'POST', 'PUT', 'HEAD', 'DELETE', 'OPTIONS', 'PATCH', 'TRACE', 'CONNECT', 'REFRESH']), return_content=dict(type='bool', default='no'), follow_redirects=dict(type='str', default='safe', choices=['all', 'safe', 'none', 'yes', 'no']), creates=dict(type='path'), removes=dict(type='path'), status_code=dict(type='list', default=[200]), timeout=dict(type='int', default=30), headers=dict(type='dict', default={}) )) module = AnsibleModule( argument_spec=argument_spec, check_invalid_arguments=False, add_file_common_args=True ) url = module.params['url'] body = module.params['body'] body_format = module.params['body_format'].lower() method = module.params['method'] dest = module.params['dest'] return_content = module.params['return_content'] creates = module.params['creates'] removes = module.params['removes'] status_code = [int(x) for x in list(module.params['status_code'])] socket_timeout = module.params['timeout'] dict_headers = module.params['headers'] if body_format == 'json': # Encode the body unless its a string, then assume it is pre-formatted JSON if not isinstance(body, six.string_types): body = json.dumps(body) lower_header_keys = [key.lower() for key in dict_headers] if 'content-type' not in lower_header_keys: dict_headers['Content-Type'] = 'application/json' # Grab all the http headers. Need this hack since passing multi-values is # currently a bit ugly. (e.g. headers='{"Content-Type":"application/json"}') for key, value in six.iteritems(module.params): if key.startswith("HEADER_"): module.deprecate('Supplying headers via HEADER_* is deprecated and ' 'will be removed in a future version. Please use ' '`headers` to supply headers for the request') skey = key.replace("HEADER_", "") dict_headers[skey] = value if creates is not None: # do not run the command if the line contains creates=filename # and the filename already exists. This allows idempotence # of uri executions. if os.path.exists(creates): module.exit_json(stdout="skipped, since '%s' exists" % creates, changed=False, rc=0) if removes is not None: # do not run the command if the line contains removes=filename # and the filename do not exists. This allows idempotence # of uri executions. if not os.path.exists(removes): module.exit_json(stdout="skipped, since '%s' does not exist" % removes, changed=False, rc=0) # Make the request resp, content, dest = uri(module, url, dest, body, body_format, method, dict_headers, socket_timeout) resp['status'] = int(resp['status']) # Write the file out if requested if dest is not None: if resp['status'] == 304: changed = False else: write_file(module, url, dest, content) # allow file attribute changes changed = True module.params['path'] = dest file_args = module.load_file_common_arguments(module.params) file_args['path'] = dest changed = module.set_fs_attributes_if_different(file_args, changed) resp['path'] = dest else: changed = False # Transmogrify the headers, replacing '-' with '_', since variables don't # work with dashes. # In python3, the headers are title cased. Lowercase them to be # compatible with the python2 behaviour. uresp = {} for key, value in six.iteritems(resp): ukey = key.replace("-", "_").lower() uresp[ukey] = value try: uresp['location'] = absolute_location(url, uresp['location']) except KeyError: pass # Default content_encoding to try content_encoding = 'utf-8' if 'content_type' in uresp: content_type, params = cgi.parse_header(uresp['content_type']) if 'charset' in params: content_encoding = params['charset'] u_content = to_text(content, encoding=content_encoding) if 'application/json' in content_type or 'text/json' in content_type: try: js = json.loads(u_content) uresp['json'] = js except: pass else: u_content = to_text(content, encoding=content_encoding) if resp['status'] not in status_code: uresp['msg'] = 'Status code was not %s: %s' % (status_code, uresp.get('msg', '')) module.fail_json(content=u_content, **uresp) elif return_content: module.exit_json(changed=changed, content=u_content, **uresp) else: module.exit_json(changed=changed, **uresp)
def main(): argument_spec = ovirt_full_argument_spec( state=dict( choices=['present', 'absent'], default='present', ), data_center=dict(required=True), id=dict(default=None), name=dict(required=True), description=dict(default=None), comment=dict(default=None), vlan_tag=dict(default=None, type='int'), vm_network=dict(default=None, type='bool'), mtu=dict(default=None, type='int'), clusters=dict(default=None, type='list'), label=dict(default=None), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) if module._name == 'ovirt_networks': module.deprecate( "The 'ovirt_networks' module is being renamed 'ovirt_network'", version=2.8) check_sdk(module) check_params(module) try: auth = module.params.pop('auth') connection = create_connection(auth) clusters_service = connection.system_service().clusters_service() networks_service = connection.system_service().networks_service() networks_module = NetworksModule( connection=connection, module=module, service=networks_service, ) state = module.params['state'] search_params = { 'name': module.params['name'], 'datacenter': module.params['data_center'], } if state == 'present': ret = networks_module.create(search_params=search_params) # Update clusters networks: if module.params.get('clusters') is not None: for param_cluster in module.params.get('clusters'): cluster = search_by_name(clusters_service, param_cluster.get('name')) if cluster is None: raise Exception("Cluster '%s' was not found." % param_cluster.get('name')) cluster_networks_service = clusters_service.service( cluster.id).networks_service() cluster_networks_module = ClusterNetworksModule( network_id=ret['id'], cluster_network=param_cluster, connection=connection, module=module, service=cluster_networks_service, ) if param_cluster.get('assigned', True): ret = cluster_networks_module.create() else: ret = cluster_networks_module.remove() elif state == 'absent': ret = networks_module.remove(search_params=search_params) module.exit_json(**ret) except Exception as e: module.fail_json(msg=str(e), exception=traceback.format_exc()) finally: connection.close(logout=auth.get('token') is None)
class AzureRMModuleBase(object): def __init__(self, derived_arg_spec, bypass_checks=False, no_log=False, check_invalid_arguments=None, mutually_exclusive=None, required_together=None, required_one_of=None, add_file_common_args=False, supports_check_mode=False, required_if=None, supports_tags=True, facts_module=False, skip_exec=False): merged_arg_spec = dict() merged_arg_spec.update(AZURE_COMMON_ARGS) if supports_tags: merged_arg_spec.update(AZURE_TAG_ARGS) if derived_arg_spec: merged_arg_spec.update(derived_arg_spec) merged_required_if = list(AZURE_COMMON_REQUIRED_IF) if required_if: merged_required_if += required_if self.module = AnsibleModule( argument_spec=merged_arg_spec, bypass_checks=bypass_checks, no_log=no_log, check_invalid_arguments=check_invalid_arguments, mutually_exclusive=mutually_exclusive, required_together=required_together, required_one_of=required_one_of, add_file_common_args=add_file_common_args, supports_check_mode=supports_check_mode, required_if=merged_required_if) if not HAS_PACKAGING_VERSION: self.fail( "Do you have packaging installed? Try `pip install packaging`" "- {0}".format(HAS_PACKAGING_VERSION_EXC)) if not HAS_MSRESTAZURE: self.fail( "Do you have msrestazure installed? Try `pip install msrestazure`" "- {0}".format(HAS_MSRESTAZURE_EXC)) if not HAS_AZURE: self.fail( "Do you have azure>={1} installed? Try `pip install ansible[azure]`" "- {0}".format(HAS_AZURE_EXC, AZURE_MIN_RELEASE)) self._cloud_environment = None self._network_client = None self._storage_client = None self._resource_client = None self._compute_client = None self._dns_client = None self._web_client = None self._containerservice_client = None self._mysql_client = None self._postgresql_client = None self._adfs_authority_url = None self._resource = None self.check_mode = self.module.check_mode self.api_profile = self.module.params.get('api_profile') self.facts_module = facts_module # authenticate self.credentials = self._get_credentials(self.module.params) if not self.credentials: if HAS_AZURE_CLI_CORE: self.fail( "Failed to get credentials. Either pass as parameters, set environment variables, " "define a profile in ~/.azure/credentials, or log in with Azure CLI (`az login`)." ) else: self.fail( "Failed to get credentials. Either pass as parameters, set environment variables, " "define a profile in ~/.azure/credentials, or install Azure CLI and log in (`az login`)." ) # cert validation mode precedence: module-arg, credential profile, env, "validate" self._cert_validation_mode = self.module.params['cert_validation_mode'] or self.credentials.get('cert_validation_mode') or \ os.environ.get('AZURE_CERT_VALIDATION_MODE') or 'validate' if self._cert_validation_mode not in ['validate', 'ignore']: self.fail('invalid cert_validation_mode: {0}'.format( self._cert_validation_mode)) # if cloud_environment specified, look up/build Cloud object raw_cloud_env = self.credentials.get('cloud_environment') if self.credentials.get( 'credentials') is not None and raw_cloud_env is not None: self._cloud_environment = raw_cloud_env elif not raw_cloud_env: self._cloud_environment = azure_cloud.AZURE_PUBLIC_CLOUD # SDK default else: # try to look up "well-known" values via the name attribute on azure_cloud members all_clouds = [ x[1] for x in inspect.getmembers(azure_cloud) if isinstance(x[1], azure_cloud.Cloud) ] matched_clouds = [x for x in all_clouds if x.name == raw_cloud_env] if len(matched_clouds) == 1: self._cloud_environment = matched_clouds[0] elif len(matched_clouds) > 1: self.fail( "Azure SDK failure: more than one cloud matched for cloud_environment name '{0}'" .format(raw_cloud_env)) else: if not urlparse.urlparse(raw_cloud_env).scheme: self.fail( "cloud_environment must be an endpoint discovery URL or one of {0}" .format([x.name for x in all_clouds])) try: self._cloud_environment = azure_cloud.get_cloud_from_metadata_endpoint( raw_cloud_env) except Exception as e: self.fail( "cloud_environment {0} could not be resolved: {1}". format(raw_cloud_env, e.message), exception=traceback.format_exc(e)) if self.credentials.get( 'subscription_id', None) is None and self.credentials.get('credentials') is None: self.fail("Credentials did not include a subscription_id value.") self.log("setting subscription_id") self.subscription_id = self.credentials['subscription_id'] # get authentication authority # for adfs, user could pass in authority or not. # for others, use default authority from cloud environment if self.credentials.get('adfs_authority_url') is None: self._adfs_authority_url = self._cloud_environment.endpoints.active_directory else: self._adfs_authority_url = self.credentials.get( 'adfs_authority_url') # get resource from cloud environment self._resource = self._cloud_environment.endpoints.active_directory_resource_id if self.credentials.get('credentials') is not None: # AzureCLI credentials self.azure_credentials = self.credentials['credentials'] elif self.credentials.get('client_id') is not None and \ self.credentials.get('secret') is not None and \ self.credentials.get('tenant') is not None: self.azure_credentials = ServicePrincipalCredentials( client_id=self.credentials['client_id'], secret=self.credentials['secret'], tenant=self.credentials['tenant'], cloud_environment=self._cloud_environment, verify=self._cert_validation_mode == 'validate') elif self.credentials.get('ad_user') is not None and \ self.credentials.get('password') is not None and \ self.credentials.get('client_id') is not None and \ self.credentials.get('tenant') is not None: self.azure_credentials = self.acquire_token_with_username_password( self._adfs_authority_url, self._resource, self.credentials['ad_user'], self.credentials['password'], self.credentials['client_id'], self.credentials['tenant']) elif self.credentials.get( 'ad_user') is not None and self.credentials.get( 'password') is not None: tenant = self.credentials.get('tenant') if not tenant: tenant = 'common' # SDK default self.azure_credentials = UserPassCredentials( self.credentials['ad_user'], self.credentials['password'], tenant=tenant, cloud_environment=self._cloud_environment, verify=self._cert_validation_mode == 'validate') else: self.fail( "Failed to authenticate with provided credentials. Some attributes were missing. " "Credentials must include client_id, secret and tenant or ad_user and password, or " "ad_user, password, client_id, tenant and adfs_authority_url(optional) for ADFS authentication, or " "be logged in using AzureCLI.") # common parameter validation if self.module.params.get('tags'): self.validate_tags(self.module.params['tags']) if not skip_exec: res = self.exec_module(**self.module.params) self.module.exit_json(**res) def acquire_token_with_username_password(self, authority, resource, username, password, client_id, tenant): authority_uri = authority if tenant is not None: authority_uri = authority + '/' + tenant context = AuthenticationContext(authority_uri) token_response = context.acquire_token_with_username_password( resource, username, password, client_id) return AADTokenCredentials(token_response) def check_client_version(self, client_type): # Ensure Azure modules are at least 2.0.0rc5. package_version = AZURE_PKG_VERSIONS.get(client_type.__name__, None) if package_version is not None: client_name = package_version.get('package_name') try: client_module = importlib.import_module(client_type.__module__) client_version = client_module.VERSION except RuntimeError: # can't get at the module version for some reason, just fail silently... return expected_version = package_version.get('expected_version') if Version(client_version) < Version(expected_version): self.fail( "Installed azure-mgmt-{0} client version is {1}. The minimum supported version is {2}. Try " "`pip install ansible[azure]`".format( client_name, client_version, expected_version)) if Version(client_version) != Version(expected_version): self.module.warn( "Installed azure-mgmt-{0} client version is {1}. The expected version is {2}. Try " "`pip install ansible[azure]`".format( client_name, client_version, expected_version)) def exec_module(self, **kwargs): self.fail("Error: {0} failed to implement exec_module method.".format( self.__class__.__name__)) def fail(self, msg, **kwargs): ''' Shortcut for calling module.fail() :param msg: Error message text. :param kwargs: Any key=value pairs :return: None ''' self.module.fail_json(msg=msg, **kwargs) def deprecate(self, msg, version=None): self.module.deprecate(msg, version) def log(self, msg, pretty_print=False): if pretty_print: self.module.debug(json.dumps(msg, indent=4, sort_keys=True)) else: self.module.debug(msg) def validate_tags(self, tags): ''' Check if tags dictionary contains string:string pairs. :param tags: dictionary of string:string pairs :return: None ''' if not self.facts_module: if not isinstance(tags, dict): self.fail("Tags must be a dictionary of string:string values.") for key, value in tags.items(): if not isinstance(value, str): self.fail( "Tags values must be strings. Found {0}:{1}".format( str(key), str(value))) def update_tags(self, tags): ''' Call from the module to update metadata tags. Returns tuple with bool indicating if there was a change and dict of new tags to assign to the object. :param tags: metadata tags from the object :return: bool, dict ''' new_tags = copy.copy(tags) if isinstance(tags, dict) else dict() param_tags = self.module.params.get('tags') if isinstance( self.module.params.get('tags'), dict) else dict() append_tags = self.module.params.get( 'append_tags') if self.module.params.get( 'append_tags') is not None else True changed = False # check add or update for key, value in param_tags.items(): if not new_tags.get(key) or new_tags[key] != value: changed = True new_tags[key] = value # check remove if not append_tags: for key, value in tags.items(): if not param_tags.get(key): new_tags.pop(key) changed = True return changed, new_tags def has_tags(self, obj_tags, tag_list): ''' Used in fact modules to compare object tags to list of parameter tags. Return true if list of parameter tags exists in object tags. :param obj_tags: dictionary of tags from an Azure object. :param tag_list: list of tag keys or tag key:value pairs :return: bool ''' if not obj_tags and tag_list: return False if not tag_list: return True matches = 0 result = False for tag in tag_list: tag_key = tag tag_value = None if ':' in tag: tag_key, tag_value = tag.split(':') if tag_value and obj_tags.get(tag_key) == tag_value: matches += 1 elif not tag_value and obj_tags.get(tag_key): matches += 1 if matches == len(tag_list): result = True return result def get_resource_group(self, resource_group): ''' Fetch a resource group. :param resource_group: name of a resource group :return: resource group object ''' try: return self.rm_client.resource_groups.get(resource_group) except CloudError as cloud_error: self.fail("Error retrieving resource group {0} - {1}".format( resource_group, cloud_error.message)) except Exception as exc: self.fail("Error retrieving resource group {0} - {1}".format( resource_group, str(exc))) def _get_profile(self, profile="default"): path = expanduser("~/.azure/credentials") try: config = configparser.ConfigParser() config.read(path) except Exception as exc: self.fail( "Failed to access {0}. Check that the file exists and you have read " "access. {1}".format(path, str(exc))) credentials = dict() for key in AZURE_CREDENTIAL_ENV_MAPPING: try: credentials[key] = config.get(profile, key, raw=True) except: pass if credentials.get('subscription_id'): return credentials return None def _get_msi_credentials(self, subscription_id_param=None): credentials = MSIAuthentication() subscription_id = subscription_id_param or os.environ.get( AZURE_CREDENTIAL_ENV_MAPPING['subscription_id'], None) if not subscription_id: try: # use the first subscription of the MSI subscription_client = SubscriptionClient(credentials) subscription = next(subscription_client.subscriptions.list()) subscription_id = str(subscription.subscription_id) except Exception as exc: self.fail( "Failed to get MSI token: {0}. " "Please check whether your machine enabled MSI or grant access to any subscription." .format(str(exc))) return {'credentials': credentials, 'subscription_id': subscription_id} def _get_azure_cli_credentials(self): credentials, subscription_id = get_azure_cli_credentials() cloud_environment = get_cli_active_cloud() cli_credentials = { 'credentials': credentials, 'subscription_id': subscription_id, 'cloud_environment': cloud_environment } return cli_credentials def _get_env_credentials(self): env_credentials = dict() for attribute, env_variable in AZURE_CREDENTIAL_ENV_MAPPING.items(): env_credentials[attribute] = os.environ.get(env_variable, None) if env_credentials['profile']: credentials = self._get_profile(env_credentials['profile']) return credentials if env_credentials.get('subscription_id') is not None: return env_credentials return None def _get_credentials(self, params): # Get authentication credentials. self.log('Getting credentials') arg_credentials = dict() for attribute, env_variable in AZURE_CREDENTIAL_ENV_MAPPING.items(): arg_credentials[attribute] = params.get(attribute, None) auth_source = params.get('auth_source', None) if not auth_source: auth_source = os.environ.get('ANSIBLE_AZURE_AUTH_SOURCE', 'auto') if auth_source == 'msi': self.log('Retrieving credenitals from MSI') return self._get_msi_credentials( arg_credentials['subscription_id']) if auth_source == 'cli': if not HAS_AZURE_CLI_CORE: self.fail( "Azure auth_source is `cli`, but azure-cli package is not available. Try `pip install azure-cli --upgrade`" ) try: self.log('Retrieving credentials from Azure CLI profile') cli_credentials = self._get_azure_cli_credentials() return cli_credentials except CLIError as err: self.fail( "Azure CLI profile cannot be loaded - {0}".format(err)) if auth_source == 'env': self.log('Retrieving credentials from environment') env_credentials = self._get_env_credentials() return env_credentials if auth_source == 'credential_file': self.log("Retrieving credentials from credential file") profile = params.get('profile', 'default') default_credentials = self._get_profile(profile) return default_credentials # auto, precedence: module parameters -> environment variables -> default profile in ~/.azure/credentials # try module params if arg_credentials['profile'] is not None: self.log('Retrieving credentials with profile parameter.') credentials = self._get_profile(arg_credentials['profile']) return credentials if arg_credentials['subscription_id']: self.log('Received credentials from parameters.') return arg_credentials # try environment env_credentials = self._get_env_credentials() if env_credentials: self.log('Received credentials from env.') return env_credentials # try default profile from ~./azure/credentials default_credentials = self._get_profile() if default_credentials: self.log( 'Retrieved default profile credentials from ~/.azure/credentials.' ) return default_credentials try: if HAS_AZURE_CLI_CORE: self.log('Retrieving credentials from AzureCLI profile') cli_credentials = self._get_azure_cli_credentials() return cli_credentials except CLIError as ce: self.log( 'Error getting AzureCLI profile credentials - {0}'.format(ce)) return None def parse_resource_to_dict(self, resource): ''' Return a dict of the give resource, which contains name and resource group. :param resource: It can be a resource name, id or a dict contains name and resource group. ''' resource_dict = parse_resource_id(resource) if not isinstance( resource, dict) else resource resource_dict['resource_group'] = resource_dict.get( 'resource_group', self.resource_group) resource_dict['subscription_id'] = resource_dict.get( 'subscription_id', self.subscription_id) return resource_dict def serialize_obj(self, obj, class_name, enum_modules=None): ''' Return a JSON representation of an Azure object. :param obj: Azure object :param class_name: Name of the object's class :param enum_modules: List of module names to build enum dependencies from. :return: serialized result ''' enum_modules = [] if enum_modules is None else enum_modules dependencies = dict() if enum_modules: for module_name in enum_modules: mod = importlib.import_module(module_name) for mod_class_name, mod_class_obj in inspect.getmembers( mod, predicate=inspect.isclass): dependencies[mod_class_name] = mod_class_obj self.log("dependencies: ") self.log(str(dependencies)) serializer = Serializer(classes=dependencies) return serializer.body(obj, class_name, keep_readonly=True) def get_poller_result(self, poller, wait=5): ''' Consistent method of waiting on and retrieving results from Azure's long poller :param poller Azure poller object :return object resulting from the original request ''' try: delay = wait while not poller.done(): self.log("Waiting for {0} sec".format(delay)) poller.wait(timeout=delay) return poller.result() except Exception as exc: self.log(str(exc)) raise def check_provisioning_state(self, azure_object, requested_state='present'): ''' Check an Azure object's provisioning state. If something did not complete the provisioning process, then we cannot operate on it. :param azure_object An object such as a subnet, storageaccount, etc. Must have provisioning_state and name attributes. :return None ''' if hasattr(azure_object, 'properties') and hasattr(azure_object.properties, 'provisioning_state') and \ hasattr(azure_object, 'name'): # resource group object fits this model if isinstance(azure_object.properties.provisioning_state, Enum): if azure_object.properties.provisioning_state.value != AZURE_SUCCESS_STATE and \ requested_state != 'absent': self.fail( "Error {0} has a provisioning state of {1}. Expecting state to be {2}." .format(azure_object.name, azure_object.properties.provisioning_state, AZURE_SUCCESS_STATE)) return if azure_object.properties.provisioning_state != AZURE_SUCCESS_STATE and \ requested_state != 'absent': self.fail( "Error {0} has a provisioning state of {1}. Expecting state to be {2}." .format(azure_object.name, azure_object.properties.provisioning_state, AZURE_SUCCESS_STATE)) return if hasattr(azure_object, 'provisioning_state') or not hasattr(azure_object, 'name'): if isinstance(azure_object.provisioning_state, Enum): if azure_object.provisioning_state.value != AZURE_SUCCESS_STATE and requested_state != 'absent': self.fail( "Error {0} has a provisioning state of {1}. Expecting state to be {2}." .format(azure_object.name, azure_object.provisioning_state, AZURE_SUCCESS_STATE)) return if azure_object.provisioning_state != AZURE_SUCCESS_STATE and requested_state != 'absent': self.fail( "Error {0} has a provisioning state of {1}. Expecting state to be {2}." .format(azure_object.name, azure_object.provisioning_state, AZURE_SUCCESS_STATE)) def get_blob_client(self, resource_group_name, storage_account_name, storage_blob_type='block'): keys = dict() try: # Get keys from the storage account self.log('Getting keys') account_keys = self.storage_client.storage_accounts.list_keys( resource_group_name, storage_account_name) except Exception as exc: self.fail("Error getting keys for account {0} - {1}".format( storage_account_name, str(exc))) try: self.log('Create blob service') if storage_blob_type == 'page': return CloudStorageAccount( storage_account_name, account_keys.keys[0].value).create_page_blob_service() elif storage_blob_type == 'block': return CloudStorageAccount( storage_account_name, account_keys.keys[0].value).create_block_blob_service() else: raise Exception("Invalid storage blob type defined.") except Exception as exc: self.fail( "Error creating blob service client for storage account {0} - {1}" .format(storage_account_name, str(exc))) def create_default_pip(self, resource_group, location, public_ip_name, allocation_method='Dynamic'): ''' Create a default public IP address <public_ip_name> to associate with a network interface. If a PIP address matching <public_ip_name> exists, return it. Otherwise, create one. :param resource_group: name of an existing resource group :param location: a valid azure location :param public_ip_name: base name to assign the public IP address :param allocation_method: one of 'Static' or 'Dynamic' :return: PIP object ''' pip = None self.log("Starting create_default_pip {0}".format(public_ip_name)) self.log("Check to see if public IP {0} exists".format(public_ip_name)) try: pip = self.network_client.public_ip_addresses.get( resource_group, public_ip_name) except CloudError: pass if pip: self.log("Public ip {0} found.".format(public_ip_name)) self.check_provisioning_state(pip) return pip params = self.network_models.PublicIPAddress( location=location, public_ip_allocation_method=allocation_method, ) self.log('Creating default public IP {0}'.format(public_ip_name)) try: poller = self.network_client.public_ip_addresses.create_or_update( resource_group, public_ip_name, params) except Exception as exc: self.fail("Error creating {0} - {1}".format( public_ip_name, str(exc))) return self.get_poller_result(poller) def create_default_securitygroup(self, resource_group, location, security_group_name, os_type, open_ports): ''' Create a default security group <security_group_name> to associate with a network interface. If a security group matching <security_group_name> exists, return it. Otherwise, create one. :param resource_group: Resource group name :param location: azure location name :param security_group_name: base name to use for the security group :param os_type: one of 'Windows' or 'Linux'. Determins any default rules added to the security group. :param ssh_port: for os_type 'Linux' port used in rule allowing SSH access. :param rdp_port: for os_type 'Windows' port used in rule allowing RDP access. :return: security_group object ''' group = None self.log("Create security group {0}".format(security_group_name)) self.log("Check to see if security group {0} exists".format( security_group_name)) try: group = self.network_client.network_security_groups.get( resource_group, security_group_name) except CloudError: pass if group: self.log("Security group {0} found.".format(security_group_name)) self.check_provisioning_state(group) return group parameters = self.network_models.NetworkSecurityGroup() parameters.location = location if not open_ports: # Open default ports based on OS type if os_type == 'Linux': # add an inbound SSH rule parameters.security_rules = [ self.network_models.SecurityRule( protocol='Tcp', source_address_prefix='*', destination_address_prefix='*', access='Allow', direction='Inbound', description='Allow SSH Access', source_port_range='*', destination_port_range='22', priority=100, name='SSH') ] parameters.location = location else: # for windows add inbound RDP and WinRM rules parameters.security_rules = [ self.network_models.SecurityRule( protocol='Tcp', source_address_prefix='*', destination_address_prefix='*', access='Allow', direction='Inbound', description='Allow RDP port 3389', source_port_range='*', destination_port_range='3389', priority=100, name='RDP01'), self.network_models.SecurityRule( protocol='Tcp', source_address_prefix='*', destination_address_prefix='*', access='Allow', direction='Inbound', description='Allow WinRM HTTPS port 5986', source_port_range='*', destination_port_range='5986', priority=101, name='WinRM01'), ] else: # Open custom ports parameters.security_rules = [] priority = 100 for port in open_ports: priority += 1 rule_name = "Rule_{0}".format(priority) parameters.security_rules.append( self.network_models.SecurityRule( protocol='Tcp', source_address_prefix='*', destination_address_prefix='*', access='Allow', direction='Inbound', source_port_range='*', destination_port_range=str(port), priority=priority, name=rule_name)) self.log( 'Creating default security group {0}'.format(security_group_name)) try: poller = self.network_client.network_security_groups.create_or_update( resource_group, security_group_name, parameters) except Exception as exc: self.fail("Error creating default security rule {0} - {1}".format( security_group_name, str(exc))) return self.get_poller_result(poller) @staticmethod def _validation_ignore_callback(session, global_config, local_config, **kwargs): session.verify = False def get_api_profile(self, client_type_name, api_profile_name): profile_all_clients = AZURE_API_PROFILES.get(api_profile_name) if not profile_all_clients: raise KeyError( "unknown Azure API profile: {0}".format(api_profile_name)) profile_raw = profile_all_clients.get(client_type_name, None) if not profile_raw: self.module.warn( "Azure API profile {0} does not define an entry for {1}". format(api_profile_name, client_type_name)) if isinstance(profile_raw, dict): if not profile_raw.get('default_api_version'): raise KeyError( "Azure API profile {0} does not define 'default_api_version'" .format(api_profile_name)) return profile_raw # wrap basic strings in a dict that just defines the default return dict(default_api_version=profile_raw) def get_mgmt_svc_client(self, client_type, base_url=None, api_version=None): self.log('Getting management service client {0}'.format( client_type.__name__)) self.check_client_version(client_type) client_argspec = inspect.getargspec(client_type.__init__) if not base_url: # most things are resource_manager, don't make everyone specify base_url = self._cloud_environment.endpoints.resource_manager client_kwargs = dict(credentials=self.azure_credentials, subscription_id=self.subscription_id, base_url=base_url) api_profile_dict = {} if self.api_profile: api_profile_dict = self.get_api_profile(client_type.__name__, self.api_profile) # unversioned clients won't accept profile; only send it if necessary # clients without a version specified in the profile will use the default if api_profile_dict and 'profile' in client_argspec.args: client_kwargs['profile'] = api_profile_dict # If the client doesn't accept api_version, it's unversioned. # If it does, favor explicitly-specified api_version, fall back to api_profile if 'api_version' in client_argspec.args: profile_default_version = api_profile_dict.get( 'default_api_version', None) if api_version or profile_default_version: client_kwargs[ 'api_version'] = api_version or profile_default_version if 'profile' in client_kwargs: # remove profile; only pass API version if specified client_kwargs.pop('profile') client = client_type(**client_kwargs) # FUTURE: remove this once everything exposes models directly (eg, containerinstance) try: getattr(client, "models") except AttributeError: def _ansible_get_models(self, *arg, **kwarg): return self._ansible_models setattr(client, '_ansible_models', importlib.import_module(client_type.__module__).models) client.models = types.MethodType(_ansible_get_models, client) # Add user agent for Ansible client.config.add_user_agent(ANSIBLE_USER_AGENT) # Add user agent when running from Cloud Shell if CLOUDSHELL_USER_AGENT_KEY in os.environ: client.config.add_user_agent(os.environ[CLOUDSHELL_USER_AGENT_KEY]) # Add user agent when running from VSCode extension if VSCODEEXT_USER_AGENT_KEY in os.environ: client.config.add_user_agent(os.environ[VSCODEEXT_USER_AGENT_KEY]) if self._cert_validation_mode == 'ignore': client.config.session_configuration_callback = self._validation_ignore_callback return client @property def storage_client(self): self.log('Getting storage client...') if not self._storage_client: self._storage_client = self.get_mgmt_svc_client( StorageManagementClient, base_url=self._cloud_environment.endpoints.resource_manager, api_version='2017-10-01') return self._storage_client @property def storage_models(self): return StorageManagementClient.models("2017-10-01") @property def network_client(self): self.log('Getting network client') if not self._network_client: self._network_client = self.get_mgmt_svc_client( NetworkManagementClient, base_url=self._cloud_environment.endpoints.resource_manager, api_version='2017-11-01') return self._network_client @property def network_models(self): self.log("Getting network models...") return NetworkManagementClient.models("2017-11-01") @property def rm_client(self): self.log('Getting resource manager client') if not self._resource_client: self._resource_client = self.get_mgmt_svc_client( ResourceManagementClient, base_url=self._cloud_environment.endpoints.resource_manager, api_version='2017-05-10') return self._resource_client @property def rm_models(self): self.log("Getting resource manager models") return ResourceManagementClient.models("2017-05-10") @property def compute_client(self): self.log('Getting compute client') if not self._compute_client: self._compute_client = self.get_mgmt_svc_client( ComputeManagementClient, base_url=self._cloud_environment.endpoints.resource_manager, api_version='2017-03-30') return self._compute_client @property def compute_models(self): self.log("Getting compute models") return ComputeManagementClient.models("2017-03-30") @property def dns_client(self): self.log('Getting dns client') if not self._dns_client: self._dns_client = self.get_mgmt_svc_client( DnsManagementClient, base_url=self._cloud_environment.endpoints.resource_manager) return self._dns_client @property def web_client(self): self.log('Getting web client') if not self._web_client: self._web_client = self.get_mgmt_svc_client( WebSiteManagementClient, base_url=self._cloud_environment.endpoints.resource_manager, api_version='2016-08-01') return self._web_client @property def containerservice_client(self): self.log('Getting container service client') if not self._containerservice_client: self._containerservice_client = self.get_mgmt_svc_client( ContainerServiceClient, base_url=self._cloud_environment.endpoints.resource_manager) return self._containerservice_client @property def postgresql_client(self): self.log('Getting PostgreSQL client') if not self._postgresql_client: self._postgresql_client = self.get_mgmt_svc_client( PostgreSQLManagementClient, base_url=self._cloud_environment.endpoints.resource_manager) return self._postgresql_client @property def mysql_client(self): self.log('Getting MySQL client') if not self._mysql_client: self._mysql_client = self.get_mgmt_svc_client( MySQLManagementClient, base_url=self._cloud_environment.endpoints.resource_manager) return self._mysql_client
def main(): argument_spec = ec2_argument_spec() argument_spec.update( dict( bucket=dict(required=True), dest=dict(default=None), encrypt=dict(default=True, type='bool'), expiry=dict(default=600, type='int', aliases=['expiration']), headers=dict(type='dict'), marker=dict(default=""), max_keys=dict(default=1000, type='int'), metadata=dict(type='dict'), mode=dict(choices=['get', 'put', 'delete', 'create', 'geturl', 'getstr', 'delobj', 'list'], required=True), object=dict(), permission=dict(type='list', default=['private']), version=dict(default=None), overwrite=dict(aliases=['force'], default='always'), prefix=dict(default=""), retries=dict(aliases=['retry'], type='int', default=0), s3_url=dict(aliases=['S3_URL']), rgw=dict(default='no', type='bool'), src=dict(), ignore_nonexistent_bucket=dict(default=False, type='bool') ), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) if module._name == 's3': module.deprecate("The 's3' module is being renamed 'aws_s3'", version=2.7) if not HAS_BOTO3: module.fail_json(msg='boto3 and botocore required for this module') bucket = module.params.get('bucket') encrypt = module.params.get('encrypt') expiry = module.params.get('expiry') dest = module.params.get('dest', '') headers = module.params.get('headers') marker = module.params.get('marker') max_keys = module.params.get('max_keys') metadata = module.params.get('metadata') mode = module.params.get('mode') obj = module.params.get('object') version = module.params.get('version') overwrite = module.params.get('overwrite') prefix = module.params.get('prefix') retries = module.params.get('retries') s3_url = module.params.get('s3_url') rgw = module.params.get('rgw') src = module.params.get('src') ignore_nonexistent_bucket = module.params.get('ignore_nonexistent_bucket') if dest: dest = os.path.expanduser(dest) object_canned_acl = ["private", "public-read", "public-read-write", "aws-exec-read", "authenticated-read", "bucket-owner-read", "bucket-owner-full-control"] bucket_canned_acl = ["private", "public-read", "public-read-write", "authenticated-read"] if overwrite not in ['always', 'never', 'different']: if module.boolean(overwrite): overwrite = 'always' else: overwrite = 'never' region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True) if region in ('us-east-1', '', None): # default to US Standard region location = 'us-east-1' else: # Boto uses symbolic names for locations but region strings will # actually work fine for everything except us-east-1 (US Standard) location = region if module.params.get('object'): obj = module.params['object'] # If there is a top level object, do nothing - if the object starts with / # remove the leading character to maintain compatibility with Ansible versions < 2.4 if obj.startswith('/'): obj = obj[1:] # Bucket deletion does not require obj. Prevents ambiguity with delobj. if obj and mode == "delete": module.fail_json(msg='Parameter obj cannot be used with mode=delete') # allow eucarc environment variables to be used if ansible vars aren't set if not s3_url and 'S3_URL' in os.environ: s3_url = os.environ['S3_URL'] # rgw requires an explicit url if rgw and not s3_url: module.fail_json(msg='rgw flavour requires s3_url') # Look at s3_url and tweak connection settings # if connecting to RGW, Walrus or fakes3 for key in ['validate_certs', 'security_token', 'profile_name']: aws_connect_kwargs.pop(key, None) try: s3 = get_s3_connection(module, aws_connect_kwargs, location, rgw, s3_url) except (botocore.exceptions.NoCredentialsError, botocore.exceptions.ProfileNotFound) as e: module.fail_json(msg="Can't authorize connection. Check your credentials and profile.", exceptions=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) validate = not ignore_nonexistent_bucket # separate types of ACLs bucket_acl = [acl for acl in module.params.get('permission') if acl in bucket_canned_acl] object_acl = [acl for acl in module.params.get('permission') if acl in object_canned_acl] error_acl = [acl for acl in module.params.get('permission') if acl not in bucket_canned_acl and acl not in object_canned_acl] if error_acl: module.fail_json(msg='Unknown permission specified: %s' % error_acl) # First, we check to see if the bucket exists, we get "bucket" returned. bucketrtn = bucket_check(module, s3, bucket, validate=validate) if validate and mode not in ('create', 'put', 'delete') and not bucketrtn: module.fail_json(msg="Source bucket cannot be found.") # If our mode is a GET operation (download), go through the procedure as appropriate ... if mode == 'get': # Next, we check to see if the key in the bucket exists. If it exists, it also returns key_matches md5sum check. keyrtn = key_check(module, s3, bucket, obj, version=version, validate=validate) if keyrtn is False: module.fail_json(msg="Key %s with version id %s does not exist." % (obj, version)) # If the destination path doesn't exist or overwrite is True, no need to do the md5um etag check, so just download. # Compare the remote MD5 sum of the object with the local dest md5sum, if it already exists. if path_check(dest): # Determine if the remote and local object are identical if keysum(module, s3, bucket, obj, version=version) == module.md5(dest): sum_matches = True if overwrite == 'always': download_s3file(module, s3, bucket, obj, dest, retries, version=version) else: module.exit_json(msg="Local and remote object are identical, ignoring. Use overwrite=always parameter to force.", changed=False) else: sum_matches = False if overwrite in ('always', 'different'): download_s3file(module, s3, bucket, obj, dest, retries, version=version) else: module.exit_json(msg="WARNING: Checksums do not match. Use overwrite parameter to force download.") else: download_s3file(module, s3, bucket, obj, dest, retries, version=version) # if our mode is a PUT operation (upload), go through the procedure as appropriate ... if mode == 'put': # if putting an object in a bucket yet to be created, acls for the bucket and/or the object may be specified # these were separated into the variables bucket_acl and object_acl above # Lets check the src path. if not path_check(src): module.fail_json(msg="Local object for PUT does not exist") # Lets check to see if bucket exists to get ground truth. if bucketrtn: keyrtn = key_check(module, s3, bucket, obj, version=version, validate=validate) # Lets check key state. Does it exist and if it does, compute the etag md5sum. if bucketrtn and keyrtn: # Compare the local and remote object if module.md5(src) == keysum(module, s3, bucket, obj): sum_matches = True if overwrite == 'always': # only use valid object acls for the upload_s3file function module.params['permission'] = object_acl upload_s3file(module, s3, bucket, obj, src, expiry, metadata, encrypt, headers) else: get_download_url(module, s3, bucket, obj, expiry, changed=False) else: sum_matches = False if overwrite in ('always', 'different'): # only use valid object acls for the upload_s3file function module.params['permission'] = object_acl upload_s3file(module, s3, bucket, obj, src, expiry, metadata, encrypt, headers) else: module.exit_json(msg="WARNING: Checksums do not match. Use overwrite parameter to force upload.") # If neither exist (based on bucket existence), we can create both. if not bucketrtn: # only use valid bucket acls for create_bucket function module.params['permission'] = bucket_acl create_bucket(module, s3, bucket, location) # only use valid object acls for the upload_s3file function module.params['permission'] = object_acl upload_s3file(module, s3, bucket, obj, src, expiry, metadata, encrypt, headers) # If bucket exists but key doesn't, just upload. if bucketrtn and not keyrtn: # only use valid object acls for the upload_s3file function module.params['permission'] = object_acl upload_s3file(module, s3, bucket, obj, src, expiry, metadata, encrypt, headers) # Delete an object from a bucket, not the entire bucket if mode == 'delobj': if obj is None: module.fail_json(msg="object parameter is required") if bucket: deletertn = delete_key(module, s3, bucket, obj) if deletertn is True: module.exit_json(msg="Object deleted from bucket %s." % bucket, changed=True) else: module.fail_json(msg="Bucket parameter is required.") # Delete an entire bucket, including all objects in the bucket if mode == 'delete': if bucket: deletertn = delete_bucket(module, s3, bucket) if deletertn is True: module.exit_json(msg="Bucket %s and all keys have been deleted." % bucket, changed=True) else: module.fail_json(msg="Bucket parameter is required.") # Support for listing a set of keys if mode == 'list': exists = bucket_check(module, s3, bucket) # If the bucket does not exist then bail out if not exists: module.fail_json(msg="Target bucket (%s) cannot be found" % bucket) list_keys(module, s3, bucket, prefix, marker, max_keys) # Need to research how to create directories without "populating" a key, so this should just do bucket creation for now. # WE SHOULD ENABLE SOME WAY OF CREATING AN EMPTY KEY TO CREATE "DIRECTORY" STRUCTURE, AWS CONSOLE DOES THIS. if mode == 'create': # if both creating a bucket and putting an object in it, acls for the bucket and/or the object may be specified # these were separated above into the variables bucket_acl and object_acl if bucket and not obj: if bucketrtn: module.exit_json(msg="Bucket already exists.", changed=False) else: # only use valid bucket acls when creating the bucket module.params['permission'] = bucket_acl module.exit_json(msg="Bucket created successfully", changed=create_bucket(module, s3, bucket, location)) if bucket and obj: if obj.endswith('/'): dirobj = obj else: dirobj = obj + "/" if bucketrtn: if key_check(module, s3, bucket, dirobj): module.exit_json(msg="Bucket %s and key %s already exists." % (bucket, obj), changed=False) else: # setting valid object acls for the create_dirkey function module.params['permission'] = object_acl create_dirkey(module, s3, bucket, dirobj) else: # only use valid bucket acls for the create_bucket function module.params['permission'] = bucket_acl created = create_bucket(module, s3, bucket, location) # only use valid object acls for the create_dirkey function module.params['permission'] = object_acl create_dirkey(module, s3, bucket, dirobj) # Support for grabbing the time-expired URL for an object in S3/Walrus. if mode == 'geturl': if not bucket and not obj: module.fail_json(msg="Bucket and Object parameters must be set") keyrtn = key_check(module, s3, bucket, obj, version=version, validate=validate) if keyrtn: get_download_url(module, s3, bucket, obj, expiry) else: module.fail_json(msg="Key %s does not exist." % obj) if mode == 'getstr': if bucket and obj: keyrtn = key_check(module, s3, bucket, obj, version=version, validate=validate) if keyrtn: download_s3str(module, s3, bucket, obj, version=version) elif version is not None: module.fail_json(msg="Key %s with version id %s does not exist." % (obj, version)) else: module.fail_json(msg="Key %s does not exist." % obj) module.exit_json(failed=False)
def main(): result = {} module = AnsibleModule(argument_spec=dict( category=dict(required=True), command=dict(required=True, type='list'), baseuri=dict(required=True), username=dict(required=True), password=dict(required=True, no_log=True), manager_attribute_name=dict(default=None), manager_attribute_value=dict(default=None), manager_attributes=dict(type='dict', default={}), timeout=dict(type='int', default=10), resource_id=dict()), supports_check_mode=False) category = module.params['category'] command_list = module.params['command'] # admin credentials used for authentication creds = { 'user': module.params['username'], 'pswd': module.params['password'] } # timeout timeout = module.params['timeout'] # System, Manager or Chassis ID to modify resource_id = module.params['resource_id'] # Build root URI root_uri = "https://" + module.params['baseuri'] rf_utils = IdracRedfishUtils(creds, root_uri, timeout, module, resource_id=resource_id, data_modification=True) # Check that Category is valid if category not in CATEGORY_COMMANDS_ALL: module.fail_json( msg=to_native("Invalid Category '%s'. Valid Categories = %s" % (category, CATEGORY_COMMANDS_ALL.keys()))) # Check that all commands are valid for cmd in command_list: # Fail if even one command given is invalid if cmd not in CATEGORY_COMMANDS_ALL[category]: module.fail_json( msg=to_native("Invalid Command '%s'. Valid Commands = %s" % (cmd, CATEGORY_COMMANDS_ALL[category]))) # check for mutually exclusive commands try: # check_mutually_exclusive accepts a single list or list of lists that # are groups of terms that should be mutually exclusive with one another # and checks that against a dictionary check_mutually_exclusive( CATEGORY_COMMANDS_MUTUALLY_EXCLUSIVE[category], dict.fromkeys(command_list, True)) except TypeError as e: module.fail_json(msg=to_native(e)) # Organize by Categories / Commands if category == "Manager": # execute only if we find a Manager resource result = rf_utils._find_managers_resource() if result['ret'] is False: module.fail_json(msg=to_native(result['msg'])) for command in command_list: if command in [ "SetManagerAttributes", "SetLifecycleControllerAttributes", "SetSystemAttributes" ]: result = rf_utils.set_manager_attributes(command) if any((module.params['manager_attribute_name'], module.params['manager_attribute_value'])): module.deprecate(msg='Arguments `manager_attribute_name` and ' '`manager_attribute_value` are deprecated. ' 'Use `manager_attributes` instead for passing in ' 'the manager attribute name and value pairs', version='2.13') # Return data back or fail with proper message if result['ret'] is True: module.exit_json(changed=result['changed'], msg=to_native(result['msg'])) else: module.fail_json(msg=to_native(result['msg']))
def main(): argument_spec = url_argument_spec() # setup aliases argument_spec['url_username']['aliases'] = ['username'] argument_spec['url_password']['aliases'] = ['password'] argument_spec.update( url=dict(type='str', required=True), dest=dict(type='path', required=True), backup=dict(type='bool'), sha256sum=dict(type='str', default=''), checksum=dict(type='str', default=''), timeout=dict(type='int', default=10), headers=dict(type='raw'), tmp_dest=dict(type='path'), ) module = AnsibleModule( # not checking because of daisy chain to file module argument_spec=argument_spec, add_file_common_args=True, supports_check_mode=True, mutually_exclusive=[['checksum', 'sha256sum']], ) url = module.params['url'] dest = module.params['dest'] backup = module.params['backup'] force = module.params['force'] sha256sum = module.params['sha256sum'] checksum = module.params['checksum'] use_proxy = module.params['use_proxy'] timeout = module.params['timeout'] tmp_dest = module.params['tmp_dest'] result = dict( changed=False, checksum_dest=None, checksum_src=None, dest=dest, elapsed=0, url=url, ) # Parse headers to dict if isinstance(module.params['headers'], dict): headers = module.params['headers'] elif module.params['headers']: try: headers = dict(item.split(':', 1) for item in module.params['headers'].split(',')) module.deprecate('Supplying `headers` as a string is deprecated. Please use dict/hash format for `headers`', version='2.10') except Exception: module.fail_json(msg="The string representation for the `headers` parameter requires a key:value,key:value syntax to be properly parsed.", **result) else: headers = None dest_is_dir = os.path.isdir(dest) last_mod_time = None # workaround for usage of deprecated sha256sum parameter if sha256sum: checksum = 'sha256:%s' % (sha256sum) # checksum specified, parse for algorithm and checksum if checksum: try: algorithm, checksum = checksum.split(':', 1) if checksum.startswith('http://') or checksum.startswith('https://') or checksum.startswith('ftp://'): checksum_url = checksum # download checksum file to checksum_tmpsrc checksum_tmpsrc, checksum_info = url_get(module, checksum_url, dest, use_proxy, last_mod_time, force, timeout, headers, tmp_dest) with open(checksum_tmpsrc) as f: lines = [line.rstrip('\n') for line in f] os.remove(checksum_tmpsrc) lines = dict(s.split(None, 1) for s in lines) filename = url_filename(url) # Look through each line in the checksum file for a hash corresponding to # the filename in the url, returning the first hash that is found. for cksum in (s for (s, f) in lines.items() if f.strip('./') == filename): checksum = cksum break else: checksum = None if checksum is None: module.fail_json(msg="Unable to find a checksum for file '%s' in '%s'" % (filename, checksum_url)) # Remove any non-alphanumeric characters, including the infamous # Unicode zero-width space checksum = re.sub(r'\W+', '', checksum).lower() # Ensure the checksum portion is a hexdigest int(checksum, 16) except ValueError: module.fail_json(msg="The checksum parameter has to be in format <algorithm>:<checksum>", **result) if not dest_is_dir and os.path.exists(dest): checksum_mismatch = False # If the download is not forced and there is a checksum, allow # checksum match to skip the download. if not force and checksum != '': destination_checksum = module.digest_from_file(dest, algorithm) if checksum != destination_checksum: checksum_mismatch = True # Not forcing redownload, unless checksum does not match if not force and not checksum_mismatch: # Not forcing redownload, unless checksum does not match # allow file attribute changes module.params['path'] = dest file_args = module.load_file_common_arguments(module.params) file_args['path'] = dest result['changed'] = module.set_fs_attributes_if_different(file_args, False) if result['changed']: module.exit_json(msg="file already exists but file attributes changed", **result) module.exit_json(msg="file already exists", **result) # If the file already exists, prepare the last modified time for the # request. mtime = os.path.getmtime(dest) last_mod_time = datetime.datetime.utcfromtimestamp(mtime) # If the checksum does not match we have to force the download # because last_mod_time may be newer than on remote if checksum_mismatch: force = True # download to tmpsrc start = datetime.datetime.utcnow() tmpsrc, info = url_get(module, url, dest, use_proxy, last_mod_time, force, timeout, headers, tmp_dest) result['elapsed'] = (datetime.datetime.utcnow() - start).seconds result['src'] = tmpsrc # Now the request has completed, we can finally generate the final # destination file name from the info dict. if dest_is_dir: filename = extract_filename_from_headers(info) if not filename: # Fall back to extracting the filename from the URL. # Pluck the URL from the info, since a redirect could have changed # it. filename = url_filename(info['url']) dest = os.path.join(dest, filename) # If the remote URL exists, we're done with check mode if module.check_mode: os.remove(tmpsrc) result['changed'] = True module.exit_json(msg=info.get('msg', ''), **result) # raise an error if there is no tmpsrc file if not os.path.exists(tmpsrc): os.remove(tmpsrc) module.fail_json(msg="Request failed", status_code=info['status'], response=info['msg'], **result) if not os.access(tmpsrc, os.R_OK): os.remove(tmpsrc) module.fail_json(msg="Source %s is not readable" % (tmpsrc), **result) result['checksum_src'] = module.sha1(tmpsrc) # check if there is no dest file if os.path.exists(dest): # raise an error if copy has no permission on dest if not os.access(dest, os.W_OK): os.remove(tmpsrc) module.fail_json(msg="Destination %s is not writable" % (dest), **result) if not os.access(dest, os.R_OK): os.remove(tmpsrc) module.fail_json(msg="Destination %s is not readable" % (dest), **result) result['checksum_dest'] = module.sha1(dest) else: if not os.path.exists(os.path.dirname(dest)): os.remove(tmpsrc) module.fail_json(msg="Destination %s does not exist" % (os.path.dirname(dest)), **result) if not os.access(os.path.dirname(dest), os.W_OK): os.remove(tmpsrc) module.fail_json(msg="Destination %s is not writable" % (os.path.dirname(dest)), **result) backup_file = None if result['checksum_src'] != result['checksum_dest']: try: if backup: if os.path.exists(dest): backup_file = module.backup_local(dest) module.atomic_move(tmpsrc, dest) except Exception as e: if os.path.exists(tmpsrc): os.remove(tmpsrc) module.fail_json(msg="failed to copy %s to %s: %s" % (tmpsrc, dest, to_native(e)), exception=traceback.format_exc(), **result) result['changed'] = True else: result['changed'] = False if os.path.exists(tmpsrc): os.remove(tmpsrc) if checksum != '': destination_checksum = module.digest_from_file(dest, algorithm) if checksum != destination_checksum: os.remove(dest) module.fail_json(msg="The checksum for %s did not match %s; it was %s." % (dest, checksum, destination_checksum), **result) # allow file attribute changes module.params['path'] = dest file_args = module.load_file_common_arguments(module.params) file_args['path'] = dest result['changed'] = module.set_fs_attributes_if_different(file_args, result['changed']) # Backwards compat only. We'll return None on FIPS enabled systems try: result['md5sum'] = module.md5(dest) except ValueError: result['md5sum'] = None if backup_file: result['backup_file'] = backup_file # Mission complete module.exit_json(msg=info.get('msg', ''), status_code=info.get('status', ''), **result)
def main(): argument_spec = url_argument_spec() argument_spec.update( dest=dict(type='path'), url_username=dict(type='str', aliases=['user']), url_password=dict(type='str', aliases=['password'], no_log=True), body=dict(type='raw'), body_format=dict(type='str', default='raw', choices=['form-urlencoded', 'json', 'raw']), src=dict(type='path'), method=dict(type='str', default='GET', choices=['CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'PATCH', 'POST', 'PUT', 'REFRESH', 'TRACE']), return_content=dict(type='bool', default=False), follow_redirects=dict(type='str', default='safe', choices=['all', 'no', 'none', 'safe', 'urllib2', 'yes']), creates=dict(type='path'), removes=dict(type='path'), status_code=dict(type='list', default=[200]), timeout=dict(type='int', default=30), headers=dict(type='dict', default={}), unix_socket=dict(type='path'), ) module = AnsibleModule( argument_spec=argument_spec, # TODO: Remove check_invalid_arguments in 2.9 check_invalid_arguments=False, add_file_common_args=True, mutually_exclusive=[['body', 'src']], ) url = module.params['url'] body = module.params['body'] body_format = module.params['body_format'].lower() method = module.params['method'] dest = module.params['dest'] return_content = module.params['return_content'] creates = module.params['creates'] removes = module.params['removes'] status_code = [int(x) for x in list(module.params['status_code'])] socket_timeout = module.params['timeout'] dict_headers = module.params['headers'] if body_format == 'json': # Encode the body unless its a string, then assume it is pre-formatted JSON if not isinstance(body, string_types): body = json.dumps(body) if 'content-type' not in [header.lower() for header in dict_headers]: dict_headers['Content-Type'] = 'application/json' elif body_format == 'form-urlencoded': if not isinstance(body, string_types): try: body = form_urlencoded(body) except ValueError as e: module.fail_json(msg='failed to parse body as form_urlencoded: %s' % to_native(e), elapsed=0) if 'content-type' not in [header.lower() for header in dict_headers]: dict_headers['Content-Type'] = 'application/x-www-form-urlencoded' # TODO: Deprecated section. Remove in Ansible 2.9 # Grab all the http headers. Need this hack since passing multi-values is # currently a bit ugly. (e.g. headers='{"Content-Type":"application/json"}') for key, value in iteritems(module.params): if key.startswith("HEADER_"): module.deprecate('Supplying headers via HEADER_* is deprecated. Please use `headers` to' ' supply headers for the request', version='2.9') skey = key.replace("HEADER_", "") dict_headers[skey] = value # End deprecated section if creates is not None: # do not run the command if the line contains creates=filename # and the filename already exists. This allows idempotence # of uri executions. if os.path.exists(creates): module.exit_json(stdout="skipped, since '%s' exists" % creates, changed=False) if removes is not None: # do not run the command if the line contains removes=filename # and the filename does not exist. This allows idempotence # of uri executions. if not os.path.exists(removes): module.exit_json(stdout="skipped, since '%s' does not exist" % removes, changed=False) # Make the request start = datetime.datetime.utcnow() resp, content, dest = uri(module, url, dest, body, body_format, method, dict_headers, socket_timeout) resp['elapsed'] = (datetime.datetime.utcnow() - start).seconds resp['status'] = int(resp['status']) # Write the file out if requested if dest is not None: if resp['status'] == 304: resp['changed'] = False else: write_file(module, url, dest, content, resp) # allow file attribute changes resp['changed'] = True module.params['path'] = dest file_args = module.load_file_common_arguments(module.params) file_args['path'] = dest resp['changed'] = module.set_fs_attributes_if_different(file_args, resp['changed']) resp['path'] = dest else: resp['changed'] = False # Transmogrify the headers, replacing '-' with '_', since variables don't # work with dashes. # In python3, the headers are title cased. Lowercase them to be # compatible with the python2 behaviour. uresp = {} for key, value in iteritems(resp): ukey = key.replace("-", "_").lower() uresp[ukey] = value if 'location' in uresp: uresp['location'] = absolute_location(url, uresp['location']) # Default content_encoding to try content_encoding = 'utf-8' if 'content_type' in uresp: content_type, params = cgi.parse_header(uresp['content_type']) if 'charset' in params: content_encoding = params['charset'] u_content = to_text(content, encoding=content_encoding) if any(candidate in content_type for candidate in JSON_CANDIDATES): try: js = json.loads(u_content) uresp['json'] = js except Exception: if PY2: sys.exc_clear() # Avoid false positive traceback in fail_json() on Python 2 else: u_content = to_text(content, encoding=content_encoding) if resp['status'] not in status_code: uresp['msg'] = 'Status code was %s and not %s: %s' % (resp['status'], status_code, uresp.get('msg', '')) module.fail_json(content=u_content, **uresp) elif return_content: module.exit_json(content=u_content, **uresp) else: module.exit_json(**uresp)
def main(): module = AnsibleModule( argument_spec=dict( state=dict(type='str', default='present', choices=['present', 'absent']), size=dict(type='int', default=4096), type=dict(type='str', default='RSA', choices=[ 'DSA', 'ECC', 'Ed25519', 'Ed448', 'RSA', 'X25519', 'X448' ]), curve=dict(type='str', choices=[ 'secp384r1', 'secp521r1', 'secp224r1', 'secp192r1', 'secp256r1', 'secp256k1', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1', 'sect571k1', 'sect409k1', 'sect283k1', 'sect233k1', 'sect163k1', 'sect571r1', 'sect409r1', 'sect283r1', 'sect233r1', 'sect163r2', ]), force=dict(type='bool', default=False), path=dict(type='path', required=True), passphrase=dict(type='str', no_log=True), cipher=dict(type='str'), backup=dict(type='bool', default=False), format=dict(type='str', default='auto_ignore', choices=['pkcs1', 'pkcs8', 'raw', 'auto', 'auto_ignore']), format_mismatch=dict(type='str', default='regenerate', choices=['regenerate', 'convert']), select_crypto_backend=dict(type='str', choices=['auto', 'pyopenssl', 'cryptography'], default='auto'), return_content=dict(type='bool', default=False), regenerate=dict( type='str', default='full_idempotence', choices=['never', 'fail', 'partial_idempotence', 'full_idempotence', 'always'] ), ), supports_check_mode=True, add_file_common_args=True, required_together=[ ['cipher', 'passphrase'] ], required_if=[ ['type', 'ECC', ['curve']], ], ) base_dir = os.path.dirname(module.params['path']) or '.' if not os.path.isdir(base_dir): module.fail_json( name=base_dir, msg='The directory %s does not exist or the file is not a directory' % base_dir ) backend = module.params['select_crypto_backend'] if backend == 'auto': # Detection what is possible can_use_cryptography = CRYPTOGRAPHY_FOUND and CRYPTOGRAPHY_VERSION >= LooseVersion(MINIMAL_CRYPTOGRAPHY_VERSION) can_use_pyopenssl = PYOPENSSL_FOUND and PYOPENSSL_VERSION >= LooseVersion(MINIMAL_PYOPENSSL_VERSION) # Decision if module.params['cipher'] and module.params['passphrase'] and module.params['cipher'] != 'auto': # First try pyOpenSSL, then cryptography if can_use_pyopenssl: backend = 'pyopenssl' elif can_use_cryptography: backend = 'cryptography' else: # First try cryptography, then pyOpenSSL if can_use_cryptography: backend = 'cryptography' elif can_use_pyopenssl: backend = 'pyopenssl' # Success? if backend == 'auto': module.fail_json(msg=("Can't detect any of the required Python libraries " "cryptography (>= {0}) or PyOpenSSL (>= {1})").format( MINIMAL_CRYPTOGRAPHY_VERSION, MINIMAL_PYOPENSSL_VERSION)) try: if backend == 'pyopenssl': if not PYOPENSSL_FOUND: module.fail_json(msg=missing_required_lib('pyOpenSSL >= {0}'.format(MINIMAL_PYOPENSSL_VERSION)), exception=PYOPENSSL_IMP_ERR) module.deprecate('The module is using the PyOpenSSL backend. This backend has been deprecated', version='2.13') private_key = PrivateKeyPyOpenSSL(module) elif backend == 'cryptography': if not CRYPTOGRAPHY_FOUND: module.fail_json(msg=missing_required_lib('cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION)), exception=CRYPTOGRAPHY_IMP_ERR) private_key = PrivateKeyCryptography(module) if private_key.state == 'present': if module.check_mode: result = private_key.dump() result['changed'] = private_key.force \ or not private_key.check(module, ignore_conversion=True) \ or not private_key.check(module, ignore_conversion=False) module.exit_json(**result) private_key.generate(module) else: if module.check_mode: result = private_key.dump() result['changed'] = os.path.exists(module.params['path']) module.exit_json(**result) private_key.remove(module) result = private_key.dump() module.exit_json(**result) except OpenSSLObjectError as exc: module.fail_json(msg=to_native(exc))
def main(): helper = get_connection( vsys_importable=True, template=True, with_classic_provider_spec=True, with_state=True, min_pandevice_version=(0, 8, 0), argument_spec=dict( if_name=dict(required=True), ip=dict(type='list', elements='str'), ipv6_enabled=dict(type='bool'), management_profile=dict(), mtu=dict(type='int'), netflow_profile=dict(), comment=dict(), zone_name=dict(), vr_name=dict(), commit=dict(type='bool', default=False), # TODO(gfreeman) - remove this in 2.12 vsys_dg=dict(), ), ) module = AnsibleModule( argument_spec=helper.argument_spec, supports_check_mode=True, required_one_of=helper.required_one_of, ) # Get the object params. spec = { 'name': module.params['if_name'], 'ip': module.params['ip'], 'ipv6_enabled': module.params['ipv6_enabled'], 'management_profile': module.params['management_profile'], 'mtu': module.params['mtu'], 'netflow_profile': module.params['netflow_profile'], 'comment': module.params['comment'], } # Get other info. state = module.params['state'] zone_name = module.params['zone_name'] vr_name = module.params['vr_name'] vsys = module.params['vsys'] vsys_dg = module.params['vsys_dg'] commit = module.params['commit'] # TODO(gfreeman) - Remove vsys_dg in 2.12, as well as this code chunk. # In the mean time, we'll need to do this special handling. if vsys_dg is not None: module.deprecate('Param "vsys_dg" is deprecated, use "vsys"', version='3.0.0', collection_name='paloaltonetworks.panos') if vsys is None: vsys = vsys_dg else: msg = [ 'Params "vsys" and "vsys_dg" both given', 'Specify one or the other, not both.', ] module.fail_json(msg='. '.join(msg)) elif vsys is None: # TODO(gfreeman) - v2.12, just set the default for vsys to 'vsys1'. vsys = 'vsys1' # Make sure 'vsys' is set appropriately. module.params['vsys'] = vsys # Verify libs are present, get the parent object. parent = helper.get_pandevice_parent(module) # Retrieve the current config. try: interfaces = TunnelInterface.refreshall(parent, add=False, matching_vsys=False) except PanDeviceError as e: module.fail_json(msg='Failed refresh: {0}'.format(e)) # Build the object based on the user spec. obj = TunnelInterface(**spec) parent.add(obj) # Which action should we take on the interface? changed = False diff = None reference_params = { 'refresh': True, 'update': not module.check_mode, 'return_type': 'bool', } if state == 'present': for item in interfaces: if item.name != obj.name: continue diff = dict(before=eltostr(item)) # Interfaces have children, so don't compare them. if not item.equal(obj, compare_children=False): changed = True obj.extend(item.children) diff['after'] = eltostr(obj) if not module.check_mode: try: obj.apply() except PanDeviceError as e: module.fail_json(msg='Failed apply: {0}'.format(e)) break else: changed = True diff = dict(before="", after=eltostr(obj)) if not module.check_mode: try: obj.create() except PanDeviceError as e: module.fail_json(msg='Failed create: {0}'.format(e)) # Set references. try: changed |= obj.set_vsys(vsys, **reference_params) changed |= obj.set_zone(zone_name, mode='layer3', **reference_params) changed |= obj.set_virtual_router(vr_name, **reference_params) except PanDeviceError as e: module.fail_json(msg='Failed setref: {0}'.format(e)) elif state == 'absent': # Remove references. try: changed |= obj.set_virtual_router(None, **reference_params) changed |= obj.set_zone(None, mode='layer3', **reference_params) changed |= obj.set_vsys(None, **reference_params) except PanDeviceError as e: module.fail_json(msg='Failed setref: {0}'.format(e)) # Remove the interface. if obj.name in [x.name for x in interfaces]: changed = True diff = dict(before=eltostr(obj), after="") if not module.check_mode: try: obj.delete() except PanDeviceError as e: module.fail_json(msg='Failed delete: {0}'.format(e)) # Commit if we were asked to do so. if changed and commit: helper.commit(module) # Done! module.exit_json(changed=changed, diff=diff, msg='Done')
def main(): argument_spec = openstack_full_argument_spec( server=dict(required=True), action=dict(required=True, choices=['stop', 'start', 'pause', 'unpause', 'lock', 'unlock', 'suspend', 'resume', 'rebuild']), image=dict(required=False), ) module_kwargs = openstack_module_kwargs() module = AnsibleModule(argument_spec, supports_check_mode=True, required_if=[('action', 'rebuild', ['image'])], **module_kwargs) if module._name == 'os_server_actions': module.deprecate("The 'os_server_actions' module is being renamed 'os_server_action'", version=2.8) action = module.params['action'] wait = module.params['wait'] timeout = module.params['timeout'] image = module.params['image'] if action in _admin_actions: shade, cloud = openstack_cloud_from_module(module) else: shade, cloud = openstack_cloud_from_module(module) try: server = cloud.get_server(module.params['server']) if not server: module.fail_json(msg='Could not find server %s' % server) status = server.status if module.check_mode: module.exit_json(changed=_system_state_change(action, status)) if action == 'stop': if not _system_state_change(action, status): module.exit_json(changed=False) cloud.nova_client.servers.stop(server=server.id) if wait: _wait(timeout, cloud, server, action, module, shade) module.exit_json(changed=True) if action == 'start': if not _system_state_change(action, status): module.exit_json(changed=False) cloud.nova_client.servers.start(server=server.id) if wait: _wait(timeout, cloud, server, action, module, shade) module.exit_json(changed=True) if action == 'pause': if not _system_state_change(action, status): module.exit_json(changed=False) cloud.nova_client.servers.pause(server=server.id) if wait: _wait(timeout, cloud, server, action, module, shade) module.exit_json(changed=True) elif action == 'unpause': if not _system_state_change(action, status): module.exit_json(changed=False) cloud.nova_client.servers.unpause(server=server.id) if wait: _wait(timeout, cloud, server, action, module, shade) module.exit_json(changed=True) elif action == 'lock': # lock doesn't set a state, just do it cloud.nova_client.servers.lock(server=server.id) module.exit_json(changed=True) elif action == 'unlock': # unlock doesn't set a state, just do it cloud.nova_client.servers.unlock(server=server.id) module.exit_json(changed=True) elif action == 'suspend': if not _system_state_change(action, status): module.exit_json(changed=False) cloud.nova_client.servers.suspend(server=server.id) if wait: _wait(timeout, cloud, server, action, module, shade) module.exit_json(changed=True) elif action == 'resume': if not _system_state_change(action, status): module.exit_json(changed=False) cloud.nova_client.servers.resume(server=server.id) if wait: _wait(timeout, cloud, server, action, module, shade) module.exit_json(changed=True) elif action == 'rebuild': image = cloud.get_image(image) if image is None: module.fail_json(msg="Image does not exist") # rebuild doesn't set a state, just do it cloud.nova_client.servers.rebuild(server=server.id, image=image.id) if wait: _wait(timeout, cloud, server, action, module, shade) module.exit_json(changed=True) except shade.OpenStackCloudException as e: module.fail_json(msg=str(e), extra_data=e.extra_data)
def main(): module = AnsibleModule( argument_spec=dict( name=dict(type='list', aliases=['pkg', 'package']), state=dict(type='str', default='present', choices=[ 'present', 'installed', 'latest', 'absent', 'removed' ]), recurse=dict(type='bool', default=False), force=dict(type='bool', default=False), extra_args=dict(type='str', default=''), upgrade=dict(type='bool', default=False), upgrade_extra_args=dict(type='str', default=''), update_cache=dict(type='bool', default=False, aliases=['update-cache']), update_cache_extra_args=dict(type='str', default=''), ), required_one_of=[['name', 'update_cache', 'upgrade']], supports_check_mode=True, ) pacman_path = module.get_bin_path('pacman', True) p = module.params # normalize the state parameter if p['state'] in ['present', 'installed']: p['state'] = 'present' elif p['state'] in ['absent', 'removed']: p['state'] = 'absent' if p['recurse']: module.deprecate( 'Option `recurse` is deprecated and will be removed in ' 'version 2.10. Please use `extra_args=--recursive` ' 'instead', '2.10') if p['state'] == 'absent': p['extra_args'] += " --recursive" if p["update_cache"] and not module.check_mode: update_package_db(module, pacman_path) if not (p['name'] or p['upgrade']): module.exit_json(changed=True, msg='Updated the package master lists') if p['update_cache'] and module.check_mode and not (p['name'] or p['upgrade']): module.exit_json(changed=True, msg='Would have updated the package cache') if p['upgrade']: upgrade(module, pacman_path) if p['name']: pkgs = expand_package_groups(module, pacman_path, p['name']) pkg_files = [] for i, pkg in enumerate(pkgs): if not pkg: # avoid empty strings continue elif re.match(r".*\.pkg\.tar(\.(gz|bz2|xz|lrz|lzo|Z))?$", pkg): # The package given is a filename, extract the raw pkg name from # it and store the filename pkg_files.append(pkg) pkgs[i] = re.sub(r'-[0-9].*$', '', pkgs[i].split('/')[-1]) else: pkg_files.append(None) if module.check_mode: check_packages(module, pacman_path, pkgs, p['state']) if p['state'] in ['present', 'latest']: install_packages(module, pacman_path, p['state'], pkgs, pkg_files) elif p['state'] == 'absent': remove_packages(module, pacman_path, pkgs)
def main(): argument_spec = url_argument_spec() # setup aliases argument_spec['url_username']['aliases'] = ['username'] argument_spec['url_password']['aliases'] = ['password'] argument_spec.update( url=dict(type='str', required=True), dest=dict(type='path', required=True), backup=dict(type='bool', default=False), sha256sum=dict(type='str', default=''), checksum=dict(type='str', default=''), timeout=dict(type='int', default=10), headers=dict(type='dict'), tmp_dest=dict(type='path'), unredirected_headers=dict(type='list', elements='str', default=[]), ) module = AnsibleModule( # not checking because of daisy chain to file module argument_spec=argument_spec, add_file_common_args=True, supports_check_mode=True, mutually_exclusive=[['checksum', 'sha256sum']], ) if module.params.get('sha256sum'): module.deprecate( 'The parameter "sha256sum" has been deprecated and will be removed, use "checksum" instead', version='2.14', collection_name='ansible.builtin') url = module.params['url'] dest = module.params['dest'] backup = module.params['backup'] force = module.params['force'] sha256sum = module.params['sha256sum'] checksum = module.params['checksum'] use_proxy = module.params['use_proxy'] timeout = module.params['timeout'] headers = module.params['headers'] tmp_dest = module.params['tmp_dest'] unredirected_headers = module.params['unredirected_headers'] result = dict( changed=False, checksum_dest=None, checksum_src=None, dest=dest, elapsed=0, url=url, ) dest_is_dir = os.path.isdir(dest) last_mod_time = None # workaround for usage of deprecated sha256sum parameter if sha256sum: checksum = 'sha256:%s' % (sha256sum) # checksum specified, parse for algorithm and checksum if checksum: try: algorithm, checksum = checksum.split(':', 1) except ValueError: module.fail_json( msg= "The checksum parameter has to be in format <algorithm>:<checksum>", **result) if is_url(checksum): checksum_url = checksum # download checksum file to checksum_tmpsrc checksum_tmpsrc, checksum_info = url_get( module, checksum_url, dest, use_proxy, last_mod_time, force, timeout, headers, tmp_dest, unredirected_headers=unredirected_headers) with open(checksum_tmpsrc) as f: lines = [line.rstrip('\n') for line in f] os.remove(checksum_tmpsrc) checksum_map = [] for line in lines: # Split by one whitespace to keep the leading type char ' ' (whitespace) for text and '*' for binary parts = line.split(" ", 1) if len(parts) == 2: # Remove the leading type char, we expect if parts[1].startswith(( " ", "*", )): parts[1] = parts[1][1:] # Append checksum and path without potential leading './' checksum_map.append((parts[0], parts[1].lstrip("./"))) filename = url_filename(url) # Look through each line in the checksum file for a hash corresponding to # the filename in the url, returning the first hash that is found. for cksum in (s for (s, f) in checksum_map if f == filename): checksum = cksum break else: checksum = None if checksum is None: module.fail_json( msg="Unable to find a checksum for file '%s' in '%s'" % (filename, checksum_url)) # Remove any non-alphanumeric characters, including the infamous # Unicode zero-width space checksum = re.sub(r'\W+', '', checksum).lower() # Ensure the checksum portion is a hexdigest try: int(checksum, 16) except ValueError: module.fail_json(msg='The checksum format is invalid', **result) if not dest_is_dir and os.path.exists(dest): checksum_mismatch = False # If the download is not forced and there is a checksum, allow # checksum match to skip the download. if not force and checksum != '': destination_checksum = module.digest_from_file(dest, algorithm) if checksum != destination_checksum: checksum_mismatch = True # Not forcing redownload, unless checksum does not match if not force and checksum and not checksum_mismatch: # Not forcing redownload, unless checksum does not match # allow file attribute changes file_args = module.load_file_common_arguments(module.params, path=dest) result['changed'] = module.set_fs_attributes_if_different( file_args, False) if result['changed']: module.exit_json( msg="file already exists but file attributes changed", **result) module.exit_json(msg="file already exists", **result) # If the file already exists, prepare the last modified time for the # request. mtime = os.path.getmtime(dest) last_mod_time = datetime.datetime.utcfromtimestamp(mtime) # If the checksum does not match we have to force the download # because last_mod_time may be newer than on remote if checksum_mismatch: force = True # download to tmpsrc start = datetime.datetime.utcnow() method = 'HEAD' if module.check_mode else 'GET' tmpsrc, info = url_get(module, url, dest, use_proxy, last_mod_time, force, timeout, headers, tmp_dest, method, unredirected_headers=unredirected_headers) result['elapsed'] = (datetime.datetime.utcnow() - start).seconds result['src'] = tmpsrc # Now the request has completed, we can finally generate the final # destination file name from the info dict. if dest_is_dir: filename = extract_filename_from_headers(info) if not filename: # Fall back to extracting the filename from the URL. # Pluck the URL from the info, since a redirect could have changed # it. filename = url_filename(info['url']) dest = os.path.join(dest, filename) result['dest'] = dest # raise an error if there is no tmpsrc file if not os.path.exists(tmpsrc): os.remove(tmpsrc) module.fail_json(msg="Request failed", status_code=info['status'], response=info['msg'], **result) if not os.access(tmpsrc, os.R_OK): os.remove(tmpsrc) module.fail_json(msg="Source %s is not readable" % (tmpsrc), **result) result['checksum_src'] = module.sha1(tmpsrc) # check if there is no dest file if os.path.exists(dest): # raise an error if copy has no permission on dest if not os.access(dest, os.W_OK): os.remove(tmpsrc) module.fail_json(msg="Destination %s is not writable" % (dest), **result) if not os.access(dest, os.R_OK): os.remove(tmpsrc) module.fail_json(msg="Destination %s is not readable" % (dest), **result) result['checksum_dest'] = module.sha1(dest) else: if not os.path.exists(os.path.dirname(dest)): os.remove(tmpsrc) module.fail_json(msg="Destination %s does not exist" % (os.path.dirname(dest)), **result) if not os.access(os.path.dirname(dest), os.W_OK): os.remove(tmpsrc) module.fail_json(msg="Destination %s is not writable" % (os.path.dirname(dest)), **result) if module.check_mode: if os.path.exists(tmpsrc): os.remove(tmpsrc) result['changed'] = ('checksum_dest' not in result or result['checksum_src'] != result['checksum_dest']) module.exit_json(msg=info.get('msg', ''), **result) backup_file = None if result['checksum_src'] != result['checksum_dest']: try: if backup: if os.path.exists(dest): backup_file = module.backup_local(dest) module.atomic_move(tmpsrc, dest, unsafe_writes=module.params['unsafe_writes']) except Exception as e: if os.path.exists(tmpsrc): os.remove(tmpsrc) module.fail_json(msg="failed to copy %s to %s: %s" % (tmpsrc, dest, to_native(e)), exception=traceback.format_exc(), **result) result['changed'] = True else: result['changed'] = False if os.path.exists(tmpsrc): os.remove(tmpsrc) if checksum != '': destination_checksum = module.digest_from_file(dest, algorithm) if checksum != destination_checksum: os.remove(dest) module.fail_json( msg="The checksum for %s did not match %s; it was %s." % (dest, checksum, destination_checksum), **result) # allow file attribute changes file_args = module.load_file_common_arguments(module.params, path=dest) result['changed'] = module.set_fs_attributes_if_different( file_args, result['changed']) # Backwards compat only. We'll return None on FIPS enabled systems try: result['md5sum'] = module.md5(dest) except ValueError: result['md5sum'] = None if backup_file: result['backup_file'] = backup_file # Mission complete module.exit_json(msg=info.get('msg', ''), status_code=info.get('status', ''), **result)
def main(): argument_spec = dict( ip_address=dict(required=True), password=dict(no_log=True), username=dict(default='admin'), api_key=dict(no_log=True), rule_name=dict(required=True), description=dict(default=''), tag=dict(), to_zone=dict(type='list', default=['any']), from_zone=dict(type='list', default=['any']), source=dict(type='list', default=["any"]), source_user=dict(type='list', default=['any']), destination=dict(type='list', default=["any"]), category=dict(type='list', default=['any']), application=dict(type='list', default=['any']), service=dict(type='list', default=['application-default']), hip_profiles=dict(type='list', default=['any']), group_profile=dict(), antivirus=dict(), vulnerability=dict(), spyware=dict(), url_filtering=dict(), file_blocking=dict(), data_filtering=dict(), wildfire_analysis=dict(), log_start=dict(type='bool', default=False), log_end=dict(type='bool', default=True), rule_type=dict(default='universal'), action=dict(default='allow'), devicegroup=dict(), commit=dict(type='bool', default=True) ) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, required_one_of=[['api_key', 'password']]) if module._name == 'panos_security_policy': module.deprecate("The 'panos_security_policy' module is being renamed 'panos_security_rule'", version=2.8) if not HAS_LIB: module.fail_json(msg='Missing required pan-python and pandevice modules.') ip_address = module.params["ip_address"] password = module.params["password"] username = module.params['username'] api_key = module.params['api_key'] rule_name = module.params['rule_name'] description = module.params['description'] tag = module.params['tag'] from_zone = module.params['from_zone'] to_zone = module.params['to_zone'] source = module.params['source'] source_user = module.params['source_user'] destination = module.params['destination'] category = module.params['category'] application = module.params['application'] service = module.params['service'] hip_profiles = module.params['hip_profiles'] log_start = module.params['log_start'] log_end = module.params['log_end'] rule_type = module.params['rule_type'] action = module.params['action'] group_profile = module.params['group_profile'] antivirus = module.params['antivirus'] vulnerability = module.params['vulnerability'] spyware = module.params['spyware'] url_filtering = module.params['url_filtering'] file_blocking = module.params['file_blocking'] data_filtering = module.params['data_filtering'] wildfire_analysis = module.params['wildfire_analysis'] devicegroup = module.params['devicegroup'] commit = module.params['commit'] if devicegroup: device = pandevice.panorama.Panorama(ip_address, username, password, api_key=api_key) dev_grps = device.refresh_devices() for grp in dev_grps: if grp.name == devicegroup: break module.fail_json(msg=' \'%s\' device group not found in Panorama. Is the name correct?' % devicegroup) else: device = pandevice.firewall.Firewall(ip_address, username, password, api_key=api_key) sec_rule = create_security_rule( rule_name=rule_name, description=description, tag=tag, from_zone=from_zone, to_zone=to_zone, source=source, source_user=source_user, destination=destination, category=category, application=application, service=service, hip_profiles=hip_profiles, group_profile=group_profile, antivirus=antivirus, vulnerability=vulnerability, spyware=spyware, url_filtering=url_filtering, file_blocking=file_blocking, data_filtering=data_filtering, wildfire_analysis=wildfire_analysis, log_start=log_start, log_end=log_end, rule_type=rule_type, action=action ) rule_exist = security_rule_exists(device, sec_rule) if rule_exist is True: module.fail_json(msg='Rule with the same name but different objects exists.') try: changed = add_security_rule(device, sec_rule, rule_exist) except PanXapiError: exc = get_exception() module.fail_json(msg=exc.message) if changed and commit: result = _commit(device, devicegroup) module.exit_json(changed=changed, msg="okey dokey")
def main(): module = AnsibleModule( argument_spec=dict( state=dict(type='str', default='present', choices=['present', 'absent']), force=dict(type='bool', default=False), path=dict(type='path', required=True), privatekey_path=dict(type='path'), privatekey_content=dict(type='str'), format=dict(type='str', default='PEM', choices=['OpenSSH', 'PEM']), privatekey_passphrase=dict(type='str', no_log=True), backup=dict(type='bool', default=False), select_crypto_backend=dict( type='str', choices=['auto', 'pyopenssl', 'cryptography'], default='auto'), return_content=dict(type='bool', default=False), ), supports_check_mode=True, add_file_common_args=True, required_if=[('state', 'present', ['privatekey_path', 'privatekey_content'], True)], mutually_exclusive=(['privatekey_path', 'privatekey_content'], ), ) minimal_cryptography_version = MINIMAL_CRYPTOGRAPHY_VERSION if module.params['format'] == 'OpenSSH': minimal_cryptography_version = MINIMAL_CRYPTOGRAPHY_VERSION_OPENSSH backend = module.params['select_crypto_backend'] if backend == 'auto': # Detection what is possible can_use_cryptography = CRYPTOGRAPHY_FOUND and CRYPTOGRAPHY_VERSION >= LooseVersion( minimal_cryptography_version) can_use_pyopenssl = PYOPENSSL_FOUND and PYOPENSSL_VERSION >= LooseVersion( MINIMAL_PYOPENSSL_VERSION) # Decision if can_use_cryptography: backend = 'cryptography' elif can_use_pyopenssl: if module.params['format'] == 'OpenSSH': module.fail_json(msg=missing_required_lib( 'cryptography >= {0}'.format( MINIMAL_CRYPTOGRAPHY_VERSION_OPENSSH)), exception=CRYPTOGRAPHY_IMP_ERR) backend = 'pyopenssl' # Success? if backend == 'auto': module.fail_json(msg=( "Can't detect any of the required Python libraries " "cryptography (>= {0}) or PyOpenSSL (>= {1})" ).format(minimal_cryptography_version, MINIMAL_PYOPENSSL_VERSION)) if module.params['format'] == 'OpenSSH' and backend != 'cryptography': module.fail_json( msg="Format OpenSSH requires the cryptography backend.") if backend == 'pyopenssl': if not PYOPENSSL_FOUND: module.fail_json(msg=missing_required_lib( 'pyOpenSSL >= {0}'.format(MINIMAL_PYOPENSSL_VERSION)), exception=PYOPENSSL_IMP_ERR) module.deprecate( 'The module is using the PyOpenSSL backend. This backend has been deprecated', version='2.13') elif backend == 'cryptography': if not CRYPTOGRAPHY_FOUND: module.fail_json(msg=missing_required_lib( 'cryptography >= {0}'.format(minimal_cryptography_version)), exception=CRYPTOGRAPHY_IMP_ERR) base_dir = os.path.dirname(module.params['path']) or '.' if not os.path.isdir(base_dir): module.fail_json( name=base_dir, msg= "The directory '%s' does not exist or the file is not a directory" % base_dir) try: public_key = PublicKey(module, backend) if public_key.state == 'present': if module.check_mode: result = public_key.dump() result['changed'] = module.params[ 'force'] or not public_key.check(module) module.exit_json(**result) public_key.generate(module) else: if module.check_mode: result = public_key.dump() result['changed'] = os.path.exists(module.params['path']) module.exit_json(**result) public_key.remove(module) result = public_key.dump() module.exit_json(**result) except crypto_utils.OpenSSLObjectError as exc: module.fail_json(msg=to_native(exc))
def main(): argument_spec = ovirt_full_argument_spec( state=dict( choices=['present', 'absent'], default='present', ), name=dict(default=None), description=dict(default=None), type=dict( default=None, required=True, choices=[ 'os_image', 'network', 'os_volume', 'foreman', ], aliases=['provider'], ), url=dict(default=None), username=dict(default=None), password=dict(default=None, no_log=True), tenant_name=dict(default=None, aliases=['tenant']), authentication_url=dict(default=None, aliases=['auth_url']), data_center=dict(default=None), read_only=dict(default=None, type='bool'), network_type=dict( default='external', choices=['external', 'neutron'], ), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) if module._name == 'ovirt_external_providers': module.deprecate("The 'ovirt_external_providers' module is being renamed 'ovirt_external_provider'", version=2.8) check_sdk(module) check_params(module) try: auth = module.params.pop('auth') connection = create_connection(auth) provider_type, external_providers_service = _external_provider_service( provider_type=module.params.get('type'), system_service=connection.system_service(), ) external_providers_module = ExternalProviderModule( connection=connection, module=module, service=external_providers_service, ) external_providers_module.provider_type(provider_type) state = module.params.pop('state') if state == 'absent': ret = external_providers_module.remove() elif state == 'present': ret = external_providers_module.create() module.exit_json(**ret) except Exception as e: module.fail_json(msg=str(e), exception=traceback.format_exc()) finally: connection.close(logout=auth.get('token') is None)
def main(): argument_spec = ecs_argument_spec() argument_spec.update(dict( availability_zone=dict(aliases=['alicloud_zone']), instance_ids=dict(type='list', elements='str', aliases=['ids']), instance_names=dict(type='list', elements='str', aliases=['names']), name_prefix=dict(type='str'), tags=dict(type='dict', aliases=['instance_tags']), filters=dict(type='dict') ) ) module = AnsibleModule(argument_spec=argument_spec) if module._name in ('ali_instance_facts', 'community.general.ali_instance_facts'): module.deprecate("The 'ali_instance_facts' module has been renamed to 'ali_instance_info'", version='3.0.0', collection_name='community.general') # was Ansible 2.13 if HAS_FOOTMARK is False: module.fail_json(msg=missing_required_lib('footmark'), exception=FOOTMARK_IMP_ERR) ecs = ecs_connect(module) instances = [] instance_ids = [] ids = module.params['instance_ids'] name_prefix = module.params['name_prefix'] names = module.params['instance_names'] zone_id = module.params['availability_zone'] if ids and (not isinstance(ids, list) or len(ids) < 1): module.fail_json(msg='instance_ids should be a list of instances, aborting') if names and (not isinstance(names, list) or len(names) < 1): module.fail_json(msg='instance_names should be a list of instances, aborting') filters = module.params['filters'] if not filters: filters = {} if not ids: ids = [] for key, value in list(filters.items()): if key in ["InstanceIds", "instance_ids", "instance-ids"] and isinstance(ids, list): for id in value: if id not in ids: ids.append(value) if ids: filters['instance_ids'] = ids if module.params['tags']: filters['tags'] = module.params['tags'] if zone_id: filters['zone_id'] = zone_id if names: filters['instance_name'] = names[0] for inst in ecs.describe_instances(**filters): if name_prefix: if not str(inst.instance_name).startswith(name_prefix): continue volumes = ecs.describe_disks(instance_id=inst.id) setattr(inst, 'block_device_mappings', volumes) setattr(inst, 'user_data', inst.describe_user_data()) instances.append(inst.read()) instance_ids.append(inst.id) module.exit_json(changed=False, ids=instance_ids, instances=instances)
def main(): argument_spec = url_argument_spec() argument_spec.update(dict( dest=dict(type='path'), url_username=dict(type='str', aliases=['user']), url_password=dict(type='str', aliases=['password'], no_log=True), body=dict(type='raw'), body_format=dict(type='str', default='raw', choices=['raw', 'json']), method=dict(type='str', default='GET', choices=['GET', 'POST', 'PUT', 'HEAD', 'DELETE', 'OPTIONS', 'PATCH', 'TRACE', 'CONNECT', 'REFRESH']), return_content=dict(type='bool', default='no'), follow_redirects=dict(type='str', default='safe', choices=['all', 'no', 'none', 'safe', 'urllib2', 'yes']), creates=dict(type='path'), removes=dict(type='path'), status_code=dict(type='list', default=[200]), timeout=dict(type='int', default=30), headers=dict(type='dict', default={}) )) module = AnsibleModule( argument_spec=argument_spec, # TODO: Remove check_invalid_arguments in 2.9 check_invalid_arguments=False, add_file_common_args=True ) url = module.params['url'] body = module.params['body'] body_format = module.params['body_format'].lower() method = module.params['method'] dest = module.params['dest'] return_content = module.params['return_content'] creates = module.params['creates'] removes = module.params['removes'] status_code = [int(x) for x in list(module.params['status_code'])] socket_timeout = module.params['timeout'] dict_headers = module.params['headers'] if body_format == 'json': # Encode the body unless its a string, then assume it is pre-formatted JSON if not isinstance(body, six.string_types): body = json.dumps(body) lower_header_keys = [key.lower() for key in dict_headers] if 'content-type' not in lower_header_keys: dict_headers['Content-Type'] = 'application/json' # TODO: Deprecated section. Remove in Ansible 2.9 # Grab all the http headers. Need this hack since passing multi-values is # currently a bit ugly. (e.g. headers='{"Content-Type":"application/json"}') for key, value in six.iteritems(module.params): if key.startswith("HEADER_"): module.deprecate('Supplying headers via HEADER_* is deprecated. Please use `headers` to' ' supply headers for the request', version='2.9') skey = key.replace("HEADER_", "") dict_headers[skey] = value # End deprecated section if creates is not None: # do not run the command if the line contains creates=filename # and the filename already exists. This allows idempotence # of uri executions. if os.path.exists(creates): module.exit_json(stdout="skipped, since '%s' exists" % creates, changed=False, rc=0) if removes is not None: # do not run the command if the line contains removes=filename # and the filename do not exists. This allows idempotence # of uri executions. if not os.path.exists(removes): module.exit_json(stdout="skipped, since '%s' does not exist" % removes, changed=False, rc=0) # Make the request resp, content, dest = uri(module, url, dest, body, body_format, method, dict_headers, socket_timeout) resp['status'] = int(resp['status']) # Write the file out if requested if dest is not None: if resp['status'] == 304: changed = False else: write_file(module, url, dest, content) # allow file attribute changes changed = True module.params['path'] = dest file_args = module.load_file_common_arguments(module.params) file_args['path'] = dest changed = module.set_fs_attributes_if_different(file_args, changed) resp['path'] = dest else: changed = False # Transmogrify the headers, replacing '-' with '_', since variables don't # work with dashes. # In python3, the headers are title cased. Lowercase them to be # compatible with the python2 behaviour. uresp = {} for key, value in six.iteritems(resp): ukey = key.replace("-", "_").lower() uresp[ukey] = value try: uresp['location'] = absolute_location(url, uresp['location']) except KeyError: pass # Default content_encoding to try content_encoding = 'utf-8' if 'content_type' in uresp: content_type, params = cgi.parse_header(uresp['content_type']) if 'charset' in params: content_encoding = params['charset'] u_content = to_text(content, encoding=content_encoding) if any(candidate in content_type for candidate in JSON_CANDIDATES): try: js = json.loads(u_content) uresp['json'] = js except: pass else: u_content = to_text(content, encoding=content_encoding) if resp['status'] not in status_code: uresp['msg'] = 'Status code was %s and not %s: %s' % (resp['status'], status_code, uresp.get('msg', '')) module.fail_json(content=u_content, **uresp) elif return_content: module.exit_json(changed=changed, content=u_content, **uresp) else: module.exit_json(changed=changed, **uresp)
def main(): module = AnsibleModule( argument_spec=dict( state=dict(type='str', default='present', choices=['absent', 'build-dep', 'installed', 'latest', 'present', 'removed', 'present', 'fixed']), update_cache=dict(type='bool', aliases=['update-cache']), cache_valid_time=dict(type='int', default=0), purge=dict(type='bool', default=False), package=dict(type='list', aliases=['pkg', 'name']), deb=dict(type='path'), default_release=dict(type='str', aliases=['default-release']), install_recommends=dict(type='bool', aliases=['install-recommends']), force=dict(type='bool', default=False), upgrade=dict(type='str', choices=['dist', 'full', 'no', 'safe', 'yes']), dpkg_options=dict(type='str', default=DPKG_OPTIONS), autoremove=dict(type='bool', default=False), autoclean=dict(type='bool', default=False), policy_rc_d=dict(type='int', default=None), only_upgrade=dict(type='bool', default=False), force_apt_get=dict(type='bool', default=False), allow_unauthenticated=dict(type='bool', default=False, aliases=['allow-unauthenticated']), ), mutually_exclusive=[['deb', 'package', 'upgrade']], required_one_of=[['autoremove', 'deb', 'package', 'update_cache', 'upgrade']], supports_check_mode=True, ) module.run_command_environ_update = APT_ENV_VARS if not HAS_PYTHON_APT: if module.check_mode: module.fail_json(msg="%s must be installed to use check mode. " "If run normally this module can auto-install it." % PYTHON_APT) try: module.warn("Updating cache and auto-installing missing dependency: %s" % PYTHON_APT) module.run_command(['apt-get', 'update'], check_rc=True) module.run_command(['apt-get', 'install', '--no-install-recommends', PYTHON_APT, '-y', '-q'], check_rc=True) global apt, apt_pkg import apt import apt.debfile import apt_pkg except ImportError: module.fail_json(msg="Could not import python modules: apt, apt_pkg. " "Please install %s package." % PYTHON_APT) global APTITUDE_CMD APTITUDE_CMD = module.get_bin_path("aptitude", False) global APT_GET_CMD APT_GET_CMD = module.get_bin_path("apt-get") p = module.params if p['upgrade'] == 'no': p['upgrade'] = None use_apt_get = p['force_apt_get'] if not use_apt_get and not APTITUDE_CMD and p.get('upgrade', None) in ['full', 'safe', 'yes']: module.warn("Could not find aptitude. Using apt-get instead.") use_apt_get = True updated_cache = False updated_cache_time = 0 install_recommends = p['install_recommends'] allow_unauthenticated = p['allow_unauthenticated'] dpkg_options = expand_dpkg_options(p['dpkg_options']) autoremove = p['autoremove'] autoclean = p['autoclean'] # Deal with deprecated aliases if p['state'] == 'installed': module.deprecate("State 'installed' is deprecated. Using state 'present' instead.", version="2.9") p['state'] = 'present' if p['state'] == 'removed': module.deprecate("State 'removed' is deprecated. Using state 'absent' instead.", version="2.9") p['state'] = 'absent' # Get the cache object cache = get_cache(module) try: if p['default_release']: try: apt_pkg.config['APT::Default-Release'] = p['default_release'] except AttributeError: apt_pkg.Config['APT::Default-Release'] = p['default_release'] # reopen cache w/ modified config cache.open(progress=None) mtimestamp, updated_cache_time = get_updated_cache_time() # Cache valid time is default 0, which will update the cache if # needed and `update_cache` was set to true updated_cache = False if p['update_cache'] or p['cache_valid_time']: now = datetime.datetime.now() tdelta = datetime.timedelta(seconds=p['cache_valid_time']) if not mtimestamp + tdelta >= now: # Retry to update the cache up to 3 times err = '' for retry in range(3): try: cache.update() break except apt.cache.FetchFailedException as e: err = to_native(e) else: module.fail_json(msg='Failed to update apt cache: %s' % err) cache.open(progress=None) mtimestamp, post_cache_update_time = get_updated_cache_time() if updated_cache_time != post_cache_update_time: updated_cache = True updated_cache_time = post_cache_update_time # If there is nothing else to do exit. This will set state as # changed based on if the cache was updated. if not p['package'] and not p['upgrade'] and not p['deb']: module.exit_json( changed=updated_cache, cache_updated=updated_cache, cache_update_time=updated_cache_time ) force_yes = p['force'] if p['upgrade']: upgrade(module, p['upgrade'], force_yes, p['default_release'], use_apt_get, dpkg_options, autoremove, allow_unauthenticated) if p['deb']: if p['state'] != 'present': module.fail_json(msg="deb only supports state=present") if '://' in p['deb']: p['deb'] = fetch_file(module, p['deb']) install_deb(module, p['deb'], cache, install_recommends=install_recommends, allow_unauthenticated=allow_unauthenticated, force=force_yes, dpkg_options=p['dpkg_options']) unfiltered_packages = p['package'] or () packages = [package for package in unfiltered_packages if package != '*'] all_installed = '*' in unfiltered_packages latest = p['state'] == 'latest' if latest and all_installed: if packages: module.fail_json(msg='unable to install additional packages when upgrading all installed packages') upgrade(module, 'yes', force_yes, p['default_release'], use_apt_get, dpkg_options, autoremove, allow_unauthenticated) if packages: for package in packages: if package.count('=') > 1: module.fail_json(msg="invalid package spec: %s" % package) if latest and '=' in package: module.fail_json(msg='version number inconsistent with state=latest: %s' % package) if not packages: if autoclean: cleanup(module, p['purge'], force=force_yes, operation='autoclean', dpkg_options=dpkg_options) if autoremove: cleanup(module, p['purge'], force=force_yes, operation='autoremove', dpkg_options=dpkg_options) if p['state'] in ('latest', 'present', 'build-dep', 'fixed'): state_upgrade = False state_builddep = False state_fixed = False if p['state'] == 'latest': state_upgrade = True if p['state'] == 'build-dep': state_builddep = True if p['state'] == 'fixed': state_fixed = True success, retvals = install( module, packages, cache, upgrade=state_upgrade, default_release=p['default_release'], install_recommends=install_recommends, force=force_yes, dpkg_options=dpkg_options, build_dep=state_builddep, fixed=state_fixed, autoremove=autoremove, only_upgrade=p['only_upgrade'], allow_unauthenticated=allow_unauthenticated ) # Store if the cache has been updated retvals['cache_updated'] = updated_cache # Store when the update time was last retvals['cache_update_time'] = updated_cache_time if success: module.exit_json(**retvals) else: module.fail_json(**retvals) elif p['state'] == 'absent': remove(module, packages, cache, p['purge'], force=force_yes, dpkg_options=dpkg_options, autoremove=autoremove) except apt.cache.LockFailedException: module.fail_json(msg="Failed to lock apt for exclusive operation") except apt.cache.FetchFailedException: module.fail_json(msg="Could not fetch updated apt files")
def main(): argument_spec = url_argument_spec() argument_spec.update( url=dict(type='str', required=True), dest=dict(type='path', required=True), backup=dict(type='bool'), sha256sum=dict(type='str', default=''), checksum=dict(type='str', default=''), timeout=dict(type='int', default=10), headers=dict(type='raw'), tmp_dest=dict(type='path'), ) module = AnsibleModule( # not checking because of daisy chain to file module argument_spec=argument_spec, add_file_common_args=True, supports_check_mode=True, mutually_exclusive=(['checksum', 'sha256sum']), ) url = module.params['url'] dest = module.params['dest'] backup = module.params['backup'] force = module.params['force'] sha256sum = module.params['sha256sum'] checksum = module.params['checksum'] use_proxy = module.params['use_proxy'] timeout = module.params['timeout'] tmp_dest = module.params['tmp_dest'] # Parse headers to dict if isinstance(module.params['headers'], dict): headers = module.params['headers'] elif module.params['headers']: try: headers = dict(item.split(':', 1) for item in module.params['headers'].split(',')) module.deprecate('Supplying `headers` as a string is deprecated. Please use dict/hash format for `headers`', version='2.10') except Exception: module.fail_json(msg="The string representation for the `headers` parameter requires a key:value,key:value syntax to be properly parsed.") else: headers = None dest_is_dir = os.path.isdir(dest) last_mod_time = None # workaround for usage of deprecated sha256sum parameter if sha256sum: checksum = 'sha256:%s' % (sha256sum) # checksum specified, parse for algorithm and checksum if checksum: try: algorithm, checksum = checksum.rsplit(':', 1) # Remove any non-alphanumeric characters, including the infamous # Unicode zero-width space checksum = re.sub(r'\W+', '', checksum).lower() # Ensure the checksum portion is a hexdigest int(checksum, 16) except ValueError: module.fail_json(msg="The checksum parameter has to be in format <algorithm>:<checksum>") if not dest_is_dir and os.path.exists(dest): checksum_mismatch = False # If the download is not forced and there is a checksum, allow # checksum match to skip the download. if not force and checksum != '': destination_checksum = module.digest_from_file(dest, algorithm) if checksum == destination_checksum: module.exit_json(msg="file already exists", dest=dest, url=url, changed=False) checksum_mismatch = True # Not forcing redownload, unless checksum does not match if not force and not checksum_mismatch: # allow file attribute changes module.params['path'] = dest file_args = module.load_file_common_arguments(module.params) file_args['path'] = dest changed = module.set_fs_attributes_if_different(file_args, False) if changed: module.exit_json(msg="file already exists but file attributes changed", dest=dest, url=url, changed=changed) module.exit_json(msg="file already exists", dest=dest, url=url, changed=changed) # If the file already exists, prepare the last modified time for the # request. mtime = os.path.getmtime(dest) last_mod_time = datetime.datetime.utcfromtimestamp(mtime) # If the checksum does not match we have to force the download # because last_mod_time may be newer than on remote if checksum_mismatch: force = True # download to tmpsrc tmpsrc, info = url_get(module, url, dest, use_proxy, last_mod_time, force, timeout, headers, tmp_dest) # Now the request has completed, we can finally generate the final # destination file name from the info dict. if dest_is_dir: filename = extract_filename_from_headers(info) if not filename: # Fall back to extracting the filename from the URL. # Pluck the URL from the info, since a redirect could have changed # it. filename = url_filename(info['url']) dest = os.path.join(dest, filename) checksum_src = None checksum_dest = None # If the remote URL exists, we're done with check mode if module.check_mode: os.remove(tmpsrc) res_args = dict(url=url, dest=dest, src=tmpsrc, changed=True, msg=info.get('msg', '')) module.exit_json(**res_args) # raise an error if there is no tmpsrc file if not os.path.exists(tmpsrc): os.remove(tmpsrc) module.fail_json(msg="Request failed", status_code=info['status'], response=info['msg']) if not os.access(tmpsrc, os.R_OK): os.remove(tmpsrc) module.fail_json(msg="Source %s is not readable" % (tmpsrc)) checksum_src = module.sha1(tmpsrc) # check if there is no dest file if os.path.exists(dest): # raise an error if copy has no permission on dest if not os.access(dest, os.W_OK): os.remove(tmpsrc) module.fail_json(msg="Destination %s is not writable" % (dest)) if not os.access(dest, os.R_OK): os.remove(tmpsrc) module.fail_json(msg="Destination %s is not readable" % (dest)) checksum_dest = module.sha1(dest) else: if not os.path.exists(os.path.dirname(dest)): os.remove(tmpsrc) module.fail_json(msg="Destination %s does not exist" % (os.path.dirname(dest))) if not os.access(os.path.dirname(dest), os.W_OK): os.remove(tmpsrc) module.fail_json(msg="Destination %s is not writable" % (os.path.dirname(dest))) backup_file = None if checksum_src != checksum_dest: try: if backup: if os.path.exists(dest): backup_file = module.backup_local(dest) module.atomic_move(tmpsrc, dest) except Exception as e: if os.path.exists(tmpsrc): os.remove(tmpsrc) module.fail_json(msg="failed to copy %s to %s: %s" % (tmpsrc, dest, to_native(e)), exception=traceback.format_exc()) changed = True else: changed = False if os.path.exists(tmpsrc): os.remove(tmpsrc) if checksum != '': destination_checksum = module.digest_from_file(dest, algorithm) if checksum != destination_checksum: os.remove(dest) module.fail_json(msg="The checksum for %s did not match %s; it was %s." % (dest, checksum, destination_checksum)) # allow file attribute changes module.params['path'] = dest file_args = module.load_file_common_arguments(module.params) file_args['path'] = dest changed = module.set_fs_attributes_if_different(file_args, changed) # Backwards compat only. We'll return None on FIPS enabled systems try: md5sum = module.md5(dest) except ValueError: md5sum = None res_args = dict( url=url, dest=dest, src=tmpsrc, md5sum=md5sum, checksum_src=checksum_src, checksum_dest=checksum_dest, changed=changed, msg=info.get('msg', ''), status_code=info.get('status', '') ) if backup_file: res_args['backup_file'] = backup_file # Mission complete module.exit_json(**res_args)
def main(): module = AnsibleModule( argument_spec=dict(server_url=dict(type='str', required=True, aliases=['url']), login_user=dict(type='str', required=True), login_password=dict(type='str', required=True, no_log=True), http_login_user=dict(type='str', required=False, default=None), http_login_password=dict(type='str', required=False, default=None, no_log=True), validate_certs=dict(type='bool', required=False, default=True), template_name=dict(type='str', required=False), template_json=dict(type='json', required=False), template_xml=dict(type='str', required=False), template_groups=dict(type='list', required=False), link_templates=dict(type='list', required=False), clear_templates=dict(type='list', required=False), macros=dict(type='list', required=False), dump_format=dict(type='str', required=False, default='json', choices=['json', 'xml']), state=dict(default="present", choices=['present', 'absent', 'dump']), timeout=dict(type='int', default=10)), required_one_of=[['template_name', 'template_json', 'template_xml']], mutually_exclusive=[['template_name', 'template_json', 'template_xml']], required_if=[['state', 'absent', ['template_name']], ['state', 'dump', ['template_name']]], supports_check_mode=True) if not HAS_ZABBIX_API: module.fail_json(msg=missing_required_lib( 'zabbix-api', url='https://pypi.org/project/zabbix-api/'), exception=ZBX_IMP_ERR) server_url = module.params['server_url'] login_user = module.params['login_user'] login_password = module.params['login_password'] http_login_user = module.params['http_login_user'] http_login_password = module.params['http_login_password'] validate_certs = module.params['validate_certs'] template_name = module.params['template_name'] template_json = module.params['template_json'] template_xml = module.params['template_xml'] template_groups = module.params['template_groups'] link_templates = module.params['link_templates'] clear_templates = module.params['clear_templates'] template_macros = module.params['macros'] dump_format = module.params['dump_format'] state = module.params['state'] timeout = module.params['timeout'] zbx = None try: zbx = ZabbixAPI(server_url, timeout=timeout, user=http_login_user, passwd=http_login_password, validate_certs=validate_certs) zbx.login(login_user, login_password) atexit.register(zbx.logout) except ZabbixAPIException as e: module.fail_json(msg="Failed to connect to Zabbix server: %s" % e) template = Template(module, zbx) # Identify template names for IDs retrieval # Template names are expected to reside in ['zabbix_export']['templates'][*]['template'] for both data types template_content, template_type = None, None if template_json is not None: template_type = 'json' template_content = template_json json_parsed = template.load_json_template(template_content) template_names = list( t['template'] for t in json_parsed['zabbix_export']['templates']) elif template_xml is not None: template_type = 'xml' template_content = template_xml xml_parsed = template.load_xml_template(template_content) template_names = list( t.find('template').text for t in list(xml_parsed.find('templates'))) else: template_names = [template_name] template_ids = template.get_template_ids(template_names) if state == "absent": if not template_ids: module.exit_json(changed=False, msg="Template not found. No changed: %s" % template_name) template.delete_template(template_ids) module.exit_json(changed=True, result="Successfully deleted template %s" % template_name) elif state == "dump": module.deprecate( "The 'dump' state has been deprecated and will be removed, use 'zabbix_template_info' module instead.", version='2.14') if not template_ids: module.fail_json(msg='Template not found: %s' % template_name) if dump_format == 'json': module.exit_json(changed=False, template_json=template.dump_template( template_ids, template_type='json')) elif dump_format == 'xml': module.exit_json(changed=False, template_xml=template.dump_template( template_ids, template_type='xml')) elif state == "present": # Load all subelements for template that were provided by user group_ids = None if template_groups is not None: group_ids = template.get_group_ids_by_group_names(template_groups) link_template_ids = None if link_templates is not None: link_template_ids = template.get_template_ids(link_templates) clear_template_ids = None if clear_templates is not None: clear_template_ids = template.get_template_ids(clear_templates) if template_macros is not None: # Zabbix configuration.export does not differentiate python types (numbers are returned as strings) for macroitem in template_macros: for key in macroitem: macroitem[key] = str(macroitem[key]) if not template_ids: # Assume new templates are being added when no ID's were found if template_content is not None: template.import_template(template_content, template_type) module.exit_json(changed=True, result="Template import successful") else: if group_ids is None: module.fail_json( msg= 'template_groups are required when creating a new Zabbix template' ) template.add_template(template_name, group_ids, link_template_ids, template_macros) module.exit_json(changed=True, result="Successfully added template: %s" % template_name) else: changed = template.check_template_changed( template_ids, template_groups, link_templates, clear_templates, template_macros, template_content, template_type) if module.check_mode: module.exit_json(changed=changed) if changed: if template_type is not None: template.import_template(template_content, template_type) else: template.update_template(template_ids, group_ids, link_template_ids, clear_template_ids, template_macros) module.exit_json(changed=changed, result="Template successfully updated")
def main(): module = AnsibleModule(argument_spec={}, supports_check_mode=True) module.deprecate(msg) module.exit_json(changed=False)
def main(): argument_spec = ovirt_full_argument_spec( state=dict( choices=['present', 'absent', 'attached', 'detached', 'exported'], default='present'), id=dict(default=None), name=dict(default=None, aliases=['alias']), vm_name=dict(default=None), vm_id=dict(default=None), size=dict(default=None), interface=dict(default=None, ), storage_domain=dict(default=None), storage_domains=dict(default=None, type='list'), profile=dict(default=None), format=dict(default='cow', choices=['raw', 'cow']), bootable=dict(default=None, type='bool'), shareable=dict(default=None, type='bool'), logical_unit=dict(default=None, type='dict'), download_image_path=dict(default=None), upload_image_path=dict(default=None, aliases=['image_path']), force=dict(default=False, type='bool'), sparsify=dict(default=None, type='bool'), openstack_volume_type=dict(default=None), image_provider=dict(default=None), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) if module._name == 'ovirt_disks': module.deprecate( "The 'ovirt_disks' module is being renamed 'ovirt_disk'", version=2.8) check_sdk(module) check_params(module) try: disk = None state = module.params['state'] auth = module.params.get('auth') connection = create_connection(auth) disks_service = connection.system_service().disks_service() disks_module = DisksModule( connection=connection, module=module, service=disks_service, ) lun = module.params.get('logical_unit') if lun: disk = _search_by_lun(disks_service, lun.get('id')) ret = None # First take care of creating the VM, if needed: if state in ('present', 'detached', 'attached'): ret = disks_module.create( entity=disk, result_state=otypes.DiskStatus.OK if lun is None else None, ) is_new_disk = ret['changed'] ret['changed'] = ret[ 'changed'] or disks_module.update_storage_domains(ret['id']) # We need to pass ID to the module, so in case we want detach/attach disk # we have this ID specified to attach/detach method: module.params['id'] = ret['id'] if disk is None else disk.id # Upload disk image in case it's new disk or force parameter is passed: if module.params['upload_image_path'] and (is_new_disk or module.params['force']): uploaded = upload_disk_image(connection, module) ret['changed'] = ret['changed'] or uploaded # Download disk image in case it's file don't exist or force parameter is passed: if (module.params['download_image_path'] and (not os.path.isfile(module.params['download_image_path']) or module.params['force'])): downloaded = download_disk_image(connection, module) ret['changed'] = ret['changed'] or downloaded # Disk sparsify, only if disk is of image type: disk = disks_service.disk_service(module.params['id']).get() if disk.storage_type == otypes.DiskStorageType.IMAGE: ret = disks_module.action( action='sparsify', action_condition=lambda d: module.params['sparsify'], wait_condition=lambda d: d.status == otypes.DiskStatus.OK, ) # Export disk as image to glance domain elif state == 'exported': disk = disks_module.search_entity() if disk is None: module.fail_json( msg="Can not export given disk '%s', it doesn't exist" % module.params.get('name') or module.params.get('id')) if disk.storage_type == otypes.DiskStorageType.IMAGE: ret = disks_module.action( action='export', action_condition=lambda d: module.params['image_provider'], wait_condition=lambda d: d.status == otypes.DiskStatus.OK, storage_domain=otypes.StorageDomain( name=module.params['image_provider']), ) elif state == 'absent': ret = disks_module.remove() # If VM was passed attach/detach disks to/from the VM: if module.params.get('vm_id') is not None or module.params.get( 'vm_name') is not None and state != 'absent': vms_service = connection.system_service().vms_service() # If `vm_id` isn't specified, find VM by name: vm_id = module.params['vm_id'] if vm_id is None: vm_id = getattr( search_by_name(vms_service, module.params['vm_name']), 'id', None) if vm_id is None: module.fail_json( msg="VM don't exists, please create it first.") disk_attachments_service = vms_service.vm_service( vm_id).disk_attachments_service() disk_attachments_module = DiskAttachmentsModule( connection=connection, module=module, service=disk_attachments_service, changed=ret['changed'] if ret else False, ) if state == 'present' or state == 'attached': ret = disk_attachments_module.create() if lun is None: wait( service=disk_attachments_service.service(ret['id']), condition=lambda d: follow_link(connection, d.disk). status == otypes.DiskStatus.OK, wait=module.params['wait'], timeout=module.params['timeout'], ) elif state == 'detached': ret = disk_attachments_module.remove() module.exit_json(**ret) except Exception as e: module.fail_json(msg=str(e), exception=traceback.format_exc()) finally: connection.close(logout=auth.get('token') is None)
def main(): argument_spec = ovirt_full_argument_spec( state=dict( choices=['present', 'absent'], default='present', ), name=dict(default=None, required=True), ballooning=dict(default=None, type='bool', aliases=['balloon']), gluster=dict(default=None, type='bool'), virt=dict(default=None, type='bool'), threads_as_cores=dict(default=None, type='bool'), ksm_numa=dict(default=None, type='bool'), ksm=dict(default=None, type='bool'), ha_reservation=dict(default=None, type='bool'), trusted_service=dict(default=None, type='bool'), vm_reason=dict(default=None, type='bool'), host_reason=dict(default=None, type='bool'), memory_policy=dict(default=None, choices=['disabled', 'server', 'desktop']), rng_sources=dict(default=None, type='list'), spice_proxy=dict(default=None), fence_enabled=dict(default=None, type='bool'), fence_skip_if_sd_active=dict(default=None, type='bool'), fence_skip_if_connectivity_broken=dict(default=None, type='bool'), fence_connectivity_threshold=dict(default=None, type='int'), resilience_policy=dict(default=None, choices=['migrate_highly_available', 'migrate', 'do_not_migrate']), migration_bandwidth=dict(default=None, choices=['auto', 'hypervisor_default', 'custom']), migration_bandwidth_limit=dict(default=None, type='int'), migration_auto_converge=dict(default=None, choices=['true', 'false', 'inherit']), migration_compressed=dict(default=None, choices=['true', 'false', 'inherit']), migration_policy=dict( default=None, choices=['legacy', 'minimal_downtime', 'suspend_workload', 'post_copy'] ), serial_policy=dict(default=None, choices=['vm', 'host', 'custom']), serial_policy_value=dict(default=None), scheduling_policy=dict(default=None), data_center=dict(default=None), description=dict(default=None), comment=dict(default=None), network=dict(default=None), cpu_arch=dict(default=None, choices=['ppc64', 'undefined', 'x86_64']), cpu_type=dict(default=None), switch_type=dict(default=None, choices=['legacy', 'ovs']), compatibility_version=dict(default=None), mac_pool=dict(default=None), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) if module._name == 'ovirt_clusters': module.deprecate("The 'ovirt_clusters' module is being renamed 'ovirt_cluster'", version=2.8) check_sdk(module) try: auth = module.params.pop('auth') connection = create_connection(auth) clusters_service = connection.system_service().clusters_service() clusters_module = ClustersModule( connection=connection, module=module, service=clusters_service, ) state = module.params['state'] if state == 'present': ret = clusters_module.create() elif state == 'absent': ret = clusters_module.remove() module.exit_json(**ret) except Exception as e: module.fail_json(msg=str(e), exception=traceback.format_exc()) finally: connection.close(logout=auth.get('token') is None)
class AzureRMModuleBase(object): def __init__(self, derived_arg_spec, bypass_checks=False, no_log=False, check_invalid_arguments=None, mutually_exclusive=None, required_together=None, required_one_of=None, add_file_common_args=False, supports_check_mode=False, required_if=None, supports_tags=True, facts_module=False, skip_exec=False): merged_arg_spec = dict() merged_arg_spec.update(AZURE_COMMON_ARGS) if supports_tags: merged_arg_spec.update(AZURE_TAG_ARGS) if derived_arg_spec: merged_arg_spec.update(derived_arg_spec) merged_required_if = list(AZURE_COMMON_REQUIRED_IF) if required_if: merged_required_if += required_if self.module = AnsibleModule(argument_spec=merged_arg_spec, bypass_checks=bypass_checks, no_log=no_log, check_invalid_arguments=check_invalid_arguments, mutually_exclusive=mutually_exclusive, required_together=required_together, required_one_of=required_one_of, add_file_common_args=add_file_common_args, supports_check_mode=supports_check_mode, required_if=merged_required_if) if not HAS_PACKAGING_VERSION: self.fail("Do you have packaging installed? Try `pip install packaging`" "- {0}".format(HAS_PACKAGING_VERSION_EXC)) if not HAS_MSRESTAZURE: self.fail("Do you have msrestazure installed? Try `pip install msrestazure`" "- {0}".format(HAS_MSRESTAZURE_EXC)) if not HAS_AZURE: self.fail("Do you have azure>={1} installed? Try `pip install ansible[azure]`" "- {0}".format(HAS_AZURE_EXC, AZURE_MIN_RELEASE)) self._cloud_environment = None self._network_client = None self._storage_client = None self._resource_client = None self._compute_client = None self._dns_client = None self._web_client = None self._containerservice_client = None self.check_mode = self.module.check_mode self.api_profile = self.module.params.get('api_profile') self.facts_module = facts_module # self.debug = self.module.params.get('debug') # authenticate self.credentials = self._get_credentials(self.module.params) if not self.credentials: if HAS_AZURE_CLI_CORE: self.fail("Failed to get credentials. Either pass as parameters, set environment variables, " "define a profile in ~/.azure/credentials, or log in with Azure CLI (`az login`).") else: self.fail("Failed to get credentials. Either pass as parameters, set environment variables, " "define a profile in ~/.azure/credentials, or install Azure CLI and log in (`az login`).") # cert validation mode precedence: module-arg, credential profile, env, "validate" self._cert_validation_mode = self.module.params['cert_validation_mode'] or self.credentials.get('cert_validation_mode') or \ os.environ.get('AZURE_CERT_VALIDATION_MODE') or 'validate' if self._cert_validation_mode not in ['validate', 'ignore']: self.fail('invalid cert_validation_mode: {0}'.format(self._cert_validation_mode)) # if cloud_environment specified, look up/build Cloud object raw_cloud_env = self.credentials.get('cloud_environment') if self.credentials.get('credentials') is not None and raw_cloud_env is not None: self._cloud_environment = raw_cloud_env elif not raw_cloud_env: self._cloud_environment = azure_cloud.AZURE_PUBLIC_CLOUD # SDK default else: # try to look up "well-known" values via the name attribute on azure_cloud members all_clouds = [x[1] for x in inspect.getmembers(azure_cloud) if isinstance(x[1], azure_cloud.Cloud)] matched_clouds = [x for x in all_clouds if x.name == raw_cloud_env] if len(matched_clouds) == 1: self._cloud_environment = matched_clouds[0] elif len(matched_clouds) > 1: self.fail("Azure SDK failure: more than one cloud matched for cloud_environment name '{0}'".format(raw_cloud_env)) else: if not urlparse.urlparse(raw_cloud_env).scheme: self.fail("cloud_environment must be an endpoint discovery URL or one of {0}".format([x.name for x in all_clouds])) try: self._cloud_environment = azure_cloud.get_cloud_from_metadata_endpoint(raw_cloud_env) except Exception as e: self.fail("cloud_environment {0} could not be resolved: {1}".format(raw_cloud_env, e.message), exception=traceback.format_exc(e)) if self.credentials.get('subscription_id', None) is None and self.credentials.get('credentials') is None: self.fail("Credentials did not include a subscription_id value.") self.log("setting subscription_id") self.subscription_id = self.credentials['subscription_id'] if self.credentials.get('credentials') is not None: # AzureCLI credentials self.azure_credentials = self.credentials['credentials'] elif self.credentials.get('client_id') is not None and \ self.credentials.get('secret') is not None and \ self.credentials.get('tenant') is not None: self.azure_credentials = ServicePrincipalCredentials(client_id=self.credentials['client_id'], secret=self.credentials['secret'], tenant=self.credentials['tenant'], cloud_environment=self._cloud_environment, verify=self._cert_validation_mode == 'validate') elif self.credentials.get('ad_user') is not None and self.credentials.get('password') is not None: tenant = self.credentials.get('tenant') if not tenant: tenant = 'common' # SDK default self.azure_credentials = UserPassCredentials(self.credentials['ad_user'], self.credentials['password'], tenant=tenant, cloud_environment=self._cloud_environment, verify=self._cert_validation_mode == 'validate') else: self.fail("Failed to authenticate with provided credentials. Some attributes were missing. " "Credentials must include client_id, secret and tenant or ad_user and password or " "be logged using AzureCLI.") # common parameter validation if self.module.params.get('tags'): self.validate_tags(self.module.params['tags']) if not skip_exec: res = self.exec_module(**self.module.params) self.module.exit_json(**res) def check_client_version(self, client_type): # Ensure Azure modules are at least 2.0.0rc5. package_version = AZURE_PKG_VERSIONS.get(client_type.__name__, None) if package_version is not None: client_name = package_version.get('package_name') try: client_module = importlib.import_module(client_type.__module__) client_version = client_module.VERSION except RuntimeError: # can't get at the module version for some reason, just fail silently... return expected_version = package_version.get('expected_version') if Version(client_version) < Version(expected_version): self.fail("Installed azure-mgmt-{0} client version is {1}. The supported version is {2}. Try " "`pip install ansible[azure]`".format(client_name, client_version, expected_version)) def exec_module(self, **kwargs): self.fail("Error: {0} failed to implement exec_module method.".format(self.__class__.__name__)) def fail(self, msg, **kwargs): ''' Shortcut for calling module.fail() :param msg: Error message text. :param kwargs: Any key=value pairs :return: None ''' self.module.fail_json(msg=msg, **kwargs) def deprecate(self, msg, version=None): self.module.deprecate(msg, version) def log(self, msg, pretty_print=False): pass # Use only during module development # if self.debug: # log_file = open('azure_rm.log', 'a') # if pretty_print: # log_file.write(json.dumps(msg, indent=4, sort_keys=True)) # else: # log_file.write(msg + u'\n') def validate_tags(self, tags): ''' Check if tags dictionary contains string:string pairs. :param tags: dictionary of string:string pairs :return: None ''' if not self.facts_module: if not isinstance(tags, dict): self.fail("Tags must be a dictionary of string:string values.") for key, value in tags.items(): if not isinstance(value, str): self.fail("Tags values must be strings. Found {0}:{1}".format(str(key), str(value))) def update_tags(self, tags): ''' Call from the module to update metadata tags. Returns tuple with bool indicating if there was a change and dict of new tags to assign to the object. :param tags: metadata tags from the object :return: bool, dict ''' new_tags = copy.copy(tags) if isinstance(tags, dict) else dict() changed = False if isinstance(self.module.params.get('tags'), dict): for key, value in self.module.params['tags'].items(): if not new_tags.get(key) or new_tags[key] != value: changed = True new_tags[key] = value if isinstance(tags, dict): for key, value in tags.items(): if not self.module.params['tags'].get(key): new_tags.pop(key) changed = True return changed, new_tags def has_tags(self, obj_tags, tag_list): ''' Used in fact modules to compare object tags to list of parameter tags. Return true if list of parameter tags exists in object tags. :param obj_tags: dictionary of tags from an Azure object. :param tag_list: list of tag keys or tag key:value pairs :return: bool ''' if not obj_tags and tag_list: return False if not tag_list: return True matches = 0 result = False for tag in tag_list: tag_key = tag tag_value = None if ':' in tag: tag_key, tag_value = tag.split(':') if tag_value and obj_tags.get(tag_key) == tag_value: matches += 1 elif not tag_value and obj_tags.get(tag_key): matches += 1 if matches == len(tag_list): result = True return result def get_resource_group(self, resource_group): ''' Fetch a resource group. :param resource_group: name of a resource group :return: resource group object ''' try: return self.rm_client.resource_groups.get(resource_group) except CloudError as cloud_error: self.fail("Error retrieving resource group {0} - {1}".format(resource_group, cloud_error.message)) except Exception as exc: self.fail("Error retrieving resource group {0} - {1}".format(resource_group, str(exc))) def _get_profile(self, profile="default"): path = expanduser("~/.azure/credentials") try: config = configparser.ConfigParser() config.read(path) except Exception as exc: self.fail("Failed to access {0}. Check that the file exists and you have read " "access. {1}".format(path, str(exc))) credentials = dict() for key in AZURE_CREDENTIAL_ENV_MAPPING: try: credentials[key] = config.get(profile, key, raw=True) except: pass if credentials.get('subscription_id'): return credentials return None def _get_msi_credentials(self, subscription_id_param=None): credentials = MSIAuthentication() subscription_id = subscription_id_param or os.environ.get(AZURE_CREDENTIAL_ENV_MAPPING['subscription_id'], None) if not subscription_id: try: # use the first subscription of the MSI subscription_client = SubscriptionClient(credentials) subscription = next(subscription_client.subscriptions.list()) subscription_id = str(subscription.subscription_id) except Exception as exc: self.fail("Failed to get MSI token: {0}. " "Please check whether your machine enabled MSI or grant access to any subscription.".format(str(exc))) return { 'credentials': credentials, 'subscription_id': subscription_id } def _get_azure_cli_credentials(self): credentials, subscription_id = get_azure_cli_credentials() cloud_environment = get_cli_active_cloud() cli_credentials = { 'credentials': credentials, 'subscription_id': subscription_id, 'cloud_environment': cloud_environment } return cli_credentials def _get_env_credentials(self): env_credentials = dict() for attribute, env_variable in AZURE_CREDENTIAL_ENV_MAPPING.items(): env_credentials[attribute] = os.environ.get(env_variable, None) if env_credentials['profile']: credentials = self._get_profile(env_credentials['profile']) return credentials if env_credentials.get('subscription_id') is not None: return env_credentials return None def _get_credentials(self, params): # Get authentication credentials. self.log('Getting credentials') arg_credentials = dict() for attribute, env_variable in AZURE_CREDENTIAL_ENV_MAPPING.items(): arg_credentials[attribute] = params.get(attribute, None) auth_source = params.get('auth_source', None) if not auth_source: auth_source = os.environ.get('ANSIBLE_AZURE_AUTH_SOURCE', 'auto') if auth_source == 'msi': self.log('Retrieving credenitals from MSI') return self._get_msi_credentials(arg_credentials['subscription_id']) if auth_source == 'cli': if not HAS_AZURE_CLI_CORE: self.fail("Azure auth_source is `cli`, but azure-cli package is not available. Try `pip install azure-cli --upgrade`") try: self.log('Retrieving credentials from Azure CLI profile') cli_credentials = self._get_azure_cli_credentials() return cli_credentials except CLIError as err: self.fail("Azure CLI profile cannot be loaded - {0}".format(err)) if auth_source == 'env': self.log('Retrieving credentials from environment') env_credentials = self._get_env_credentials() return env_credentials if auth_source == 'credential_file': self.log("Retrieving credentials from credential file") profile = params.get('profile', 'default') default_credentials = self._get_profile(profile) return default_credentials # auto, precedence: module parameters -> environment variables -> default profile in ~/.azure/credentials # try module params if arg_credentials['profile'] is not None: self.log('Retrieving credentials with profile parameter.') credentials = self._get_profile(arg_credentials['profile']) return credentials if arg_credentials['subscription_id']: self.log('Received credentials from parameters.') return arg_credentials # try environment env_credentials = self._get_env_credentials() if env_credentials: self.log('Received credentials from env.') return env_credentials # try default profile from ~./azure/credentials default_credentials = self._get_profile() if default_credentials: self.log('Retrieved default profile credentials from ~/.azure/credentials.') return default_credentials try: if HAS_AZURE_CLI_CORE: self.log('Retrieving credentials from AzureCLI profile') cli_credentials = self._get_azure_cli_credentials() return cli_credentials except CLIError as ce: self.log('Error getting AzureCLI profile credentials - {0}'.format(ce)) return None def serialize_obj(self, obj, class_name, enum_modules=None): ''' Return a JSON representation of an Azure object. :param obj: Azure object :param class_name: Name of the object's class :param enum_modules: List of module names to build enum dependencies from. :return: serialized result ''' enum_modules = [] if enum_modules is None else enum_modules dependencies = dict() if enum_modules: for module_name in enum_modules: mod = importlib.import_module(module_name) for mod_class_name, mod_class_obj in inspect.getmembers(mod, predicate=inspect.isclass): dependencies[mod_class_name] = mod_class_obj self.log("dependencies: ") self.log(str(dependencies)) serializer = Serializer(classes=dependencies) return serializer.body(obj, class_name, keep_readonly=True) def get_poller_result(self, poller, wait=5): ''' Consistent method of waiting on and retrieving results from Azure's long poller :param poller Azure poller object :return object resulting from the original request ''' try: delay = wait while not poller.done(): self.log("Waiting for {0} sec".format(delay)) poller.wait(timeout=delay) return poller.result() except Exception as exc: self.log(str(exc)) raise def check_provisioning_state(self, azure_object, requested_state='present'): ''' Check an Azure object's provisioning state. If something did not complete the provisioning process, then we cannot operate on it. :param azure_object An object such as a subnet, storageaccount, etc. Must have provisioning_state and name attributes. :return None ''' if hasattr(azure_object, 'properties') and hasattr(azure_object.properties, 'provisioning_state') and \ hasattr(azure_object, 'name'): # resource group object fits this model if isinstance(azure_object.properties.provisioning_state, Enum): if azure_object.properties.provisioning_state.value != AZURE_SUCCESS_STATE and \ requested_state != 'absent': self.fail("Error {0} has a provisioning state of {1}. Expecting state to be {2}.".format( azure_object.name, azure_object.properties.provisioning_state, AZURE_SUCCESS_STATE)) return if azure_object.properties.provisioning_state != AZURE_SUCCESS_STATE and \ requested_state != 'absent': self.fail("Error {0} has a provisioning state of {1}. Expecting state to be {2}.".format( azure_object.name, azure_object.properties.provisioning_state, AZURE_SUCCESS_STATE)) return if hasattr(azure_object, 'provisioning_state') or not hasattr(azure_object, 'name'): if isinstance(azure_object.provisioning_state, Enum): if azure_object.provisioning_state.value != AZURE_SUCCESS_STATE and requested_state != 'absent': self.fail("Error {0} has a provisioning state of {1}. Expecting state to be {2}.".format( azure_object.name, azure_object.provisioning_state, AZURE_SUCCESS_STATE)) return if azure_object.provisioning_state != AZURE_SUCCESS_STATE and requested_state != 'absent': self.fail("Error {0} has a provisioning state of {1}. Expecting state to be {2}.".format( azure_object.name, azure_object.provisioning_state, AZURE_SUCCESS_STATE)) def get_blob_client(self, resource_group_name, storage_account_name, storage_blob_type='block'): keys = dict() try: # Get keys from the storage account self.log('Getting keys') account_keys = self.storage_client.storage_accounts.list_keys(resource_group_name, storage_account_name) except Exception as exc: self.fail("Error getting keys for account {0} - {1}".format(storage_account_name, str(exc))) try: self.log('Create blob service') if storage_blob_type == 'page': return CloudStorageAccount(storage_account_name, account_keys.keys[0].value).create_page_blob_service() elif storage_blob_type == 'block': return CloudStorageAccount(storage_account_name, account_keys.keys[0].value).create_block_blob_service() else: raise Exception("Invalid storage blob type defined.") except Exception as exc: self.fail("Error creating blob service client for storage account {0} - {1}".format(storage_account_name, str(exc))) def create_default_pip(self, resource_group, location, public_ip_name, allocation_method='Dynamic'): ''' Create a default public IP address <public_ip_name> to associate with a network interface. If a PIP address matching <public_ip_name> exists, return it. Otherwise, create one. :param resource_group: name of an existing resource group :param location: a valid azure location :param public_ip_name: base name to assign the public IP address :param allocation_method: one of 'Static' or 'Dynamic' :return: PIP object ''' pip = None self.log("Starting create_default_pip {0}".format(public_ip_name)) self.log("Check to see if public IP {0} exists".format(public_ip_name)) try: pip = self.network_client.public_ip_addresses.get(resource_group, public_ip_name) except CloudError: pass if pip: self.log("Public ip {0} found.".format(public_ip_name)) self.check_provisioning_state(pip) return pip params = self.network_models.PublicIPAddress( location=location, public_ip_allocation_method=allocation_method, ) self.log('Creating default public IP {0}'.format(public_ip_name)) try: poller = self.network_client.public_ip_addresses.create_or_update(resource_group, public_ip_name, params) except Exception as exc: self.fail("Error creating {0} - {1}".format(public_ip_name, str(exc))) return self.get_poller_result(poller) def create_default_securitygroup(self, resource_group, location, security_group_name, os_type, open_ports): ''' Create a default security group <security_group_name> to associate with a network interface. If a security group matching <security_group_name> exists, return it. Otherwise, create one. :param resource_group: Resource group name :param location: azure location name :param security_group_name: base name to use for the security group :param os_type: one of 'Windows' or 'Linux'. Determins any default rules added to the security group. :param ssh_port: for os_type 'Linux' port used in rule allowing SSH access. :param rdp_port: for os_type 'Windows' port used in rule allowing RDP access. :return: security_group object ''' group = None self.log("Create security group {0}".format(security_group_name)) self.log("Check to see if security group {0} exists".format(security_group_name)) try: group = self.network_client.network_security_groups.get(resource_group, security_group_name) except CloudError: pass if group: self.log("Security group {0} found.".format(security_group_name)) self.check_provisioning_state(group) return group parameters = self.network_models.NetworkSecurityGroup() parameters.location = location if not open_ports: # Open default ports based on OS type if os_type == 'Linux': # add an inbound SSH rule parameters.security_rules = [ self.network_models.SecurityRule(protocol='Tcp', source_address_prefix='*', destination_address_prefix='*', access='Allow', direction='Inbound', description='Allow SSH Access', source_port_range='*', destination_port_range='22', priority=100, name='SSH') ] parameters.location = location else: # for windows add inbound RDP and WinRM rules parameters.security_rules = [ self.network_models.SecurityRule(protocol='Tcp', source_address_prefix='*', destination_address_prefix='*', access='Allow', direction='Inbound', description='Allow RDP port 3389', source_port_range='*', destination_port_range='3389', priority=100, name='RDP01'), self.network_models.SecurityRule(protocol='Tcp', source_address_prefix='*', destination_address_prefix='*', access='Allow', direction='Inbound', description='Allow WinRM HTTPS port 5986', source_port_range='*', destination_port_range='5986', priority=101, name='WinRM01'), ] else: # Open custom ports parameters.security_rules = [] priority = 100 for port in open_ports: priority += 1 rule_name = "Rule_{0}".format(priority) parameters.security_rules.append( self.network_models.SecurityRule(protocol='Tcp', source_address_prefix='*', destination_address_prefix='*', access='Allow', direction='Inbound', source_port_range='*', destination_port_range=str(port), priority=priority, name=rule_name) ) self.log('Creating default security group {0}'.format(security_group_name)) try: poller = self.network_client.network_security_groups.create_or_update(resource_group, security_group_name, parameters) except Exception as exc: self.fail("Error creating default security rule {0} - {1}".format(security_group_name, str(exc))) return self.get_poller_result(poller) @staticmethod def _validation_ignore_callback(session, global_config, local_config, **kwargs): session.verify = False def get_api_profile(self, client_type_name, api_profile_name): profile_all_clients = AZURE_API_PROFILES.get(api_profile_name) if not profile_all_clients: raise KeyError("unknown Azure API profile: {0}".format(api_profile_name)) profile_raw = profile_all_clients.get(client_type_name, None) if not profile_raw: self.module.warn("Azure API profile {0} does not define an entry for {1}".format(api_profile_name, client_type_name)) if isinstance(profile_raw, dict): if not profile_raw.get('default_api_version'): raise KeyError("Azure API profile {0} does not define 'default_api_version'".format(api_profile_name)) return profile_raw # wrap basic strings in a dict that just defines the default return dict(default_api_version=profile_raw) def get_mgmt_svc_client(self, client_type, base_url=None, api_version=None): self.log('Getting management service client {0}'.format(client_type.__name__)) self.check_client_version(client_type) client_argspec = inspect.getargspec(client_type.__init__) client_kwargs = dict(credentials=self.azure_credentials, subscription_id=self.subscription_id, base_url=base_url) api_profile_dict = {} if self.api_profile: api_profile_dict = self.get_api_profile(client_type.__name__, self.api_profile) if not base_url: # most things are resource_manager, don't make everyone specify base_url = self._cloud_environment.endpoints.resource_manager # unversioned clients won't accept profile; only send it if necessary # clients without a version specified in the profile will use the default if api_profile_dict and 'profile' in client_argspec.args: client_kwargs['profile'] = api_profile_dict # If the client doesn't accept api_version, it's unversioned. # If it does, favor explicitly-specified api_version, fall back to api_profile if 'api_version' in client_argspec.args: profile_default_version = api_profile_dict.get('default_api_version', None) if api_version or profile_default_version: client_kwargs['api_version'] = api_version or profile_default_version client = client_type(**client_kwargs) # FUTURE: remove this once everything exposes models directly (eg, containerinstance) try: getattr(client, "models") except AttributeError: def _ansible_get_models(self, *arg, **kwarg): return self._ansible_models setattr(client, '_ansible_models', importlib.import_module(client_type.__module__).models) client.models = types.MethodType(_ansible_get_models, client) # Add user agent for Ansible client.config.add_user_agent(ANSIBLE_USER_AGENT) # Add user agent when running from Cloud Shell if CLOUDSHELL_USER_AGENT_KEY in os.environ: client.config.add_user_agent(os.environ[CLOUDSHELL_USER_AGENT_KEY]) # Add user agent when running from VSCode extension if VSCODEEXT_USER_AGENT_KEY in os.environ: client.config.add_user_agent(os.environ[VSCODEEXT_USER_AGENT_KEY]) if self._cert_validation_mode == 'ignore': client.config.session_configuration_callback = self._validation_ignore_callback return client @property def storage_client(self): self.log('Getting storage client...') if not self._storage_client: self._storage_client = self.get_mgmt_svc_client(StorageManagementClient, base_url=self._cloud_environment.endpoints.resource_manager, api_version='2017-10-01') return self._storage_client @property def storage_models(self): self.log('Getting storage models...') return StorageManagementClient.models("2017-10-01") @property def network_client(self): self.log('Getting network client') if not self._network_client: self._network_client = self.get_mgmt_svc_client(NetworkManagementClient, base_url=self._cloud_environment.endpoints.resource_manager, api_version='2017-11-01') return self._network_client @property def network_models(self): self.log("Getting network models...") return NetworkManagementClient.models("2017-11-01") @property def rm_client(self): self.log('Getting resource manager client') if not self._resource_client: self._resource_client = self.get_mgmt_svc_client(ResourceManagementClient, base_url=self._cloud_environment.endpoints.resource_manager, api_version='2017-05-10') return self._resource_client @property def rm_models(self): self.log("Getting resource manager models") return ResourceManagementClient.models("2017-05-10") @property def compute_client(self): self.log('Getting compute client') if not self._compute_client: self._compute_client = self.get_mgmt_svc_client(ComputeManagementClient, base_url=self._cloud_environment.endpoints.resource_manager, api_version='2017-03-30') return self._compute_client @property def compute_models(self): self.log("Getting compute models") return ComputeManagementClient.models("2017-03-30") @property def dns_client(self): self.log('Getting dns client') if not self._dns_client: self._dns_client = self.get_mgmt_svc_client(DnsManagementClient, base_url=self._cloud_environment.endpoints.resource_manager) return self._dns_client @property def web_client(self): self.log('Getting web client') if not self._web_client: self._web_client = self.get_mgmt_svc_client(WebSiteManagementClient, base_url=self._cloud_environment.endpoints.resource_manager) return self._web_client @property def containerservice_client(self): self.log('Getting container service client') if not self._containerservice_client: self._containerservice_client = self.get_mgmt_svc_client(ContainerServiceClient, base_url=self._cloud_environment.endpoints.resource_manager) return self._containerservice_client