Changeset 1439


Ignore:
Timestamp:
03/08/07 18:04:18 (6 years ago)
Author:
mglb1
Message:

Add an 'Ethernet Customer' service to assist with configuring the required
components to provide service to a customer via an Ethernet interface.

Files:
7 added
1 edited

Legend:

Unmodified
Added
Removed
  • ccsd/trunk/crcnetd/modules/ccs_billing.py

    r1432 r1439  
    3333from crcnetd._utils.ccsd_config import config_get, config_getboolean 
    3434from crcnetd.modules.ccs_contact import addContact, editContact 
     35from crcnetd._utils.ccsd_service import ccsd_service, ccs_service_error, \ 
     36        registerService, getServiceInstance 
     37 
     38from crcnetd.modules.ccs_interface import INTERFACE_TYPE_ALIAS, addInterface 
     39from crcnetd.modules.ccs_link import ccs_link 
    3540 
    3641import calendar 
     
    5661CONNECTION_METHOD_ETHERNET = "Ethernet" 
    5762CONNECTION_METHODS = [ CONNECTION_METHOD_WIRELESS, CONNECTION_METHOD_ETHERNET ] 
     63 
     64# The property name for the link to allocate ethernet customer IPs from 
     65ETHERNET_CUSTOMER_LINK_PROPERTY = "ethernet_customer_link" 
     66 
     67# The property name for the firewall class to give to ethernet customers 
     68ETHERNET_CUSTOMER_FIREWALL_PROPERTY = "ethernet_customer_firewall" 
    5869 
    5970class ccs_billing_error(ccsd_error): 
     
    10741085 
    10751086##################################################################### 
     1087# Ethernet Customer Service 
     1088##################################################################### 
     1089class ethernet_customer_service(ccsd_service): 
     1090    """Configures customers onto ethernet interfaces""" 
     1091     
     1092    serviceName = "ethernet_customer" 
     1093    allowNewProperties = True 
     1094    networkService = False 
     1095 
     1096    def __init__(self, session_id, service_id): 
     1097        # Call base class setup 
     1098        ccsd_service.__init__(self, session_id, service_id) 
     1099 
     1100    @exportViaXMLRPC(SESSION_RO, AUTH_ADMINISTRATOR, True, \ 
     1101            "getEthernetCustomers") 
     1102    def getCustomers(self): 
     1103        """Returns a list of customers who receive ethernet services""" 
     1104        session = getSessionE(self._session_id) 
     1105 
     1106        # Get the interface details 
     1107        res = session.query("SELECT * FROM customers WHERE " \ 
     1108                "connection_method=%s", (CONNECTION_METHOD_ETHERNET)) 
     1109        return map(filter_keys, res) 
     1110 
     1111    @exportViaXMLRPC(SESSION_RO, AUTH_ADMINISTRATOR, True, \ 
     1112            "getCustomerInterfaces") 
     1113    def getInterfaces(self, host_id): 
     1114        """Returns customer details for the interfaces for the host""" 
     1115        session = getSessionE(self._session_id) 
     1116 
     1117        # Get the interface details 
     1118        res = session.query("SELECT i.*, ci.contact_id FROM " \ 
     1119                "interface i LEFT JOIN customer_interface ci ON " \ 
     1120                "i.interface_id=ci.interface_id WHERE i.host_id=%s",  
     1121                (host_id)) 
     1122         
     1123        # Loop through and collapse alias interfaces into the raw interface 
     1124        ifaces = {} 
     1125        tmp = [] 
     1126        for iface in res: 
     1127            if iface["contact_id"] == "": 
     1128                iface["contact_id"] = -1 
     1129            if iface["interface_type"] == INTERFACE_TYPE_ALIAS: 
     1130                tmp.append(filter_keys(iface)) 
     1131                continue 
     1132            ifaces[iface["name"]] = filter_keys(iface) 
     1133            ifaces[iface["name"]]["customer"] = None 
     1134        for iface in tmp: 
     1135            # Aliases with no associated customer are discarded 
     1136            if iface["contact_id"] == -1: continue 
     1137            if ifaces[iface["name"]]["customer"] is not None: 
     1138                log_warn("Multiple customers assigned to interface %s. " \ 
     1139                        "Ignoring all but the first!" % iface["name"]) 
     1140                continue 
     1141            ifaces[iface["name"]]["customer"] = iface 
     1142 
     1143        return ifaces 
     1144 
     1145    @exportViaXMLRPC(SESSION_RW, AUTH_ADMINISTRATOR, True) 
     1146    def updateCustomerInterface(self, host_id, interface_id, contact_id): 
     1147        """Updates the customer that is assigned to the interface 
     1148         
     1149        interface_id should be the id for the raw_interface the customer is 
     1150        assigned to. The actual link record will be created against an alias 
     1151        interface linked to this raw_interface. 
     1152        """ 
     1153        session = getSessionE(self._session_id) 
     1154        iface = None 
     1155        host_id = int(host_id) 
     1156        interface_id = int(interface_id) 
     1157        contact_id = int(contact_id) 
     1158        for ifname, temp in self.getInterfaces(host_id).items(): 
     1159            if temp["interface_id"] == interface_id: 
     1160                iface = temp 
     1161                break 
     1162        if iface is None: 
     1163            raise ccs_billing_error("Unknown interface") 
     1164 
     1165        # Handle removal now 
     1166        if int(contact_id)==-1: 
     1167            session.begin("Removing customer from interface '%s'" % \ 
     1168                    (iface["name"])) 
     1169            try: 
     1170                # Remove the link 
     1171                session.execute("DELETE FROM customer_interface WHERE " \ 
     1172                        "interface_id=%s", (iface["customer"]["interface_id"])) 
     1173                # Remove the alias interface 
     1174                session.execute("DELETE FROM interface WHERE interface_id=%s", 
     1175                        (iface["customer"]["interface_id"])) 
     1176                session.commit() 
     1177            except: 
     1178                session.rollback() 
     1179                (etype, value, tb) = sys.exc_info() 
     1180                log_error("Failed to remove customer: %s" % value,  
     1181                        (etype, value, tb)) 
     1182                raise ccs_billing_error("Failed to remove customer: %s" % \ 
     1183                        value) 
     1184            return True 
     1185 
     1186        # Get the link to allocate IP address from 
     1187        values = self.getPropertyValues() 
     1188        link_id = values[ETHERNET_CUSTOMER_LINK_PROPERTY] 
     1189        if link_id == -1: 
     1190            raise ccs_billing_error("No IP link specified. " \ 
     1191                    "Please configure the customer ethernet service!") 
     1192 
     1193        # Get the firewall class to use 
     1194        firewall_class_id = values[ETHERNET_CUSTOMER_FIREWALL_PROPERTY] 
     1195        if firewall_class_id == -1: 
     1196            raise ccs_billing_error("No firewall class specified. " \ 
     1197                    "Please configure the customer ethernet service!") 
     1198                     
     1199        # Validate that the specified customer is allowed to go onto 
     1200        # an ethernet interface 
     1201        custc = ccs_customer(self._session_id) 
     1202        cust = custc.getCustomer(contact_id)[0] 
     1203        if cust["connection_method"] != CONNECTION_METHOD_ETHERNET: 
     1204            raise ccs_billing_error("%s is a Wireless customer and " \ 
     1205                    "cannot be assigned to an Ethernet interface!" % \ 
     1206                    cust["username"]) 
     1207             
     1208        session.begin("Configured customer '%s' on interface '%s'" % \ 
     1209                (cust["username"], iface["name"])) 
     1210        try: 
     1211            # Create / Find an Alias interface on the specified interface 
     1212            # for this customers real IP address 
     1213            alias_id = -1 
     1214            res = session.query("SELECT i.interface_id, i.ip_address " \ 
     1215                    "FROM interface i LEFT JOIN " \ 
     1216                    "customer_interface ci ON i.interface_id=" \ 
     1217                    "ci.interface_id WHERE i.host_id=%s " \ 
     1218                    "AND i.interface_type=%s AND i.raw_interface=%s", 
     1219                    (host_id, INTERFACE_TYPE_ALIAS, interface_id)) 
     1220            if len(res) > 0: 
     1221                link = ccs_link(self._session_id, link_id) 
     1222                for temp in res: 
     1223                    # Find an existing interface in the right range 
     1224                    if not link.isValidIP(temp["ip_address"]): 
     1225                        continue 
     1226                    alias_id = temp["interface_id"] 
     1227                    break 
     1228            if alias_id == -1: 
     1229                # Create a new alias interface 
     1230                iface={} 
     1231                iface["interface_type"] = INTERFACE_TYPE_ALIAS 
     1232                iface["raw_interface"] = interface_id 
     1233                iface["host_id"] = host_id 
     1234                iface["link_id"] = link_id 
     1235                iface["interface_active"] = "t" 
     1236                iface["bridge_interface"] = "" 
     1237                iface["alias_netmask"] = "32" 
     1238                iface["ip_address"] = "" 
     1239                alias_id = addInterface(self._session_id, iface) 
     1240             
     1241            done = False 
     1242            # Link to the interface 
     1243            try: 
     1244                session.execute("INSERT INTO customer_interface (" \ 
     1245                        "contact_id, interface_id) VALUES " \ 
     1246                        "(%s, %s)", (contact_id, alias_id)) 
     1247                # Success 
     1248                session.commit() 
     1249                done = True 
     1250            except: 
     1251                (etype, value, tb) = sys.exc_info() 
     1252                # Assume this is because the record already exists 
     1253                pass 
     1254 
     1255            # Insert failed, try update 
     1256            if not done: 
     1257                try: 
     1258                    session.execute("UPDATE customer_interface SET " \ 
     1259                            "contact_id=%s WHERE interface_id=%s",  
     1260                            (contact_id, interface_id)) 
     1261                except: 
     1262                    # Log the previous error 
     1263                    log_error("Failed to insert customer interface record!", \ 
     1264                            (etype, value, tb)) 
     1265                    # Now log this error 
     1266                    log_error("Failed to update customer interface record!", \ 
     1267                            sys.exc_info()) 
     1268 
     1269            # Setup firewall 
     1270            firewall = getServiceInstance(self._session_id, "firewall") 
     1271            try: 
     1272                firewall.addService(host_id) 
     1273            except: 
     1274                # Assume due to already existing... 
     1275                pass 
     1276            firewall.updateFirewallInterface(host_id, interface_id, \ 
     1277                    firewall_class_id) 
     1278 
     1279            # Make permanent and return 
     1280            session.commit() 
     1281            return True 
     1282        except: 
     1283            session.rollback() 
     1284            (etype, value, tb) = sys.exc_info() 
     1285            log_error("Failed to setup customer interface record!", \ 
     1286                        (etype, value, tb)) 
     1287            raise ccs_billing_error("Exception updating customer interface!") 
     1288 
     1289        # Somethign bad happened 
     1290        return False 
     1291 
     1292    def getHostTemplateVariables(self, host_id): 
     1293        """Returns a dictionary containing template variables for a host 
     1294 
     1295        See the getTemplateVariables function for more details. 
     1296        """ 
     1297 
     1298        # Call base class to get the basics 
     1299        variables = ccsd_service.getHostTemplateVariables(self, host_id) 
     1300        return variables 
     1301 
     1302    @staticmethod 
     1303    def initialiseService(): 
     1304        """Called by the system the very first time the service is loaded. 
     1305 
     1306        This should setup an entry in the service table and load any default 
     1307        service properties into the service_prop table. 
     1308        """ 
     1309        session = getSessionE(ADMIN_SESSION_ID) 
     1310        session.begin("Initialising ethernet customer service")         
     1311        try: 
     1312 
     1313            session.execute("INSERT INTO service (service_id, service_name, " \ 
     1314                    "enabled) VALUES (DEFAULT, %s, DEFAULT)", \ 
     1315                    (ethernet_customer_service.serviceName)) 
     1316            service_id = session.getCountOf("SELECT currval('" \ 
     1317                    "service_service_id_seq') AS service_id", ()) 
     1318 
     1319            # Setup the link and firewall properties 
     1320            session.execute("INSERT INTO service_prop (service_prop_id, " \ 
     1321                "service_id, prop_name, prop_type, default_value, required) " \ 
     1322                "VALUES (DEFAULT, %s, %s, 'integer', -1, 't')", \ 
     1323                (service_id, ETHERNET_CUSTOMER_LINK_PROPERTY)) 
     1324            session.execute("INSERT INTO service_prop (service_prop_id, " \ 
     1325                "service_id, prop_name, prop_type, default_value, required) " \ 
     1326                "VALUES (DEFAULT, %s, %s, 'integer', -1, 't')", \ 
     1327                (service_id, ETHERNET_CUSTOMER_FIREWALL_PROPERTY)) 
     1328                 
     1329            # Commit the changese 
     1330            session.commit() 
     1331             
     1332            log_info("Created ethernet customer service entries") 
     1333        except: 
     1334            session.rollback() 
     1335            log_error("Unable to initialise ethernet customer service " \ 
     1336                    "database entries!", sys.exc_info()) 
     1337            raise ccs_billing_error("Failed to setup database tables!") 
     1338 
     1339        return service_id 
     1340 
     1341##################################################################### 
    10761342# Module initialisation 
    10771343##################################################################### 
    10781344def ccs_init(): 
    10791345    global invoice_store, billing_template_dir, trml_path, invoice_days_to_pay 
     1346 
     1347    # Register the service 
     1348    registerService(ethernet_customer_service) 
    10801349 
    10811350    # Load the path where we store generated invoices 
Note: See TracChangeset for help on using the changeset viewer.