def setRurallinkDeviceConfig(session_id, asset_id, type): """Updates the device asset record to reflect the configuration type""" session = getSessionE(session_id) if asset_id == -1: # Called by a device itself, use the CN of the certificate to # lookup the mac address and find an asset ID mac = ":".join([session.username[(i * 2) - 2 : i * 2] for i in range(1, 7)]) if not isValidMAC(mac): raise ccs_rurallink_error("Asset not specified!") asset = getAssetByMac(session_id, mac) asset_id = asset["asset_id"] asset = ccs_asset(session_id, asset_id) if type == "CPE": asset.updateAssetDetail("description", "RuralLink Farm Terminal") elif type == "Repeater": asset.updateAssetDetail("description", "RuralLink Farm Repeater") elif type == "Master": asset.updateAssetDetail("description", "Rurallink Farm AP (Master Node)") else: raise ccs_rurallink_error("Unknown configuration type!") return True
def getNetworkTemplateVariables(self): """Returns a dictionary containing template variables for all hosts See the getTemplateVariables function for more details. """ session = getSessionE(self._session_id) variables = {} name = self._service["service_name"] variables["service_name"] = name variables["%s_enabled" % name] = self.getState() # Include basic properties variables.update(self.getPropertyValues()) # Include a list of hosts that the service is enabled on variables["direct_mesh"] = self.buildConnectedMesh() variables["hosts"] = self.getEnabledHostList() #Get list of central sites sql = "SELECT h.host_name from service_hostdata s, host h where " \ "h.host_id = s.host_id AND service_id = %s AND service_prop_id = " \ "(select service_prop_id from service_prop where prop_name = " \ "'amplet_group') AND value = 'gtw'" variables['gtws'] = session.query(sql, (self.service_id)) return variables
def initialiseService(): """Called by the system the very first time the service is loaded. This should setup an entry in the service table and load any default service properties into the service_prop table. """ session = getSessionE(ADMIN_SESSION_ID) session.begin("initialising HostAPD service") try: session.execute("INSERT INTO service (service_id, service_name, " \ "enabled) VALUES (DEFAULT, %s, DEFAULT)", \ (hostapd_service.serviceName)) service_id = session.getCountOf("SELECT currval('" \ "service_service_id_seq') AS server_id", ()) # Commit the changese session.commit() log_info("Created hostapd service entries and tables in database") except: session.rollback() log_error("Unable to initialise hostapd database entries!", \ sys.exc_info()) raise hostapd_error("Failed to setup database tables!") return service_id
def getDetails(self): """Returns a detailed object describing the host""" session = getSessionE(self._session_id) sql = "SELECT * FROM host_detail WHERE host_id=%s" res = session.query(sql, (self.host_id)) return res[0]
def getAvailHostAssets(session_id, site_id=-1): """Returns a list of assets that could be used for a new host Returns a list of assets that are assigned to a site and could be used for a new host. If the site_id is -1 then a list of assets in stock that could be used for a new host are returned. """ session = getSessionE(session_id) if site_id==-1: # Return generic list of available host assets at site 'stock' sql = "SELECT s.asset_id, s.description FROM site_host_assets_avail " \ "s, asset a WHERE a.asset_id=s.asset_id AND s.site_id IN " \ "(SELECT site_id FROM asset_stock_location) " \ "AND s.asset_id NOT IN (SELECT asset_id FROM host WHERE " \ "asset_id IS NOT NULL) AND a.asset_type_id IN " \ "(SELECT asset_type_id FROM asset_type_map WHERE " \ "asset_function='host')" p = () else: # Verify site_id is OK validateSiteId(session_id, site_id) # Return list of host assets assigned to site but not yet to a host sql = "SELECT asset_id, description FROM site_host_assets_avail " \ "WHERE site_id=%s" p = (site_id) res = session.query(sql, p) return res
def getGraphVars(session_id, graph_id): """Returns all vars that are defined""" session = getSessionE(session_id) sql = "SELECT varname from graph_parts WHERE graph_id=%s AND (type='DEF' OR type='CDEF')" res = session.query(sql, (graph_id)) return res
def snmpDeleteHost(session_id, host_id): """This removes a host from the snmp_discovery table""" session = getSessionE(session_id) sql = "DELETE FROM snmp_discovery WHERE host_id=%s" session.execute(sql, (host_id)) return 1
def getGroups(session_id): """Returns the list of admin groups""" session = getSessionE(session_id) sql = "SELECT * FROM admin_group" res = session.query(sql, ()) return res
def addGroup(session_id, group): """Adds the specified group to the database If the group was sucessfully added to the data a dictionary with two items, (group_id and errMsg) is returned. errMsg may contain details of an error that occured but did not prevent the group from being added. """ session = getSessionE(session_id) # verify group details verifyGroup(session_id, group, True) # insert the group record sql = "INSERT INTO admin_group (admin_group_id, group_name) VALUES " \ "(DEFAULT, %s)" session.execute(sql, (group["group_name"])) # Get the group_id that was created for the group sql = "SELECT currval('admin_group_admin_group_id_seq') as " \ "admin_group_id" res = session.query(sql, ()) group_id = res[0]["admin_group_id"] # Raise the event triggerEvent(session_id, "groupAdded", group_id=group_id) return group_id
def disableLogin(session_id, login_id): """Disables the account of the specified login""" session = getSessionE(session_id) # Verify login_id is OK verifyLoginID(session_id, login_id) # If not in a changeset, create one to group these commands together commit = 0 if session.changeset == 0: session.begin("Disabled login %s" % login_id, '', 1) commit = 1 sql = "UPDATE logins SET enabled=0 WHERE login_id=%s" session.execute(sql, (login_id)) sql = "UPDATE first_login SET enabled=0 WHERE login_id=%s" session.execute(sql, (login_id)) # If we started a changeset, commit it if commit == 1: session.commit("Automatically generated changeset.") # Raise an event triggerEvent(session_id, "loginModified", login_id=login_id) return 0
def getAdminID(session_id, username): global users """ Returns the admin_id of the user with the specified username """ session = getSessionE(session_id) return users[username]["admin_id"]
def getAvail(session_id, group_id): """Returns the list of users / groups not in the specified group""" session = getSessionE(session_id) # Verify group_id is OK verifyGroupID(session_id, group_id) sql = "SELECT c.admin_id, l.username, c.givenname, c.surname, " \ "g.admin_group_id, g.group_name FROM (((admins c INNER JOIN " \ "logins l ON c.login_id=l.login_id) LEFT JOIN group_membership gm " \ "ON c.admin_id=gm.admin_id AND gm.parent_group_id=%(c)s) FULL JOIN " \ "(admin_group g LEFT JOIN group_membership gm2 ON " \ "g.admin_group_id=gm2.group_id AND gm2.parent_group_id=%(c)s) ON " \ "l.passwd=g.group_name) WHERE ((c.admin_id IS NOT NULL AND " \ "(gm.parent_group_id IS NULL OR gm.parent_group_id!=%(c)s)) OR " \ "(g.admin_group_id IS NOT NULL AND (gm2.parent_group_id IS NULL OR " \ "gm2.parent_group_id!=%(c)s) AND g.admin_group_id!=%(c)s)) ORDER BY " \ "g.group_name, l.username" res = session.query(sql, {"c":group_id}) if len(res) < 1: return [] # Filter out groups that are parents of this group res2 = [] for member in res: # Skip normal contacts if member["admin_group_id"] == "": res2.append(member) continue # Check group membership if isGroupMemberG(session_id, group_id, member["admin_group_id"]): continue # It's ok res2.append(member) return res2
def initPhoneHome(): """Initailises the phone home support.""" global devices session = getSessionE(ADMIN_SESSION_ID) # Find every asset with a Rural Link serial number and add it ot the array sql = ( "SELECT a.asset_id, a.description, d.value AS serialno FROM " "asset_data d, subasset s, asset a, subasset_property sp, " "asset_property ap WHERE d.subasset_id=s.subasset_id AND " "s.asset_id=a.asset_id AND d.subasset_property_id=" "sp.subasset_property_id AND sp.asset_property_id=" "ap.asset_property_id AND ap.description=%s AND " "a.description LIKE '%%AP%%'" ) for device in session.query(sql, (RURALLINK_SERIAL_DESCRIPTION)): serialno = int(device["serialno"]) data = { "serialno": serialno, "asset_id": device["asset_id"], "ip": None, "timestamp": None, "timestamp_str": "", "location": "", "description": device["description"], } devices[data["serialno"]] = data
def getPhoneHome(session_id): """Returns phone home status details""" global devices rv = devices.copy() session = getSessionE(session_id) sql = ( "SELECT a.asset_id, d.value AS serialno, " "date_part('epoch', al.location_updated) AS location_updated, " "COALESCE(s.location, 'Attached to Asset #' || " "al.attached_to) AS location FROM asset_data d, " "subasset sa, asset a, subasset_property sp, asset_property ap, " "asset_location al LEFT JOIN site s ON " "al.site_id=s.site_id WHERE d.subasset_id=sa.subasset_id AND " "sa.asset_id=a.asset_id AND " "d.subasset_property_id=sp.subasset_property_id AND " "sp.asset_property_id=ap.asset_property_id AND " "ap.description=%s AND a.description LIKE '%%AP%%' AND " "a.asset_id=al.asset_id" ) for device in session.query(sql, (RURALLINK_SERIAL_DESCRIPTION)): serialno = int(device["serialno"]) if serialno not in rv.keys(): continue rv[serialno]["location"] = device["location"] if rv[serialno]["timestamp"] is None: rv[serialno]["timestamp_str"] = "Never" else: rv[serialno]["timestamp_str"] = roundTime(time.time() - rv[serialno]["timestamp"]) return rv
def getGraphGroup(session_id, group_id): """Simple function to return a group""" session = getSessionE(session_id) sql = "SELECT * from graph_group WHERE group_id=%s" res = session.query(sql, (group_id)) return res[0]
def createStatic(self, details): """Creates a static route on the specified host""" session = getSessionE(self._session_id) # Validate props = [ "host_id", "description", "prefix", "next_hop", "metric" ] for prop in props: if prop!="metric" and not prop in details.keys(): raise ccs_quagga_error("Missing required property '%s'!" % \ prop) if prop in details.keys(): validateStaticProp(self._session_id, prop, details[prop]) # Build the SQL (sql, values) = buildInsertFromDict("quagga_statics", props, details) session.execute(sql, values) # Get the ID static_id = session.getCountOf("SELECT currval('" \ "quagga_statics_static_id_seq') AS static_id", ()) # Raise the event triggerEvent(self._session_id, "quaggaStaticCreated", \ service_id=self.service_id, host_id=details["host_id"], \ static_id=static_id) return static_id
def getGraphType(session_id, graph_id): """Simple function to return a graph type""" session = getSessionE(session_id) sql = "SELECT * from graph_type WHERE graph_id=%s" res = session.query(sql, (graph_id)) return res[0]
def createOSPFArea(self, area_no, link_class_id): """Creates a new OSPF area, possibly bound to a link class""" session = getSessionE(self._session_id) try: area_no = int(area_no) if area_no < 1: raise quagga_error("Invalid area number!") except: (type, value, tb) = sys.exc_info() raise quagga_error("Invalid area number! - %s" % value) try: link_class_id = int(link_class_id) except: link_class_id = -1 if link_class_id != -1: log_warn("Link Class ID: %s" % link_class_id) validateLinkClassId(self._session_id, link_class_id) session.execute("INSERT INTO quagga_ospf_area (area_no, " \ "link_class_id) VALUES (%s,%s)", (area_no, link_class_id)) else: session.execute("INSERT INTO quagga_ospf_area (area_no) " \ "VALUES (%s)", (area_no)) return 0
def updateGraphTypeDetails(session_id, graph_id, newDetails): """Updates the details of the Graph type. newDetails should be a dictionary containing only these class paramters that have changed and need to be updated in the database. """ session = getSessionE(session_id) # Build SQL props = ["title", "class_id", "virtical_label", "auto_comment", "rigid", "upper"] nulls = [] if "upper" in newDetails and newDetails["upper"] == "": nulls.append("upper") (sql, values) = buildUpdateFromDict("graph_type", props, newDetails, "graph_id", graph_id, False, nulls) if values == None: # No changes made... ? return 1 # Run the query session.execute(sql, values) return 1
def getOSPFAreas(self): """Returns details on the available OSPF areas""" session = getSessionE(self._session_id) return session.query("SELECT a.*, lc.description AS link_class_desc " \ "FROM quagga_ospf_area a LEFT JOIN link_class lc ON " \ "a.link_class_id=lc.link_class_id", ())
def snmpFlush(session_id): """This flushes the entire snmp_discovery table""" session = getSessionE(session_id) sql = "DELETE FROM snmp_discovery" session.execute(sql, ()) return 1
def getHostList(session_id): """ A custom getHostList that only returns hosts that there are graohs for""" session = getSessionE(session_id) sql = "SELECT DISTINCT host_id, host_name from graphview" res = session.query(sql, ()) res.sort(key=lambda obj: obj["host_name"].lower()) return res
def removeInterfaceSubassetLinks(self): """Removes the subasset associated with each interface on the host This function is called when the host's asset is removed, for each subasset that was part of the host's asset the associated interface is disabled and set to have no associated hardware. Assets that are attached to the hosts's asset and are configured as an interface are relocated to the site the host is present at. This needs to be called before the internal properties are updated so that self._properties["asset_id"] contains the ID of the asset that is being removed. """ session = getSessionE(self._session_id) # Disable the interfaces that used subassets of the host asset session.execute("UPDATE interface SET subasset_id=NULL, " \ "interface_active='f' WHERE host_id=%s AND subasset_id IN " \ "(SELECT subasset_id FROM interface_subassets WHERE " \ "asset_id=%s)", (self.host_id, self._properties["asset_id"])) # Move attached assets configured as an interface to the hosts site res = session.query("SELECT a.asset_id FROM interface i, subasset s, " \ "asset a WHERE i.subasset_id=s.subasset_id AND " \ "s.asset_id=a.asset_id AND i.host_id=%s AND " \ "i.subasset_id NOT IN (SELECT subasset_id FROM " \ "interface_subassets WHERE asset_id=%s)", (self.host_id, self._properties["asset_id"])) for iface in res: asset = ccs_asset(self._session_id, iface["asset_id"]) if self.hasSite(): asset.moveToSite(self._properties["site_id"]) else: asset.moveToStock()
def getGraphGroups(session_id): """Simple function to return all graph groups""" session = getSessionE(session_id) sql = "SELECT * from graph_group" res = session.query(sql, ()) return res
def getHostDetails(self, host_id): """Returns data relating to amplet""" session = getSessionE(self._session_id) service = ccsd_service.getHostDetails(self, host_id) return service
def getGraphParts(session_id, graph_id): """Simple function to return all graph parts of a graph""" session = getSessionE(session_id) sql = "SELECT * from graph_parts WHERE graph_id=%s ORDER BY graph_order" res = session.query(sql, (graph_id)) return res
def handleHostApEvent(eventName, host_id, session_id, service_id): """Receives service callbacks to update the radius client table""" session = getSessionE(session_id) hostapService = -1 ethernetService = -1 # Ignore events that don't relate to the hostap or ethernet customer # services try: hostapService = getServiceID(session_id, "hostapd") except ccs_service_error: # Hostapd service not installed pass try: ethernetService = getServiceID(session_id, "ethernet_customer") except ccs_service_error: # Ethernet customer service not installed pass if int(service_id) not in [hostapService, ethernetService]: return if eventName == "serviceAdded": # Create a RADIUS client record for this host session.execute("INSERT INTO radius_client (host_id, secret) " \ "VALUES (%s, %s)", (host_id, createPassword(16))) elif eventName == "serviceRemoved": # Remove the RADIUS client record for this host # XXX: Don't remove, the other service might still want it #session.execute("DELETE FROM radius_client WHERE host_id=%s", # (host_id)) pass else: # Invalid event pass
def getGraphPart(session_id, part_id): """Simple function to return a graph part""" session = getSessionE(session_id) sql = "SELECT * from graph_parts WHERE part_id=%s" res = session.query(sql, (part_id)) return res[0]
def updateHostAPdInterface(self, host_id, interface_id, val): """Enables HostAPd on the specified interface""" session = getSessionE(self._session_id) if val == "0": session.execute("DELETE FROM hostapd_interface WHERE " \ "interface_id=%s", (interface_id)) # Raise the event triggerHostEvent(self._session_id, "hostapdInterfaceDisabled", \ service_id=self.service_id, host_id=host_id, \ interface_id=interface_id) else: if hostapdInterfaceEnabled(self._session_id, interface_id): #raise hostapd_error("HostAPd already enabled on interface!") session.execute("UPDATE hostapd_interface SET auth=%s " \ "WHERE interface_id = %s", (val, interface_id)) else: session.execute("INSERT INTO hostapd_interface (interface_id, auth) " \ "VALUES (%s, %s)", (interface_id, val)) # Raise the event triggerHostEvent(self._session_id, "hostapdInterfaceEnabled", \ service_id=self.service_id, host_id=host_id, \ interface_id=interface_id) return True
def editEmailDomain(session_id, details): """ Edit existing email domain """ session = getSessionE(ADMIN_SESSION_ID) #Check values verifyEmailDomain(details) try: if len(details['catchall']) == 0: details['catchall'] = -1 except ValueError or KeyError: details['catchall'] = -1 try: if len(details['redirect']) == 0: details['redirect'] = -1 except ValueError or KeyError: details['redirect'] = -1 props = ['customer_id', 'domain', 'catchall', 'redirect'] sql, values = buildUpdateFromDict("email_domain", props, details, "domain", details['domain'], True) session.execute(sql,values) return True