def controlVNF(self, action, arguments): if self.VNF_STATUS < 0: return if not self.VNF_UP: return -1 if self.VNF_REST == None: management = self.managementVNF() if isinstance(management, basestring): self.VNF_REST = REST(management) else: return -2 if action == 'function_start': return self.VNF_REST.postStart() if action == 'function_stop': return self.VNF_REST.postStop() if action == 'function_replace': return self.VNF_REST.postFunction(arguments[0]) if action == 'function_run': return self.VNF_REST.getRunning() if action == 'function_data': return self.VNF_REST.getFunction() if action == 'function_id': return self.VNF_REST.getIdentification() if action == 'function_metrics': return self.VNF_REST.getMetrics() if action == 'function_log': return self.VNF_REST.getLog()
def check_hostname_valid(self, path=None): """Checks hostname has DNS entry and responds to HTTP GET""" try: # Check if the DNS name resolves self.ip_address = socket.gethostbyname('cn%s.awmdm.com' % self.instance) # Test HTTP Request try: # GET index rest = REST('cn%s.awmdm.com/%s' % (self.instance, path), timeout=2, retries=2) if rest.get('').status_code == 200: self.debug_print('\t Active') self.active = True else: # Non 200 response, mark as inactive self.active = False # Catch Timeout or Connection Errors and mark as inactive except (requests.exceptions.ReadTimeout, requests.exceptions.ConnectionError): self.debug_print('\t - HTTP timeout') self.active = False # Catch DNS SERVFAIL except socket.gaierror: self.debug_print('\t - DNS error') self.active = False return self.active
def get_version(self): """Get instance version""" # Create REST instance rest = REST(url='cn%s.awmdm.com' % self.instance, debug=self.debug) # At some stage the version file changed, try both urls = ['/api/help/local.json', '/api/system/help/localjson'] # Try the first URL response = rest.get(urls[0]) # If that 404's try the second URL if response.status_code == 404: response = rest.get(urls[1]) # If this 200 OKs if response.status_code == 200: # Get the text, parse is versions = json.loads(response.text) version = versions['apis'][0]['products'][0] # Regex it to remove AirWatch and VMWare Workspace ONE UEM strings # Leaving just the version number version = re.match(r'(AirWatch|VMware Workspace ONE UEM);(.*)', version, re.M | re.I).group(2) self.version = version self.debug_print('\t Version: %s' % self.version) # API could be behind an auth wall # Leave as None return self.version
def get_stops(self): """Get the PT stops in the area""" with open('api_key.json') as json_file: api_key = json.load(json_file)['api_key'] # Set headers headers = { 'Accept': 'application/json', 'Authorization': 'apikey %s' % api_key } # Create instance of configured REST rest = REST(url='api.transport.nsw.gov.au', debug=self.debug, headers=headers) # URL to get url = "/v1/tp/departure_mon?outputFormat=rapidJSON&coordOutputFormat=EPSG%3A4326&mode=direct&type_dm=stop&name_dm=10111010&itdDate=20161001&itdTime=1200&departureMonitorMacro=true&TfNSWDM=true&version=10.2.1.42" response = rest.get(url) # Check response was good self.check_http_response(response.status_code) print(response.text) return True
class GPIO: # set up databases independent = REST("https://marsoasis.firebaseio.com/") softwaredev = REST("https://cumarsoasis.firebaseio.com/") def __init__(self, name, pin): # assign table self.name = name # assign pin self.pin = pin # set path for device file with pin self.path = "/sys/devices/virtual/gpio/gpio" + str(pin) + "/value" def check_status(self): # open up the device device = open(self.path) # read in the value as an integer value = int(device.read().rstrip()) # close the device device.close() # look up the state state = lookup_key[self.pin][value] return state def toggle(self): # open the device for reading device = open(self.path) # read in the value as an integer value = int(device.read().rstrip()) # close the device device.close() # flip the switch if value == 0: value = 1 elif value == 1: value = 0 else: print "throw error" # open the device for writing device = open(self.path, 'w') # write the new value device.write(str(value)) # close the device device.close() print self.check_status()
def test_custom_header(): """Test custom header function""" header_content = randomString() header_key = randomString() headers = {header_key: header_content} rest_header = REST(url='postman-echo.com', headers=headers, debug=True) response = json.loads(rest_header.get('/headers').text) assert response['headers'][header_key] == header_content
class FMRestfulMethods_2(Resource): def __init__(self): self._rest = REST() @auth.login_required def post(self): if not get_pw(auth.username()): abort(404, message='Unauthorized User') data = request.get_json(force=True) result = self._rest.insertFarmerMarket(data) self._rest.destroy() return jsonify(result)
def get_location(self): """Lookup IP location""" # For some reason this IP API fails without a user agent headers = {'User-Agent': 'Mozilla/5.0'} # Create REST instance to Geo check IP rest = REST(url='ip-api.com', protocol='http', debug=self.debug, headers=headers) # Query API response = rest.get('/json/%s' % self.ip_address) # If succesful parse json and set location if response.status_code == 200: response = json.loads(response.text) self.location = "\"%s, %s, %s\", %s, %s" % ( response['city'], response['regionName'], response['country'], response['as'], response['org']) return self.location
def scriptVNF(self, scriptTasks, scriptError, functionPath): if self.VNF_STATUS < 0: return if not self.VNF_UP: return -1 if self.VNF_REST == None: management = self.managementVNF() if isinstance(management, basestring): self.VNF_REST = REST(management) else: return -2 resultCheck = self.VNF_REST.scriptExecution(scriptTasks, scriptError, functionPath) if isinstance(resultCheck, list): return resultCheck else: if resultCheck < 0: return resultCheck - 2 else: return resultCheck
class FMRestfulMethods_1(Resource): def __init__(self): self._rest = REST() @auth.login_required def get(self, paramName, value): if not get_pw(auth.username()): abort(404, message='Unauthorized User') result = self._rest.getFarmerMarket(paramName, value) self._rest.destroy() return result @auth.login_required def delete(self, paramName, value): if not get_pw(auth.username()): abort(404, message='Unauthorized User') result = {} if paramName == 'registerID': result = self._rest.deleteFarmerMarket(value) self._rest.destroy() else: result['message'] = 'Invalid parameter!' return jsonify(result) @auth.login_required def put(self, paramName, value): if not get_pw(auth.username()): abort(404, message='Unauthorized User') result = {} if paramName == 'update': data = request.get_json(force=True) result = self._rest.updateFarmerMarket(data, value) self._rest.destroy() else: result['message'] = 'Invalid parameter!' return jsonify(result)
def check_redirection(self): """Checks if an instance redirects to a company hostname""" # Get base URL rest = REST(url='cn%s.awmdm.com' % self.instance, debug=self.debug) response = rest.get('') # If response array isn't empty then we have been redirected if response.history: # Get the final URL and extract the hostname in regex try: # Use regex to extract URL, for SAML catch identity service / login #TODO: Fix nike login match hostname = re.match( r'https:\/\/(.*)\/(AirWatch|IdentityService)', response.url, re.M | re.I).group(1) # Unable to regex match, just use the whole URL except AttributeError: hostname = response.url self.hostname = hostname self.debug_print('\t Hostname: %s' % self.hostname) return self.hostname
"""Tests REST module""" import json import random import string from REST import REST # Thanks to https://postman-echo.com # For the demo REST API rest = REST(url='postman-echo.com', debug=True) # Generate random data for testing def randomString(stringLength=15): """Generate a random string of fixed length """ letters = string.ascii_lowercase return ''.join(random.choice(letters) for i in range(stringLength)) def test_rest_get(): """Tests GET function""" test_param1 = randomString() test_param1_value = randomString() test_param2 = randomString() test_param2_value = randomString() response = rest.get( "/get?%s=%s&%s=%s" % (test_param1, test_param1_value, test_param2, test_param2_value)) assert response.status_code == 200
def __init__(self, url=None, ssl_verify=False, accept="application/json, */*", content_type="application/json", user_agent="Bluecat_RESTinstance", proxies={}, schema={}, spec={}, instances=[]): self.request = { 'method': None, 'url': None, 'scheme': "", 'netloc': "", 'path': "", 'query': {}, 'body': None, 'headers': { 'Accept': REST._input_string(accept), 'Content-Type': REST._input_string(content_type), 'User-Agent': REST._input_string(user_agent) }, 'proxies': REST._input_object(proxies), 'timeout': [None, None], 'cert': None, 'sslVerify': REST._input_ssl_verify(ssl_verify), 'allowRedirects': True } if url: url = REST._input_string(url) if url.endswith('/'): url = url[:-1] if not url.startswith(("http://", "https://")): url = "http://" + url url_parts = urlparse(url) self.request['scheme'] = url_parts.scheme self.request['netloc'] = url_parts.netloc self.request['path'] = url_parts.path if not self.request['sslVerify']: disable_warnings() self.schema = { "$schema": "http://json-schema.org/draft-07/schema#", "title": url, "description": None, "default": True, "examples": [], "type": "object", "properties": { "request": { "type": "object", "properties": {} }, "response": { "type": "object", "properties": {} } } } self.schema.update(self._input_object(schema)) self.spec = {} self.spec.update(self._input_object(spec)) self.instances = self._input_array(instances)
def __init__(self): self._rest = REST()
class VNF: ID = '' MEMORY = 0 VCPU = 0 MANAGEMENT_MAC = '' INTERFACES = [] VNF_EXIST = False VNF_UP = False VNF_STATUS = 0 VNF_JSON = '' VNF_REST = None # __init__: redirects to the correct function to initialize the class, for file interfaces use set 'interface' # as none. def __init__(self, configurationPath, interfaces): if interfaces != None: self.outInterfaces(configurationPath, interfaces) else: self.inInterfaces(configurationPath) #inInterfaces: receives the JSON VNF configuration, parses it, apply data in destiny attributes and # validates the read data and check for VNF existence. # -5 = file does not exist def inInterfaces(self, configurationPath): if path.isfile(configurationPath): self.VNF_JSON = configurationPath with open(self.VNF_JSON) as dataVNF: parsedVNF = json.load(dataVNF) else: self.VNF_STATUS = -5 return -5 if 'ID' in parsedVNF: self.ID = parsedVNF['ID'] if 'MEMORY' in parsedVNF: self.MEMORY = parsedVNF['MEMORY'] if 'VCPU' in parsedVNF: self.VCPU = parsedVNF['VCPU'] if 'MANAGEMENT_MAC' in parsedVNF: self.MANAGEMENT_MAC = parsedVNF['MANAGEMENT_MAC'] if 'INTERFACES' in parsedVNF: self.INTERFACES = parsedVNF['INTERFACES'] self.fullValidation() # outInterfaces : receives the JSON VNF configuration and ignores the interface data, in this case # it receives as argument too, parses it, apply data in destiny attributes and validates # the read data and check for VNF existence. # -5 = file does not exist def outInterfaces(self, configurationPath, interfaces): if path.isfile(configurationPath): self.VNF_JSON = configurationPath with open(self.VNF_JSON) as dataVNF: parsedVNF = json.load(dataVNF) else: self.VNF_STATUS = -5 return -5 if 'ID' in parsedVNF: self.ID = parsedVNF['ID'] if 'MEMORY' in parsedVNF: self.MEMORY = parsedVNF['MEMORY'] if 'VCPU' in parsedVNF: self.VCPU = parsedVNF['VCPU'] if 'MANAGEMENT_MAC' in parsedVNF: self.MANAGEMENT_MAC = parsedVNF['MANAGEMENT_MAC'] self.INTERFACES = interfaces self.fullValidation() #fullValidation: verify all attributes checking if it contains possible values, check the VNF existence # in database. # -4 = VNF already exists created by an external agent # -3 = VNF already in use by an external agent or other VNFServer instance # -2 = problems in INTERFACES data # -1 = problems in GENERAL data # 0 = valid configuration, VNF is not in the database and is free for creation # 1 = valid configuration, VNF already in the database def fullValidation(self): if self.ID == '' or self.MEMORY <= 0 or self.VCPU <= 0 or self.MANAGEMENT_MAC == '': self.VNF_STATUS = -1 return -1 for iface in self.INTERFACES: if 'ID' not in iface or 'MAC' not in iface: self.VNF_STATUS = -2 return -2 existingImages = glob('./IMAGES/*') for images in existingImages: if images[9:] == self.ID: self.VNF_EXIST = True break upVMs = check_output(['virsh', 'list']).split('\n') for index in range(2, len(upVMs)-2): if [VM for VM in upVMs[index].replace(' ', ',').split(',') if VM != ''][1] == self.ID: self.VNF_UP = True break identicalVM = False allVMs = check_output(['virsh', 'list', '--all']).split('\n') for index in range(2, len(allVMs)-2): if [VM for VM in allVMs[index].replace(' ', ',').split(',') if VM != ''][1] == self.ID: identicalVM = True break if self.VNF_EXIST: if self.VNF_UP: self.VNF_STATUS = -3 return -3 else: if identicalVM: self.VNF_STATUS = -4 return -4 else: self.VNF_STATUS = 1 return 1 else: if identicalVM: self.VNF_STATUS = -4 return -4 self.VNF_STATUS = 0 return 0 #modifyValidation: verify only attributes checking if it contains possible values # -2 = problems in INTERFACES data # -1 = problems in GENERAL data # 1 = valid configuration, VNF ready for modification def modifyValidation(self): if self.ID == '' or self.MEMORY <= 0 or self.VCPU <= 0 or self.MANAGEMENT_MAC == '': self.VNF_STATUS = -1 return -1 for iface in self.INTERFACES: if 'ID' not in iface or 'MAC' not in iface: self.VNF_STATUS = -2 return -2 self.VNF_STATUS = 1 return 1 #createVNF: copy data file in VNF does not exist in the database and modify the XML configuration # according to received JSON. # -1 = VNF already exists # 0 = VNF successfully created def createVNF(self): if self.VNF_STATUS < 0: return if not self.VNF_EXIST: call(['mkdir', './IMAGES/' + self.ID]) call(['cp', './IMAGES/click-on-osv.qcow2', './IMAGES/' + self.ID + '/click-on-osv.qcow2']) self.VNF_EXIST = True self.applyVNF() return 0 else: return -1 # modifyVNF: reads the VNF JSON to replace the actual configuration. # -4 = VNF does not exist, you need create it before apply configurations # -3 = problems in INTERFACES data # -2 = problems in GENERAL data # -1 = VNF is up, down it to modify # 0 = VNF successfully modified def modifyVNF(self): if self.VNF_STATUS < 0: return if self.VNF_UP: return -1 with open(self.VNF_JSON) as dataVNF: parsedVNF = json.load(dataVNF) if 'MEMORY' in parsedVNF: self.MEMORY = parsedVNF['MEMORY'] if 'VCPU' in parsedVNF: self.VCPU = parsedVNF['VCPU'] if 'MANAGEMENT_MAC' in parsedVNF: self.MANAGEMENT_MAC = parsedVNF['MANAGEMENT_MAC'] if 'INTERFACES' in parsedVNF: self.INTERFACES = parsedVNF['INTERFACES'] check = self.modifyValidation() if check == -1: return -2 if check == -2: return -3 check = self.applyVNF() if check == -2: return -4 return 0 # destroyVNF: remove the VNF from database deleting all files. # -2 = VNF is up, down it to destroy # -1 = VNF does not exists, so it can't be removed # 0 = VNF successfully removed def destroyVNF(self): if self.VNF_STATUS < 0: return if self.VNF_UP: return -2 if self.VNF_EXIST: call(['rm', '-r', './IMAGES/' + self.ID]) self.VNF_EXIST = False self.VNF_STATUS = 0 return 0 else: return -1 #applyVNF: modify the standart XML configuration according to received JSON for VNF deploy. # -2 = VNF does not exist, you need create it before apply configurations # -1 = VNF is up, down it to modify the configuration # 0 = configuration successfully set def applyVNF(self): if self.VNF_STATUS < 0: return if not self.VNF_EXIST: return -2 if not self.VNF_UP: call(['cp', './IMAGES/click-on-osv.xml', './IMAGES/' + self.ID + '/click-on-osv.xml']) configurationXML = ElementTree.parse('./IMAGES/' + self.ID + '/click-on-osv.xml') configurationXML.find('name').text = self.ID configurationXML.find('uuid').text = str(uuid4()) configurationXML.find('memory').text = str(self.MEMORY * 1024) configurationXML.find('currentMemory').text = str(self.MEMORY * 1024) configurationXML.find('vcpu').text = str(self.VCPU) configurationXML.find('devices/interface/mac').attrib['address'] = self.MANAGEMENT_MAC configurationXML.find('devices/disk/source').attrib['file'] = path.abspath('IMAGES/' + self.ID + '/click-on-osv.qcow2') slotID = bytearray('a') for iface in self.INTERFACES: interfaceTag = ElementTree.SubElement(configurationXML.find('devices'), 'interface') interfaceTag.attrib['type'] = 'bridge' interfaceConfig = ElementTree.SubElement(interfaceTag, 'mac') interfaceConfig.attrib['address'] = iface['MAC'] interfaceConfig = ElementTree.SubElement(interfaceTag, 'source') interfaceConfig.attrib['bridge'] = iface['ID'] interfaceConfig = ElementTree.SubElement(interfaceTag, 'model') interfaceConfig.attrib['type'] = 'virtio' interfaceConfig = ElementTree.SubElement(interfaceTag, 'address') interfaceConfig.attrib['type'] = 'pci' interfaceConfig.attrib['domain'] = '0x0000' interfaceConfig.attrib['bus'] = '0x00' interfaceConfig.attrib['slot'] = '0x0' + str(slotID) interfaceConfig.attrib['function'] = '0x0' slotID[0] += 1 configurationXML.write('./IMAGES/' + self.ID + '/click-on-osv.xml') return 0 else: return -1 #upVNF: starts the VNF VM in KVM hypervisor, it is a temporary VM, so when the VM downs it will # disappear from hypervisor list. # -2 = VNF does not exist, create it to up # -1 = VNF already up # 0 = VNF upped successfully def upVNF(self): if self.VNF_STATUS < 0: return if not self.VNF_EXIST: return -2 if not self.VNF_UP: ifacesData = check_output(['brctl', 'show']).split('\n') ifacesCreate = copy(self.INTERFACES) for iface in self.INTERFACES: for iface2 in ifacesData: if iface2.startswith(iface['ID']): ifacesCreate.remove(iface) for iface in ifacesCreate: call(['brctl', 'addbr', iface['ID']]) for iface in self.INTERFACES: call(['ifconfig', iface['ID'], 'up']) call(['virsh', 'create', path.abspath('IMAGES/' + self.ID + '/click-on-osv.xml')], stdout = FNULL) self.VNF_UP = True return 0 else: return -1 #downVNF: down a started VNF and removes from hypervisor list. # -2 = VNF does not exist # -1 = VNF already down # 0 = VNF downed successfully def downVNF(self): if self.VNF_STATUS < 0: return if not self.VNF_EXIST: return -2 if self.VNF_UP: call(['virsh', 'destroy', self.ID], stdout = FNULL) self.VNF_UP = False self.VNF_REST = None return 0 else: return -1 #managementVNF: get the management interface address by a arp request. # -2 = arp did not respond # -1 = VNF is not up # IP:Port = management address def managementVNF(self): if self.VNF_STATUS < 0: return if self.VNF_UP: for attempt in range(0,3): arpData = check_output(['arp', '-n']).split('\n') for index in range(1,len(arpData)-1): iface = [data for data in arpData[index].replace(' ', ',').split(',') if data != ''] if iface[2] == self.MANAGEMENT_MAC: return iface[0] + ':8000' sleep(2) else: return -1 return -2 #controlVNF: control functions life cycle and get VNFs informations, the action is # the expected RESTfull call and arguments is a list of this call needs, # actually, only 'function_replace' uses to pass the function file. # -1 = VNF is no up, up to control it # -2 = management not acessible by ARP # other = check REST.py file def controlVNF(self, action, arguments): if self.VNF_STATUS < 0: return if not self.VNF_UP: return -1 if self.VNF_REST == None: management = self.managementVNF() if isinstance(management, basestring): self.VNF_REST = REST(management) else: return -2 if action == 'function_start': return self.VNF_REST.postStart() if action == 'function_stop': return self.VNF_REST.postStop() if action == 'function_replace': return self.VNF_REST.postFunction(arguments[0]) if action == 'function_run': return self.VNF_REST.getRunning() if action == 'function_data': return self.VNF_REST.getFunction() if action == 'function_id': return self.VNF_REST.getIdentification() if action == 'function_metrics': return self.VNF_REST.getMetrics() if action == 'function_log': return self.VNF_REST.getLog() #scriptVNF: execute a script serialized in a dictionary in scriptTasks, scriptError is # another serial tasks set as a error handle (can be None), finally, functionPath is for # replace actions, it can be None. # [] = seccessfull execution, REST results is presented # -1 = VNF is no up, up to control it # -2 = management not acessible by ARP # -3 ~ -8 = analog to REST.scriptExecution + 2 result def scriptVNF(self, scriptTasks, scriptError, functionPath): if self.VNF_STATUS < 0: return if not self.VNF_UP: return -1 if self.VNF_REST == None: management = self.managementVNF() if isinstance(management, basestring): self.VNF_REST = REST(management) else: return -2 resultCheck = self.VNF_REST.scriptExecution(scriptTasks, scriptError, functionPath) if isinstance(resultCheck, list): return resultCheck else: if resultCheck < 0: return resultCheck - 2 else: return resultCheck
def test_bad_http_responses(): """Checks good responses are False""" demo_api = REST(url='postman-echo.com') for code in (400, 401, 403, 404, 422): assert TRANSPORT.check_http_response( demo_api.get("/status/%i" % code).status_code) is False
def test_good_http_responses(): """Checks good responses are True""" demo_api = REST(url='postman-echo.com') for code in (200, 201, 204): assert TRANSPORT.check_http_response( demo_api.get("/status/%i" % code).status_code) is True