commit ca6af4f849fdecad17b936380ce431f72c7463c3 Author: Cory Hawkvelt Date: Sun Nov 20 21:27:48 2022 +1030 Fresh repo diff --git a/main.py b/main.py new file mode 100644 index 0000000..b9d80b7 --- /dev/null +++ b/main.py @@ -0,0 +1,56 @@ +import os, sys +sys.path.append(os.path.join(os.path.dirname(__file__), "lib")) +from myOpenstackApp.logger import log + + +import myOpenstackApp +testProjectName="SmokeTest" +testProjectExists=False +testProject="" +cleanupResourcesOnCompletion=True + +y=myOpenstackApp.OSC +y.initalise() +# y.ks.getCatalog() +# print(y.something()) +# print(y._keystone) + +log.info("Starting") + +allProjects=y.ks.getAllProjects() + + +#Does my test project ID already exist? +for _project in allProjects['projects']: + if _project['name']==testProjectName: + testProject=_project + testProjectExists=True + +if testProjectExists: + log.error("Project already exists") + log.info(testProject['id']) + +else: + # Create test project + log.info("{} project does not exist, creating".format(testProjectName)) + testProject=y.ks.createProject(testProjectName,"Description goes here")['project'] + log.info(testProject['id']) + +#Does my test network exist? +allNetworks=y.neutron.getAllNetworks(testProject['id']) +log.info(allNetworks) + + +def cleanUp(): + log.info("Cleaning up") + log.info("Deleting project") + y.ks.deleteProject(testProject['id']) + #Delete VM + #Delete router + #Delete Network + #Delete project + pass + + +if cleanupResourcesOnCompletion: + cleanUp() diff --git a/myOpenstackApp/OpenStackConnection.py b/myOpenstackApp/OpenStackConnection.py new file mode 100644 index 0000000..376942c --- /dev/null +++ b/myOpenstackApp/OpenStackConnection.py @@ -0,0 +1,141 @@ +import requests +# import redis +import json +import os +from myOpenstackApp.logger import log + + +from myOpenstackApp import exceptions +class OpenStackConnection_x: + someProp=0 + ks=False + nova=False + neutron=False + + catalogData="" + novaURL="" + interface="" + token="" + + """ + It's important not to initalise any of the submodules during the init cycle becuase thic causes cirtucalr import loops + The initalise function exists for this reas and should be caled by the client application using this module + """ + def __init__(self) -> None: + pass + + def initalise(self) -> None: + log.info("Initalising connection") + from myOpenstackApp.keystone import myopenstack_keystone + from myOpenstackApp.nova import myopenstack_nova + from myOpenstackApp.neutron import myopenstack_neutron + + self.ks=myopenstack_keystone(self) + self.nova=myopenstack_nova(self) + self.neutron=myopenstack_neutron(self) + self.interface=os.getenv("OS_INTERFACE") + + + pass + + def something(_self): + print(1) + _self.ks.getCatalog() + print(_self.nova.getAllServers(os.getenv("OS_PROJECT_ID"),True)) + + + def make_request(_self, getPost, url, data, apiEndpoint, scopedProjectID=""): + log.debug("Making a request {} {} ".format(apiEndpoint,url)) + # Default the scope project to the value set in .env.example, allow the user to override if required(EG creating backups) + if scopedProjectID== "": + if len(str(os.getenv("OS_PROJECT_ID")))<8: + raise Exception("No OS_PROJECT_ID provided") + scopedProjectID=os.getenv("OS_PROJECT_ID") + else: + scopedProjectID=scopedProjectID + + str(url).replace(" ","%20") + + data_json = json.dumps(data) + + token = _self.getToken(os.getenv("OS_USERNAME"), os.getenv("OS_PASSWORD"), + os.getenv("OS_USER_DOMAIN_NAME"), os.getenv("OS_USER_DOMAIN_NAME"), + scopedProjectID) + # print (token) + headers = {'Content-type': 'application/json', 'X-Auth-Token': token} + + url = apiEndpoint + "/" + url + + if getPost=="GET": + response = requests.get(url, headers=headers) + elif getPost=="POST": + response = requests.post(url, data=data_json, headers=headers) + elif getPost=="DELETE": + response = requests.delete(url, headers=headers) + else: + raise ValueError("Unknown request type") + + if 200<= response.status_code <= 300 : + return response + else: + raise ValueError ("Error in response return code" + str(response.status_code) + str(response.content)) + + def getToken(_self,username, password, authDomain, scopeDomain, scopeProject): + + try: + return _self.lookupToken(username, authDomain, scopeDomain, scopeProject) + except exceptions.ItemNotFoundError: + + url = os.getenv("OS_AUTH_URL") + '/auth/tokens' + xdata = { + "auth": { + "scope": { + "project": { + "domain": { + "name": scopeDomain + }, + "id": scopeProject + } + }, + "identity": { + "password": { + "user": { + "domain": { + "name": authDomain + }, + "password": password, + "name": username + } + }, + "methods": [ + "password" + ] + } + } + } + + response = requests.post(url) + headers = {'Content-type': 'application/json'} + response = requests.post(url, headers=headers, + data=json.dumps(xdata), + verify=False, + timeout=4) + + if response.status_code == 201: + try: + _self.saveToken( username, authDomain, scopeDomain, scopeProject, response.headers['X-Subject-Token']) + except exceptions.ItemNotSavedError: + log.warn("Error saving token to redis..meh") + return response.headers['X-Subject-Token'] + else: + raise ValueError("Error in token response to token request:"+response.text) + + def lookupToken(_self, username, authDomain, scopeDomain, scopeProject): + if _self.token!="": + return _self.token + raise exceptions.ItemNotFoundError("OpenstackToken not found in redis") + + def saveToken(_self, username, authDomain, scopeDomain, scopeProject,token): + _self.token=token + #raise exceptions.ItemNotSavedError("OpenstackToken not saved in redis") + diff --git a/myOpenstackApp/__init__.py b/myOpenstackApp/__init__.py new file mode 100644 index 0000000..b590813 --- /dev/null +++ b/myOpenstackApp/__init__.py @@ -0,0 +1,3 @@ +from myOpenstackApp import OpenStackConnection + +OSC=OpenStackConnection.OpenStackConnection_x() diff --git a/myOpenstackApp/exceptions.py b/myOpenstackApp/exceptions.py new file mode 100644 index 0000000..5d8b692 --- /dev/null +++ b/myOpenstackApp/exceptions.py @@ -0,0 +1,10 @@ +class ItemNotFoundError(ValueError): + '''Used when looking up REDIS or SQL or any other database to indicate to the calling routine that the object + cant be found and to move along and try bother some other function + ''' +class ItemNotSavedError(ValueError): + '''Item cant be saved to Redis + ''' + +class DeadIPFound(ValueError): + ''''An ip has been saved to redis as being 'DEAD"''' diff --git a/myOpenstackApp/keystone.py b/myOpenstackApp/keystone.py new file mode 100644 index 0000000..f304659 --- /dev/null +++ b/myOpenstackApp/keystone.py @@ -0,0 +1,86 @@ +import imp +import json +import os +from myOpenstackApp.logger import log +import myOpenstackApp.settings +import myOpenstackApp.OpenStackConnection + + +class myopenstack_keystone(): + def __init__(self,conn: myOpenstackApp.OpenStackConnection.OpenStackConnection_x ) -> None: + self.serviceData={} + self.catalogData={} + self.projectData={} + self.connection=conn + + + + def getAllProjects(_self): + _self.projectData=_self.connection.make_request("GET", "projects", "", + os.getenv("OS_AUTH_URL")).json() + return _self.projectData + + + + def getCatalog(_self): + catalogData=_self.connection.make_request("GET", "endpoints", "", + os.getenv("OS_AUTH_URL")).json() + + serviceData=_self.connection.make_request("GET", "services", "", + os.getenv("OS_AUTH_URL")).json() + # print(serviceData) + _self.serviceData=serviceData + _self.catalogData=catalogData + return catalogData + + + def getServicebyID(_self,id): + # print(_self.serviceData) + for _service in _self.serviceData['services']: + if str(_service['id']).lower()==str(id).lower(): + # print(_service) + return(_service) + + def getServicebyName(_self,name): + for _service in _self.serviceData['services']: + if str(_service['name']).lower()==str(name).lower(): + # print(_service) + return(_service) + + + def getEndpointByServiceIDAndInterface(_self,id,interface): + for _endpoint in _self.catalogData['endpoints']: + if str(_endpoint['service_id']).lower()==str(id).lower(): + if str(_endpoint['interface']).lower()==str(interface).lower(): + # print(_endpoint) + return(_endpoint) + + def getEndpointByNameAndInterface(_self,name,interface): + id=_self.getServicebyName(name)['id'] + for _endpoint in _self.catalogData['endpoints']: + if str(_endpoint['service_id']).lower()==str(id).lower(): + if str(_endpoint['interface']).lower()==str(interface).lower(): + # print(_endpoint) + return(_endpoint) + + def createProject(_self,name,description): + log.info("Creating a project") + data={ + "project": { + "description": description, + "enabled": True, + "is_domain": False, + "name": name + } + } + + _self.newProjectData=_self.connection.make_request("POST", "projects", data, + os.getenv("OS_AUTH_URL")).json() + return _self.newProjectData + + def deleteProject(_self,id): + log.info("Deleting a project") + + _self.newProjectData=_self.connection.make_request("DELETE", "projects/"+id, "", + os.getenv("OS_AUTH_URL")) + return _self.newProjectData \ No newline at end of file diff --git a/myOpenstackApp/logger.py b/myOpenstackApp/logger.py new file mode 100644 index 0000000..b1420dc --- /dev/null +++ b/myOpenstackApp/logger.py @@ -0,0 +1,6 @@ +import os,logging +##LOGGING OPTIONS +LOG_LEVEL = os.getenv("LOG_LEVEL") or "DEBUG" +FORMAT = '%(asctime)s [%(levelname)s] %(message)s' +log = logging +log.basicConfig(format=FORMAT,level=LOG_LEVEL) \ No newline at end of file diff --git a/myOpenstackApp/neutron.py b/myOpenstackApp/neutron.py new file mode 100644 index 0000000..ad60f11 --- /dev/null +++ b/myOpenstackApp/neutron.py @@ -0,0 +1,33 @@ +import imp +import json +import myOpenstackApp.OpenStackConnection + +class myopenstack_neutron(): + def __init__(self,conn: myOpenstackApp.OpenStackConnection.OpenStackConnection_x ) -> None: + self.conn=conn + + def getAllNetworks(_self, projectID): + result_Data=_self.conn.make_request("GET", "networks?project_id="+projectID, "", + _self.conn.ks.getEndpointByNameAndInterface("neutron",_self.conn.interface)["url"]).json() + return result_Data + + def listAllFloatingIPsByProject(_self,projectID): + result_Data=_self.conn.make_request("GET", "floatingips?project_id="+projectID, "", + _self.conn.ks.getEndpointByNameAndInterface("neutron",_self.conn.interface)["url"]).json() + return result_Data + + def ipInSubnet(_self,network,netmask,ip): + #Network, netmask and ip must be supplied in integer form + return (ip & netmask) == network + + def createNetwork(_self,name,project_id,description=""): + data={ + "network": { + "name": name, + "admin_state_up": true, + "tenant_id": project_id, + "description": description + } + } + newNetwork=_self.requestor.make_request("POST", "projects", data, ) + return newNetwork \ No newline at end of file diff --git a/myOpenstackApp/nova.py b/myOpenstackApp/nova.py new file mode 100644 index 0000000..4bdff27 --- /dev/null +++ b/myOpenstackApp/nova.py @@ -0,0 +1,34 @@ +import myOpenstackApp.OpenStackConnection + + +class myopenstack_nova(): + + def __init__(self,conn: myOpenstackApp.OpenStackConnection.OpenStackConnection_x ) -> None: + self.conn=conn + + def addNewVM(_self,Name, flavor): + return(Name) + + def getKeystone(_self): + _self.myOpenstackObject.keystone.echo() + + def showNovaURL(_self): + return _self.conn.ks.getEndpointByNameAndInterface("nova",_self.conn.interface)["url"] + + + def getAllServers(_self,projectID,all_tenants): + queryString="" + if all_tenants: + queryString="/servers/detail?all_tenants=True" + else: + queryString="/servers/detail?project_id="+projectID, + return _self.conn.make_request("GET", queryString,"",_self.conn.ks.getEndpointByNameAndInterface("nova",_self.conn.interface)["url"] ).json() + + + + def getAllFlavors(_self): + return ng_openstack.openstackRequest.openstackRequest("GET", "/flavors/detail", + "", "http://172.25.110.147:8774/v2.1").json() + + + diff --git a/myOpenstackApp/settings.py b/myOpenstackApp/settings.py new file mode 100644 index 0000000..eff8b63 --- /dev/null +++ b/myOpenstackApp/settings.py @@ -0,0 +1,3 @@ +from dotenv import load_dotenv + +load_dotenv() \ No newline at end of file diff --git a/myOpenstackApp/test_keystone.py b/myOpenstackApp/test_keystone.py new file mode 100644 index 0000000..db54fcf --- /dev/null +++ b/myOpenstackApp/test_keystone.py @@ -0,0 +1,16 @@ +import myOpenstackApp.OpenStackConnection + + +class myopenstack_keystone(): + + def __init__(self,conn ) -> None: + self.conn=conn + + def echo(_self): + print("Helllooo") + + + def getCatalog(_self): + catalog="Some shit, more shit" + _self.conn.catalogData=catalog + _self.conn.novaURL="http://nova"