def send_event(module, service_key, event_type, desc, incident_key=None, client=None, client_url=None): url = "https://events.pagerduty.com/generic/2010-04-15/create_event.json" headers = {"Content-type": "application/json"} data = { "service_key": service_key, "event_type": event_type, "incident_key": incident_key, "description": desc, "client": client, "client_url": client_url } response, info = fetch_url(module, url, method='post', headers=headers, data=json.dumps(data)) if info['status'] != 200: module.fail_json(msg="failed to %s. Reason: %s" % (event_type, info['msg'])) json_out = json.loads(response.read()) return json_out
def test_fetch_url_connectionerror(open_url_mock, fake_ansible_module): open_url_mock.side_effect = ConnectionError('TESTS') with pytest.raises(FailJson) as excinfo: fetch_url(fake_ansible_module, 'http://ansible.com/') assert excinfo.value.kwargs['msg'] == 'TESTS' assert 'http://ansible.com/' == excinfo.value.kwargs['url'] assert excinfo.value.kwargs['status'] == -1 open_url_mock.side_effect = ValueError('TESTS') with pytest.raises(FailJson) as excinfo: fetch_url(fake_ansible_module, 'http://ansible.com/') assert excinfo.value.kwargs['msg'] == 'TESTS' assert 'http://ansible.com/' == excinfo.value.kwargs['url'] assert excinfo.value.kwargs['status'] == -1
def test_fetch_url(open_url_mock, fake_ansible_module): r, info = fetch_url(fake_ansible_module, 'http://ansible.com/') dummy, kwargs = open_url_mock.call_args open_url_mock.assert_called_once_with('http://ansible.com/', client_cert=None, client_key=None, cookies=kwargs['cookies'], data=None, follow_redirects='urllib2', force=False, force_basic_auth='', headers=None, http_agent='ansible-httpget', last_mod_time=None, method=None, timeout=10, url_password='', url_username='', use_proxy=True, validate_certs=True, use_gssapi=False, unix_socket=None, ca_path=None)
def run(self): result = { 'nginx_status_facts': { 'active_connections': None, 'accepts': None, 'handled': None, 'requests': None, 'reading': None, 'writing': None, 'waiting': None, 'data': None, } } (response, info) = fetch_url(module=module, url=self.url, force=True, timeout=self.timeout) if not response: module.fail_json(msg="No valid or no response from url %s within %s seconds (timeout)" % (self.url, self.timeout)) data = to_text(response.read(), errors='surrogate_or_strict') if not data: return result result['nginx_status_facts']['data'] = data expr = r'Active connections: ([0-9]+) \nserver accepts handled requests\n ([0-9]+) ([0-9]+) ([0-9]+) \n' \ r'Reading: ([0-9]+) Writing: ([0-9]+) Waiting: ([0-9]+)' match = re.match(expr, data, re.S) if match: result['nginx_status_facts']['active_connections'] = int(match.group(1)) result['nginx_status_facts']['accepts'] = int(match.group(2)) result['nginx_status_facts']['handled'] = int(match.group(3)) result['nginx_status_facts']['requests'] = int(match.group(4)) result['nginx_status_facts']['reading'] = int(match.group(5)) result['nginx_status_facts']['writing'] = int(match.group(6)) result['nginx_status_facts']['waiting'] = int(match.group(7)) return result
def send_request(self, commands, output='text'): commands = to_list(commands) if self._enable: commands.insert(0, self._enable) body = self._request_builder(commands, output) data = self._module.jsonify(body) headers = {'Content-Type': 'application/json-rpc'} timeout = self._module.params['provider']['timeout'] use_proxy = self._module.params['provider']['use_proxy'] response, headers = fetch_url( self._module, self._url, data=data, headers=headers, method='POST', timeout=timeout, use_proxy=use_proxy ) if headers['status'] != 200: self._module.fail_json(**headers) try: data = response.read() response = self._module.from_json(to_text(data, errors='surrogate_then_replace')) except ValueError: self._module.fail_json(msg='unable to load response from device', data=data) if self._enable and 'result' in response: response['result'].pop(0) return response
def _post_or_patch(self, api_call, method, data): # This helps with tags when we have the full API resource href to update. if API_URL not in api_call: api_endpoint = API_URL + api_call else: api_endpoint = api_call headers = self._auth_header.copy() if data is not None: # Sanitize data dictionary # Deepcopy: Duplicate the data object for iteration, because # iterating an object and changing it at the same time is insecure for k, v in deepcopy(data).items(): if v is None: del data[k] data = self._module.jsonify(data) headers['Content-type'] = 'application/json' resp, info = fetch_url(self._module, api_endpoint, headers=headers, method=method, data=data, timeout=self._module.params['api_timeout']) if info['status'] in (200, 201): return self._module.from_json(to_text(resp.read(), errors='surrogate_or_strict')) elif info['status'] == 204: return None else: self._module.fail_json(msg='Failure while calling the cloudscale.ch API with %s for ' '"%s".' % (method, api_call), fetch_url_info=info)
def send(self, method, path, data=None, headers=None): url = self._url_builder(path) data = self.module.jsonify(data) resp, info = fetch_url(self.module, url, data=data, headers=self.headers, method=method) return Response(resp, info)
def login(self): ''' Log in to MSO ''' # Perform login request self.url = urljoin(self.baseuri, 'auth/login') payload = { 'username': self.params.get('username'), 'password': self.params.get('password') } resp, auth = fetch_url(self.module, self.url, data=json.dumps(payload), method='POST', headers=self.headers, timeout=self.params.get('timeout'), use_proxy=self.params.get('use_proxy')) # Handle MSO response if auth.get('status') != 201: self.response = auth.get('msg') self.status = auth.get('status') self.fail_json(msg='Authentication failed: {msg}'.format(**auth)) payload = json.loads(resp.read()) self.headers['Authorization'] = 'Bearer {token}'.format(**payload)
def send_msg_v1(module, token, room, msg_from, msg, msg_format='text', color='yellow', notify=False, api=MSG_URI_V1): '''sending message to hipchat v1 server''' params = {} params['room_id'] = room params['from'] = msg_from[:15] # max length is 15 params['message'] = msg params['message_format'] = msg_format params['color'] = color params['api'] = api params['notify'] = int(notify) url = api + MSG_URI_V1 + "?auth_token=%s" % (token) data = urlencode(params) if module.check_mode: # In check mode, exit before actually sending the message module.exit_json(changed=False) response, info = fetch_url(module, url, data=data) if info['status'] == 200: return response.read() else: module.fail_json(msg="failed to send message, return status=%s" % str(info['status']))
def request(url, user, passwd, timeout, data=None, method=None): if data: data = json.dumps(data) # NOTE: fetch_url uses a password manager, which follows the # standard request-then-challenge basic-auth semantics. However as # JIRA allows some unauthorised operations it doesn't necessarily # send the challenge, so the request occurs as the anonymous user, # resulting in unexpected results. To work around this we manually # inject the basic-auth header up-front to ensure that JIRA treats # the requests as authorized for this user. auth = to_text(base64.b64encode(to_bytes('{0}:{1}'.format(user, passwd), errors='surrogate_or_strict'))) response, info = fetch_url(module, url, data=data, method=method, timeout=timeout, headers={'Content-Type': 'application/json', 'Authorization': "Basic %s" % auth}) if info['status'] not in (200, 201, 204): module.fail_json(msg=info['msg']) body = response.read() if body: return json.loads(to_text(body, errors='surrogate_or_strict')) else: return {}
def request_rundeck_api(self, query, data=None, method="GET"): resp, info = fetch_url(self.module, "%s/api/%d/%s" % (self.module.params["url"], self.module.params["api_version"], query), data=json.dumps(data), method=method, headers={ "Content-Type": "application/json", "Accept": "application/json", "X-Rundeck-Auth-Token": self.module.params["token"] }) self.handle_http_code_if_needed(info) if resp is not None: resp = resp.read() if resp != "": try: json_resp = json.loads(resp) return json_resp, info except ValueError as e: self.module.fail_json( msg= "Rundeck response was not a valid JSON. Exception was: %s. " "Object was: %s" % (to_native(e), resp)) return resp, info
def get_token(module): """ :param module: :return: token """ # defaulting the value for transport_protocol to be : http transport_protocol = 'http' if module.params['https'] or module.params['validate_certs'] is True: transport_protocol = 'https' url = transport_protocol + "://" + module.params['iap_fqdn'] + ":" + module.params['iap_port'] + "/login" username = module.params['username'] password = module.params['password'] login = { "user": { "username": username, "password": password } } json_body = module.jsonify(login) headers = {} headers['Content-Type'] = 'application/json' # Using fetch url instead of requests response, info = fetch_url(module, url, data=json_body, headers=headers) response_code = str(info['status']) if info['status'] not in [200, 201]: module.fail_json(msg="Failed to connect to Itential Automation Platform" + response_code) response = response.read() module.exit_json(changed=True, token=response)
def save_config(self): url = '%s://%s/nitro/v1/config/nsconfig?action=save' % ( self._module.params['nitro_protocol'], self._module.params['nsip'], ) data = self._module.jsonify( { 'nsconfig': {}, } ) r, info = fetch_url( self._module, url=url, headers=self._headers, data=data, method='POST', ) result = {} self.edit_response_data(r, info, result, success_status=200) self._module_result['changed'] = False return result
def delete_by_args(self): if self._module.params['resource'] is None: self.fail_module(msg='NITRO resource is undefined.') if self._module.params['args'] is None: self.fail_module(msg='NITRO args is undefined.') url = '%s://%s/nitro/v1/config/%s' % ( self._module.params['nitro_protocol'], self._module.params['nsip'], self._module.params['resource'], ) args_dict = self._module.params['args'] args = ','.join(['%s:%s' % (k, args_dict[k]) for k in args_dict]) args = 'args=' + args url = '?'.join([url, args]) r, info = fetch_url( self._module, url=url, headers=self._headers, method='DELETE', ) result = {} self.edit_response_data(r, info, result, success_status=200) if result['nitro_errorcode'] == 0: self._module_result['changed'] = True else: self._module_result['changed'] = False return result
def count(self): if self._module.params['resource'] is None: self.fail_module(msg='NITRO resource is undefined.') url = '%s://%s/nitro/v1/config/%s?count=yes' % ( self._module.params['nitro_protocol'], self._module.params['nsip'], self._module.params['resource'], ) r, info = fetch_url( self._module, url=url, headers=self._headers, method='GET', ) result = {} self.edit_response_data(r, info, result) if result['http_response_body'] != '': data = self._module.from_json(result['http_response_body']) result['nitro_errorcode'] = data['errorcode'] result['nitro_message'] = data['message'] result['nitro_severity'] = data['severity'] if self._module.params['resource'] in data: result['nitro_count'] = data[self._module.params['resource']][0]['__count'] self._module_result['changed'] = False return result
def get_filtered(self): if self._module.params['resource'] is None: self.fail_module(msg='NITRO resource is undefined.') if self._module.params['filter'] is None: self.fail_module(msg='NITRO filter is undefined.') keys = list(self._module.params['filter'].keys()) filter_key = keys[0] filter_value = self._module.params['filter'][filter_key] filter_str = '%s:%s' % (filter_key, filter_value) url = '%s://%s/nitro/v1/config/%s?filter=%s' % ( self._module.params['nitro_protocol'], self._module.params['nsip'], self._module.params['resource'], filter_str, ) r, info = fetch_url( self._module, url=url, headers=self._headers, method='GET', ) result = {} self.edit_response_data(r, info, result, success_status=200) self.handle_get_return_object(result) self._module_result['changed'] = False return result
def delete(self): if self._module.params['resource'] is None: self.fail_module(msg='NITRO resource is undefined.') if self._module.params['name'] is None: self.fail_module(msg='NITRO resource is undefined.') # Deletion by name takes precedence over deletion by attributes url = '%s://%s/nitro/v1/config/%s/%s' % ( self._module.params['nitro_protocol'], self._module.params['nsip'], self._module.params['resource'], self._module.params['name'], ) r, info = fetch_url( self._module, url=url, headers=self._headers, method='DELETE', ) result = {} self.edit_response_data(r, info, result, success_status=200) if result['nitro_errorcode'] == 0: self._module_result['changed'] = True else: self._module_result['changed'] = False return result
def add(self): # Check if required attributes are present if self._module.params['resource'] is None: self.fail_module(msg='NITRO resource is undefined.') if self._module.params['attributes'] is None: self.fail_module(msg='NITRO resource attributes are undefined.') url = '%s://%s/nitro/v1/config/%s' % ( self._module.params['nitro_protocol'], self._module.params['nsip'], self._module.params['resource'], ) data = self._module.jsonify({self._module.params['resource']: self._module.params['attributes']}) r, info = fetch_url( self._module, url=url, headers=self._headers, data=data, method='POST', ) result = {} self.edit_response_data(r, info, result, success_status=201) if result['nitro_errorcode'] == 0: self._module_result['changed'] = True else: self._module_result['changed'] = False return result
def get(self): if self._module.params['resource'] is None: self.fail_module(msg='NITRO resource is undefined.') if self._module.params['name'] is None: self.fail_module(msg='NITRO resource name is undefined.') url = '%s://%s/nitro/v1/config/%s/%s' % ( self._module.params['nitro_protocol'], self._module.params['nsip'], self._module.params['resource'], self._module.params['name'], ) r, info = fetch_url( self._module, url=url, headers=self._headers, method='GET', ) result = {} self.edit_response_data(r, info, result, success_status=200) self.handle_get_return_object(result) self._module_result['changed'] = False return result
def run(self, priority, msg, title): ''' Do, whatever it is, we do. ''' url = '%s/1/messages.json' % (self.base_uri) # parse config options = dict(user=self.user, token=self.token, priority=priority, message=msg) if title is not None: options = dict(options, title=title) data = urlencode(options) headers = {"Content-type": "application/x-www-form-urlencoded"} r, info = fetch_url(self.module, url, method='POST', data=data, headers=headers) if info['status'] != 200: raise Exception(info) return r.read()
def _get_url_data(self, url, what=None, msg_status=None, msg_exception=None, **kwargs): # Compose default messages if msg_status is None: msg_status = "Cannot get %s" % what if msg_exception is None: msg_exception = "Retrieval of %s failed." % what # Get the URL data try: response, info = fetch_url(self.module, url, timeout=self.timeout, cookies=self.cookies, headers=self.crumb, **kwargs) if info['status'] != 200: self.module.fail_json(msg=msg_status, details=info['msg']) except Exception as e: self.module.fail_json(msg=msg_exception, details=to_native(e)) return response
def update_repo_importer_config(self, repo_id, **kwargs): url = "%s/pulp/api/v2/repositories/%s/importers/" % (self.host, repo_id) data = dict() importer_config = dict() for key, value in kwargs.items(): if value is not None: importer_config[key] = value data['importer_config'] = importer_config if self.repo_type == 'rpm': data['importer_type_id'] = "yum_importer" response, info = fetch_url(self.module, url, data=json.dumps(data), method='POST') if info['status'] != 202: self.module.fail_json( msg="Failed to set the repo importer configuration", status_code=info['status'], response=info['msg'], importer_config=importer_config, url=url)
def verify_tasks_completed(self, response_dict): for task in response_dict['spawned_tasks']: task_url = "%s%s" % (self.host, task['_href']) while True: response, info = fetch_url(self.module, task_url, data='', method='GET') if info['status'] != 200: self.module.fail_json( msg="Failed to check async task status.", status_code=info['status'], response=info['msg'], url=task_url) task_dict = json.load(response) if task_dict['state'] == 'finished': return True if task_dict['state'] == 'error': self.module.fail_json( msg="Asynchronous task failed to complete.", error=task_dict['error']) sleep(2)
def request(self, api_url, method, data=None, headers=None): headers = headers or {} if self.access_token: headers.update({ 'Authorization': 'Bearer {0}'.format(self.access_token), }) if isinstance(data, dict): data = self.module.jsonify(data) headers.update({ 'Content-type': 'application/json', }) response, info = fetch_url( module=self.module, url=api_url, method=method, headers=headers, data=data, force=True, ) content = {} if response is not None: body = to_text(response.read()) if body: content = json.loads(body) return info, content
def request(module, api_url, project, path, access_token, private_token, rawdata='', method='GET'): url = "%s/v4/projects/%s%s" % (api_url, quote_plus(project), path) headers = {} if access_token: headers['Authorization'] = "Bearer %s" % access_token else: headers['Private-Token'] = private_token headers['Accept'] = "application/json" headers['Content-Type'] = "application/json" response, info = fetch_url(module=module, url=url, headers=headers, data=rawdata, method=method) status = info['status'] content = "" if response: content = response.read() if status == 204: return True, content elif status == 200 or status == 201: return True, json.loads(content) else: return False, str(status) + ": " + content
def request(self, path, method=None, payload=None): """Generic HTTP method for Meraki requests.""" self.path = path self.define_protocol() if method is not None: self.method = method self.url = '{protocol}://{host}/api/v0/{path}'.format( path=self.path.lstrip('/'), **self.params) resp, info = fetch_url( self.module, self.url, headers=self.headers, data=payload, method=self.method, timeout=self.params['timeout'], use_proxy=self.params['use_proxy'], ) self.response = info['msg'] self.status = info['status'] try: return json.loads(to_native(resp.read())) except Exception: pass
def mas_login(self): url = '%s://%s/nitro/v1/config/login' % ( self._module.params['nitro_protocol'], self._module.params['nsip'], ) login_credentials = { 'login': { 'username': self._module.params['nitro_user'], 'password': self._module.params['nitro_pass'], } } data = 'object=\n%s' % self._module.jsonify(login_credentials) r, info = fetch_url( self._module, url=url, headers=self._headers, data=data, method='POST', ) print(r, info) result = {} self.edit_response_data(r, info, result, success_status=200) if result['nitro_errorcode'] == 0: body_data = self._module.from_json(result['http_response_body']) result['nitro_auth_token'] = body_data['login'][0]['sessionid'] self._module_result['changed'] = False return result
def post_twilio_api(module, account_sid, auth_token, msg, from_number, to_number, media_url=None): URI = "https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json" \ % (account_sid,) AGENT = "Ansible" data = {'From': from_number, 'To': to_number, 'Body': msg} if media_url: data['MediaUrl'] = media_url encoded_data = urlencode(data) headers = { 'User-Agent': AGENT, 'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'application/json', } # Hack module params to have the Basic auth params that fetch_url expects module.params['url_username'] = account_sid.replace('\n', '') module.params['url_password'] = auth_token.replace('\n', '') return fetch_url(module, URI, data=encoded_data, headers=headers)
def axapi_call(module, url, post=None): ''' Returns a datastructure based on the result of the API call ''' rsp, info = fetch_url(module, url, data=post) if not rsp or info['status'] >= 400: module.fail_json( msg="failed to connect (status code %s), error was %s" % (info['status'], info.get('msg', 'no error given'))) try: raw_data = rsp.read() data = json.loads(raw_data) except ValueError: # at least one API call (system.action.write_config) returns # XML even when JSON is requested, so do some minimal handling # here to prevent failing even when the call succeeded if 'status="ok"' in raw_data.lower(): data = {"response": {"status": "OK"}} else: data = {"response": {"status": "fail", "err": {"msg": raw_data}}} except Exception: module.fail_json(msg="could not read the result from the host") finally: rsp.close() return data
def main(): module = AnsibleModule( supports_check_mode=True, argument_spec=dict( url=dict(type='str', required=True), api_key=dict(type='str', required=True, no_log=True), text=dict(type='str', required=True), channel=dict(type='str', default=None), username=dict(type='str', default='Ansible'), icon_url=dict(type='str', default='https://www.ansible.com/favicon.ico'), validate_certs=dict(default='yes', type='bool'), )) # init return dict result = dict(changed=False, msg="OK") # define webhook webhook_url = "{0}/hooks/{1}".format(module.params['url'], module.params['api_key']) result['webhook_url'] = webhook_url # define payload payload = {} for param in ['text', 'channel', 'username', 'icon_url']: if module.params[param] is not None: payload[param] = module.params[param] payload = module.jsonify(payload) result['payload'] = payload # http headers headers = { 'Content-Type': 'application/json', 'Accept': 'application/json', } # notes: # Nothing is done in check mode # it'll pass even if your server is down or/and if your token is invalid. # If someone find good way to check... # send request if not in test mode if module.check_mode is False: response, info = fetch_url(module=module, url=webhook_url, headers=headers, method='POST', data=payload) # something's wrong if info['status'] != 200: # some problem result[ 'msg'] = "Failed to send mattermost message, the error was: {0}".format( info['msg']) module.fail_json(**result) # Looks good module.exit_json(**result)