def __init__(self, ctx, form, data): self.ctx = ctx self.form = form self.data = data self.toplevel_fda = formalutils.FormDataAccessor(form, [], ctx) self.client_connection_fda = formalutils.FormDataAccessor( form, ['client_connection'], ctx)
def fill_users_group(self, ctx, form, g): fda = formalutils.FormDataAccessor(form, ['userlist_group'], ctx) ui_root = helpers.get_ui_config() if ui_root.hasS(ns_ui.users): for idx, user in enumerate( ui_root.getS(ns_ui.users, rdf.Seq(rdf.Type(ns_ui.User)))): try: g = self._create_user_list_entry(idx) fda_user = fda.descend(str(idx)) fda_user['username'] = user.getS(ns_ui.username, rdf.String) #fda_user['password'] = user.getS(ns_ui.password, rdf.String) fda_user['password'] = '' if user.hasS(ns_ui.fixedIp): fda_user['fixed_ip'] = user.getS( ns_ui.fixedIp, rdf.IPv4Address) else: fda_user['fixed_ip'] = None fda_user['admin_rights'] = user.getS( ns_ui.adminRights, rdf.Boolean) fda_user['vpn_rights'] = user.getS(ns_ui.vpnRights, rdf.Boolean) except: _log.exception('cannot fill data for a user, skipping')
def save_client_connection_data(self, ctx, form, data): cc_fda = formalutils.FormDataAccessor(form, ['client_connection'], ctx) ui_root = helpers.get_new_ui_config() # Server address & psk if cc_fda.has_key('server_name') and cc_fda['server_name'] is not None: ui_root.setS(ns_ui.vpnServerAddress, rdf.String, cc_fda['server_name']) else: ui_root.setS(ns_ui.vpnServerAddress, rdf.String, '') psk_seq = ui_root.setS(ns_ui.preSharedKeys, rdf.Seq(rdf.Type(ns_ui.PreSharedKey))) if cc_fda.has_key('psk_1') and (cc_fda['psk_1'] != '') and (cc_fda['psk_1'] is not None): psk = psk_seq.new() psk.setS(ns_ui.preSharedKey, rdf.String, cc_fda['psk_1']) if cc_fda.has_key('psk_2') and (cc_fda['psk_2'] != '') and (cc_fda['psk_2'] is not None): psk = psk_seq.new() psk.setS(ns_ui.preSharedKey, rdf.String, cc_fda['psk_2']) # DNS if cc_fda['dns'] == 'use_ic_dns': ui_root.setS(ns_ui.clientDnsServers, rdf.Type(ns_ui.NetworkConnectionDns)) elif cc_fda['dns'] == 'manual_dns': dns_root = ui_root.setS(ns_ui.clientDnsServers, rdf.Type(ns_ui.SetDnsServers)) uidatahelpers.save_optional_field_to_rdf(dns_root, ns_ui.primaryDns, rdf.IPv4Address, cc_fda, 'dns_1') uidatahelpers.save_optional_field_to_rdf(dns_root, ns_ui.secondaryDns, rdf.IPv4Address, cc_fda, 'dns_2') else: raise uidatahelpers.FormDataError( 'Client connection dns is neither network dns nor set dns.') # WINS # Note: parent node is ui-root, which may already have a value from old config, use empty default # value to remove old data in case form value is missing. uidatahelpers.save_optional_field_to_rdf(ui_root, ns_ui.clientPrimaryWins, rdf.IPv4Address, cc_fda, 'wins_1', default=None) uidatahelpers.save_optional_field_to_rdf(ui_root, ns_ui.clientSecondaryWins, rdf.IPv4Address, cc_fda, 'wins_2', default=None) ui_root.setS(ns_ui.clientSubnet, rdf.IPv4Subnet, cc_fda['client_subnet']) ui_root.setS(ns_ui.clientAddressRange, rdf.IPv4AddressRange, cc_fda['client_address_range']) ui_root.setS(ns_ui.clientCompression, rdf.Boolean, cc_fda['client_compression'])
def _clear_errors_from_disabled_fields(self): """Clears all the field errors from disabled fields. Validation must know which fields are disabled, while all the fields are enabled in the form post. """ form_fda = formalutils.FormDataAccessor(self.form, [], self.ctx) self._walk_through_disabled_fields( form_fda.clear_local_errors_and_warnings)
def _is_disabled(self, fda, fda_key, full_key=None): """Returns true if the field is disabled.""" if full_key is None: search_key = fda.combine(fda_key) else: search_key = full_key # Check if the field is in the dis_fields list. if self.dis_fields.has_key(search_key): # Check the conditions. # Uses full key names and main fda in order to give a possibility to disable/enable elements from # other groups. form_fda = formalutils.FormDataAccessor(self.form, [], self.ctx) for k in self.dis_fields[search_key].keys(): # If k is not found in main fda, k has a local error. Only local error in selection is that # selection is missing -> not disabled. Continue with other possible selections. if not (form_fda.has_key(k)): continue if form_fda[k] != self.dis_fields[search_key][k]: return True else: # Check if the key matches to dynamic list entries. for key in self.dyn_list_dis_fields.keys(): dyn_list_name, dyn_list_field = key.split('*') if (search_key[:len(dyn_list_name)] == dyn_list_name) and ( search_key[-len(dyn_list_field):] == dyn_list_field): # search_key matches, take the list index and check the conditions dyn_list_index = search_key[len(dyn_list_name ):-len(dyn_list_field)] for cond_key in self.dyn_list_dis_fields[key].keys(): cond_field = dyn_list_name + dyn_list_index + cond_key.split( '*')[1] form_fda = formalutils.FormDataAccessor( self.form, [], self.ctx) if not (form_fda.has_key(cond_field)): continue if form_fda[cond_field] != self.dyn_list_dis_fields[ key][cond_key]: return True return False
def form_config(self, ctx): form = formal.Form() dr = self.create_default_route_group(form, ctx) ar = self.create_additional_routes_group(form, ctx) sr = self.create_source_routing_group(form, ctx) fw = self.create_firewall_group(form, ctx) fwrule = self.create_ppp_firewall_group(form, ctx) pf = self.create_port_forwarding_group(form, ctx) form.add(dr) form.add(ar) form.add(sr) form.add(fwrule) form.add(fw) form.add(pf) try: toplevel_fda = formalutils.FormDataAccessor(form, [], ctx) self.fill_routing_group(form, ctx, toplevel_fda) except: _log.exception('failed to fill in form data, ignoring') try: fw_fda = formalutils.FormDataAccessor(form, ['firewall'], ctx) self.fill_firewall_group(form, ctx, fw_fda) except: _log.exception('failed to fill in form data, ignoring') try: pf_fda = formalutils.FormDataAccessor(form, ['port_forwards'], ctx) self.fill_port_forwarding_group(form, ctx, pf_fda) except: _log.exception('failed to fill in form data, ignoring') sg = formalutils.SubmitFieldGroup('buttons') sg.add( formalutils.SubmitField('submit', formal.String(), label='Save changes')) form.add(sg) form.addAction(self.submitted, name='submit', validate=False) return form
def submitted_configimport(self, ctx, form, data): fda = formalutils.FormDataAccessor(form, [], ctx) f = None # Here is the web UI import logic. We basically check the ZIP file, # extract the RDF/XML data, and stash it to the file system. We # then reboot, handling the actual import during reboot. To make # the use case as good as possible, basic sanity checking of the # RDF/XML data is done here, too. try: fda = fda.descend('import') cfg_data = self._parse_configuration_import(fda) if cfg_data is None: fda.add_error('importfile', 'File missing or empty') else: _log.info('configuration import file (rdf) is %s bytes long' % len(cfg_data)) # sanity check tmp_model = rdf.Model.fromString(cfg_data) if tmp_model is None: raise Exception('cannot create model') @db.transact(database=tmp_model) def _f(): # XXX: more checks here, like version, etc. # write to a temporary file for next reboot f = None try: f = open(constants.CONFIGURATION_IMPORT_BOOT_FILE, 'wb') f.write(tmp_model.toString(name='rdfxml')) finally: if f is not None: f.close() f = None _f() # reboot host, skip update on next boot request = inevow.IRequest(ctx) request.redirect( request.URLPath().sibling('waitconfigimport.html')) request.finish() return '' except: fda.add_error('importfile', 'Cannot parse file') _log.exception('import file check failed') if f is not None: f.close() fda.finalize_validation()
def _validate_radius(self, ctx, form, data): fda = formalutils.FormDataAccessor(form, ['radius'], ctx) ui_root = helpers.get_ui_config() # Basic RADIUS validation - currently limit server addresses to IP addresses # because of FreeRADIUS DNS lookup issues (lookup happens during startup and # failed lookup makes daemon exit) server_ip_addrs = [] for srv, prt, sec in [('server1', 'serverport1', 'secret1'), ('server2', 'serverport2', 'secret2')]: has_ip = False if fda.has_key(srv) and fda[srv] is not None and fda[srv] != '': # must be IP if nonempty has_ip = True ip_ok = False try: tmp = datatypes.IPv4Address.fromString(fda[srv]) server_ip_addrs.append(tmp) ip_ok = True except: _log.exception( 'cannot parse IP address from user input: %s' % fda[srv]) if not ip_ok: fda.add_error(srv, 'Invalid IP address') if fda.has_key(prt) and fda[prt] is not None: pass # already integer and range validated else: if has_ip: fda.add_error( prt, 'Required when server defined (suggested value: 1812)') if fda.has_key(sec) and fda[sec] is not None: if not uihelpers.check_radius_secret_characters(fda[sec]): fda.add_error(sec, 'Invalid characters') else: if has_ip: fda.add_error(sec, 'Required when server defined') # If two servers, don't allow same IP for both if len(server_ip_addrs) == 2: if server_ip_addrs[0] == server_ip_addrs[1]: fda.add_error( 'server2', 'Secondary server address cannot be the same as primary server address' ) # Nas-Identifier validation if fda.has_key('nasidentifier') and fda['nasidentifier'] is not None: if not uihelpers.check_radius_nai_identifier_characters( fda['nasidentifier']): fda.add_error('nasidentifier', 'Invalid characters')
def submitted_start_install(self, ctx, form, data): print 'submitted_start_install' fda = formalutils.FormDataAccessor(form, [], ctx) if not fda['startinstall.acceptlicense']: fda.add_error('startinstall.acceptlicense', 'Required') fda.finalize_validation() request = inevow.IRequest(ctx) request.redirect(request.URLPath().sibling('installtarget.html')) request.finish() return ''
def form_config(self, ctx): form = formal.Form() ifcount = self.create_iface_count_group(form, ctx) pubif = self.create_internet_connection_group(form, ctx) privif = self.create_private_network_group(form, ctx) dns = self.create_dns_group(form, ctx) dyndns = self.create_dynamic_dns_group(form, ctx) client = self.create_client_connection_group(form, ctx) form.add(ifcount) form.add(pubif) form.add(privif) form.add(dns) form.add(dyndns) form.add(client) try: # XXX: this data filler is one unit because ifcount, pubif, privif, dns, and dyndns # were previously part of one group fda = formalutils.FormDataAccessor(form, [], ctx) self.fill_network_config(form, ctx, fda) except: _log.exception('failed to fill in form data, ignoring') try: cc_fda = formalutils.FormDataAccessor(form, ['client_connection'], ctx) self.fill_client_connection_group(form, ctx, cc_fda) except: _log.exception('failed to fill in form data, ignoring') sg = formalutils.SubmitFieldGroup('buttons') sg.add( formalutils.SubmitField('submit', formal.String(), label='Save changes')) form.add(sg) form.addAction(self.submitted, name='submit', validate=False) return form
def fill_radius_group(self, ctx, form, g): fda = formalutils.FormDataAccessor(form, ['radius'], ctx) ui_root = helpers.get_ui_config() fda['server1'] = ui_root.getS(ns_ui.radiusPrimaryServer, rdf.String) fda['serverport1'] = ui_root.getS(ns_ui.radiusPrimaryServerPort, rdf.Integer) fda['secret1'] = ui_root.getS(ns_ui.radiusPrimarySecret, rdf.String) fda['server2'] = ui_root.getS(ns_ui.radiusSecondaryServer, rdf.String) fda['serverport2'] = ui_root.getS(ns_ui.radiusSecondaryServerPort, rdf.Integer) fda['secret2'] = ui_root.getS(ns_ui.radiusSecondarySecret, rdf.String) fda['nasidentifier'] = ui_root.getS(ns_ui.radiusNasIdentifier, rdf.String)
def submitted(self, ctx, form, data): fda = formalutils.FormDataAccessor(form, [], ctx).descend('changepassword') if fda.has_key('pw2') and fda.has_key('pw3') and (fda['pw2'] != fda['pw3']): fda.add_error('pw2', 'Passwords do not match') fda.add_error('pw3', 'Passwords do not match') # verify old password username = self.get_logged_in_username() user_rdf = uihelpers.find_user(username) if user_rdf is None: # presumably RADIUS user fda.add_error('pw1', 'Password change not allowed') else: if fda.has_key('pw1') and ( not uihelpers.check_username_and_password( username, fda['pw1'])): fda.add_error('pw1', 'Password incorrect') # prevent password change if marker exists; this is useful for demo server if os.path.exists(constants.NOPWCHANGE_MARKERFILE): _log.info('nopwchange marker exists, not changing password') fda.add_error('pw1', 'Password change not allowed') # finalize validation fda.finalize_validation() # XXX: does admin need control here? i.e., prevent changing of password? # ok, we're happy; change the password _log.info('changing password for user %s' % username) uihelpers.change_user_password(username, fda['pw2']) # restart radius server with new config; no need to nuke connections here because # no users are added or removed. try: pd = uidatahelpers.CreateProtocolData() pd.save_protocol_data(use_current_config=True) pd.activate_protocol_data(use_current_config=True) pd.restart_freeradius() # needs protocol config in place except: _log.exception('cannot restart freeradius, ignoring') # redirect request = inevow.IRequest(ctx) request.redirect(request.URLPath().sibling('passwordchanged.html')) request.finish() return ''
def save_firewall_data(self, ctx, form, data): def _save_port_forward_to_rdf(rdf_node, fda): rdf_node.setS(ns_ui.protocol, rdf.String, fda['new_fw_protocol']) uidatahelpers.save_optional_field_to_rdf(rdf_node, ns_ui.incomingPort, rdf.Integer, fda, 'new_fw_port_in') rdf_node.setS(ns_ui.ipAddress, rdf.IPv4Address, fda['new_fw_ip_out']) uidatahelpers.save_optional_field_to_rdf(rdf_node, ns_ui.destinationPort, rdf.Integer, fda, 'new_fw_port_out') ui_root = helpers.get_new_ui_config() fw_fda = formalutils.FormDataAccessor(form, ['firewall'], ctx) ui_root.setS(ns_ui.firewallInUse, rdf.Boolean, fw_fda['firewall_in_use']) # XXX: separate function pf_fda = formalutils.FormDataAccessor(form, ['port_forwards'], ctx) uidatahelpers.save_dynamic_list_to_rdf(ui_root, ns_ui.portForwards, ns_ui.PortForward, pf_fda, _save_port_forward_to_rdf)
def create_debug_group(self, form, ctx): debug_group = formalutils.CollapsibleGroup('debug_group', label='Debug') debug_group.setCollapsed(False) debug_group.add( formal.Field('debug', formal.Integer( required=True, validators=[formal.RangeValidator(min=0, max=2)]), label='Debug mode (0=normal, 1=light, 2=heavy)')) ui_root = db.get_db().getRoot().getS(ns_ui.uiConfig, rdf.Type(ns_ui.UiConfig)) # Default false if no entry found from the database. debug_fda = formalutils.FormDataAccessor(form, ['debug_group'], ctx) if ui_root.hasS(ns_ui.debug): debug_fda['debug'] = ui_root.getS(ns_ui.debug, rdf.Integer) else: debug_fda['debug'] = 0 return debug_group
def save_user_list(self, ctx, form, data, userpw_dict): def _save_user_to_rdf(user, fda): username = fda['username'] user.setS(ns_ui.username, rdf.String, username) # Password is tricky; we look up the previous config, and if a user # of this name existed and it had a password, use that password unless # a new one is specified. This is not perfect, but at least it works # correctly w.r.t. changed username. Note however that we do not track # user identity as such across a name change: if admin removes user XYZ # and adds a new user with name XYZ (with empty password field), that # user will simply inherit the older user XYZ password. if fda.has_key('password') and (fda['password'] is not None) and ( fda['password'] != ''): # set hashed password entries uihelpers.set_user_password_hashes(user, fda['password']) else: if userpw_dict.has_key(username): password_plain, password_md5, password_nt = userpw_dict[ username] user.setS(ns_ui.passwordMd5, rdf.String, password_md5) user.setS(ns_ui.passwordNtHash, rdf.String, password_nt) user.removeNodes(ns_ui.password) else: # this should not happen; log but don't fail badly _log.error( 'no password in form or userpw dict, should not happen' ) user.setS(ns_ui.password, rdf.String, '') uidatahelpers.save_optional_field_to_rdf(user, ns_ui.fixedIp, rdf.IPv4Address, fda, 'fixed_ip') user.setS(ns_ui.adminRights, rdf.Boolean, fda['admin_rights']) user.setS(ns_ui.vpnRights, rdf.Boolean, fda['vpn_rights']) ui_root = helpers.get_new_ui_config() fda = formalutils.FormDataAccessor(form, ['userlist_group'], ctx) uidatahelpers.save_dynamic_list_to_rdf(ui_root, ns_ui.users, ns_ui.User, fda, _save_user_to_rdf)
def _walk_through_disabled_fields(self, func): """Iterate trough disabled field keys and call function given as a parameter if a field is disabled.""" # Dynamic list callback function. def _check_dynamic_field(list_item_fda, list_index): search_key = dyn_list + str(list_index) + dyn_list_field if self._is_disabled(None, None, search_key): func(search_key) # Non-dynamic fields for key in self.dis_fields.keys(): if self._is_disabled(None, None, key): func(key) # Dynamic list fields for key in self.dyn_list_dis_fields: dyn_list, dyn_list_field = key.split('*') dyn_list_fda = formalutils.FormDataAccessor( self.form, [dyn_list[:-1]], self.ctx) # Take '.' away from dyn_list end. self._walk_through_dynamic_list(dyn_list_fda, _check_dynamic_field)
def fill_s2s_list(self, form, ctx, conn_list): fda = formalutils.FormDataAccessor(form, ['s2s_connections'], ctx) ui_root = helpers.get_ui_config() if ui_root.hasS(ns_ui.siteToSiteConnections): for idx, conn in enumerate( ui_root.getS(ns_ui.siteToSiteConnections, rdf.Seq(rdf.Type( ns_ui.SiteToSiteConnection)))): try: g = self._create_s2s_connection_list_entry(idx) fda_conn = fda.descend(str(idx)) fda_conn['s2s_username'] = conn.getS( ns_ui.username, rdf.String) fda_conn['s2s_password'] = conn.getS( ns_ui.password, rdf.String) # XXX: why is this API so weird? why not give the rdf:Seq and get a string in response? uidatahelpers.fill_subnet_list_to_form( conn, ns_ui.subnetList, fda_conn, 's2s_subnets') mode = conn.getS(ns_ui.mode, rdf.String) if mode == 'client': fda_conn['s2s_mode'] = 'client' fda_conn['s2s_psk'] = conn.getS( ns_ui.preSharedKey, rdf.String) fda_conn['s2s_server'] = conn.getS( ns_ui.serverAddress, rdf.String) elif mode == 'server': fda_conn['s2s_mode'] = 'server' fda_conn['s2s_psk'] = '' fda_conn['s2s_server'] = '' else: raise 'unknown mode: %s' % mode conn_list.add(g) except: _log.exception( 'cannot fill data for s2s connection, skipping')
def save_s2s_list_data(self, ctx, form, data): def _save_connection(conn, fda): conn.setS(ns_ui.username, rdf.String, fda['s2s_username']) conn.setS(ns_ui.password, rdf.String, fda['s2s_password']) uidatahelpers.save_subnet_list_to_rdf(conn, ns_ui.subnetList, fda, 's2s_subnets') mode = fda['s2s_mode'] if mode == 'client': conn.setS(ns_ui.mode, rdf.String, 'client') conn.setS(ns_ui.preSharedKey, rdf.String, fda['s2s_psk']) conn.setS(ns_ui.serverAddress, rdf.String, fda['s2s_server']) elif mode == 'server': conn.setS(ns_ui.mode, rdf.String, 'server') else: raise Exception('unknown mode: %s' % mode) ui_root = helpers.get_new_ui_config() fda = formalutils.FormDataAccessor(form, ['s2s_connections'], ctx) uidatahelpers.save_dynamic_list_to_rdf(ui_root, ns_ui.siteToSiteConnections, ns_ui.SiteToSiteConnection, fda, _save_connection)
def save_radius(self, ctx, form, data): ui_root = helpers.get_new_ui_config() fda = formalutils.FormDataAccessor(form, ['radius'], ctx) val = '' if fda.has_key('server1') and fda['server1'] is not None: val = fda['server1'] ui_root.setS(ns_ui.radiusPrimaryServer, rdf.String, val) val = 1812 if fda.has_key('serverport1') and fda['serverport1'] is not None: val = fda['serverport1'] ui_root.setS(ns_ui.radiusPrimaryServerPort, rdf.Integer, val) val = '' if fda.has_key('secret1') and fda['secret1'] is not None: val = fda['secret1'] ui_root.setS(ns_ui.radiusPrimarySecret, rdf.String, val) val = '' if fda.has_key('server2') and fda['server2'] is not None: val = fda['server2'] ui_root.setS(ns_ui.radiusSecondaryServer, rdf.String, val) val = 1812 if fda.has_key('serverport2') and fda['serverport2'] is not None: val = fda['serverport2'] ui_root.setS(ns_ui.radiusSecondaryServerPort, rdf.Integer, val) val = '' if fda.has_key('secret2') and fda['secret2'] is not None: val = fda['secret2'] ui_root.setS(ns_ui.radiusSecondarySecret, rdf.String, val) val = '' if fda.has_key('nasidentifier') and fda['nasidentifier'] is not None: val = fda['nasidentifier'] ui_root.setS(ns_ui.radiusNasIdentifier, rdf.String, val)
def submitted(self, ctx, form, data): fda = formalutils.FormDataAccessor(form, [], ctx) fda.finalize_validation() self.save_ui_data(ctx, form, data)
def save_debug(self, ctx, form, data): ui_root = db.get_db().getRoot().getS(ns_ui.uiConfig, rdf.Type(ns_ui.UiConfig)) debug_fda = formalutils.FormDataAccessor(form, ['debug_group'], ctx) ui_root.setS(ns_ui.debug, rdf.Integer, debug_fda['debug'])
def submitted(self, ctx, form, data): fda = formalutils.FormDataAccessor(form, [], ctx) pd = uidatahelpers.CreateProtocolData() # Save collapsed states first, so they feed back to next round for [rdf_uri, key] in [[ns_ui.collapseInterfaceCount, 'ifcount_group'], [ns_ui.collapseInternetConnection, 'ic_group'], [ns_ui.collapsePrivateNetwork, 'pn_group'], [ns_ui.collapseDns, 'dns_group'], [ns_ui.collapseDynamicDns, 'ddns_group'], [ns_ui.collapseClientConnection, 'client_connection']]: try: # XXX: passing of the hidden _collapsedstate_ parameter is not too clean uihelpers.update_collapse_setting( rdf_uri, fda['%s._collapsedstate_' % key]) except: _log.exception('error updating collapsed state for %s' % rdf_uri) # Validation and config generation old_vpn_server_address = None try: # Form global canonicalization gc = networkconfigvalidation.ConfigNetworkCanonicalizator( ctx, form, data) gc.canonicalize_ip_subnet() # Form global validation gv = networkconfigvalidation.ConfigNetworkValidator( ctx, form, data) # Check required fields. Some fields may be required because of some other fields value and thus cannot # be checked locally. gv.check_required_fields() gv.ip_and_subnet_match() # Checks public and private. gv.public_private_ip_not_same( ) # XXX: warning for now only; worth a warning, but still works to some extent gv.public_private_eth_not_same() gv.check_single_interface_ok() gv.check_interface_default_gateways() gv.check_public_subnet( ) # XXX: warning for now only, overlaps don't cause runner errors gv.check_private_subnet( ) # XXX: warning for now only, overlaps don't cause runner errors gv.check_uplink() gv.check_only_one_proxyarp() gv.check_dns_dhcp_valid() gv.check_client_settings( ) # XXX: some checks commented to warnings for now # Intermediate early bail out to avoid saving if there are errors gv.finalize_validation() # XXX: One interface setup could rename the internet connection tab to # network connection, and update all the selections. # Get old VPN server address for comparison ui_root = helpers.get_ui_config() if ui_root.hasS(ns_ui.vpnServerAddress): old_vpn_server_address = ui_root.getS(ns_ui.vpnServerAddress, rdf.String) # Deep copy UI config to 'new' UI config pd.clone_ui_config() # Save form data self.save_network_data(ctx, form, data) self.save_client_connection_data(ctx, form, data) # newUiConfig -> newL2tpDeviceConfig pd.save_protocol_data() except: _log.exception( 'validation failed unexpectedly, adding global error') fda.add_global_error('Unknown validation error') # Finalize raises exception if there are errors and handles disabled fields as well as copying form data to errors data. gv.finalize_validation() # Save ok, activate config pd.activate_protocol_data() # Update initial config saved flag pd.update_initial_config_saved() # If certificate name has changed, regenerate and re-read cert files new_vpn_server_address = None ui_root = helpers.get_ui_config() # reget root after change if ui_root.hasS(ns_ui.vpnServerAddress): new_vpn_server_address = ui_root.getS(ns_ui.vpnServerAddress, rdf.String) # XXX: unnecessary to check for None now, but doesn't hurt if (old_vpn_server_address != new_vpn_server_address): common_name = None if (new_vpn_server_address is not None) and (new_vpn_server_address != ''): common_name = new_vpn_server_address _log.info('regenerating ssl certificates, common name %s' % common_name) @db.untransact() def _regenerate(): helpers.generate_self_signed_certificate( constants.WEBUI_PRIVATE_KEY, constants.WEBUI_CERTIFICATE, common_name=common_name) _regenerate() self.master.reread_ssl_files() else: _log.debug('certificate name unchanged, not regenerating') # # XXX: It would be cleaner if we could first stop the runner, then change the # config, and then restart it. If we do that with a deferred, then it is possible # that the user changes the config again before we have time to activate it. # Putting the config into some sort of "staging area" might help. Currently we # simply assume that runner stop (and start) are robust enough. # # stop, configure, start followup = uihelpers.build_uri(ctx, 'status/main.html') return uihelpers.reconfigure_and_restart_page(self.master, ctx, followup_uri=followup)
def save_routes_data(self, ctx, form, data): def _save_additional_route_to_rdf(rdf_node, fda): uidatahelpers.create_rdf_route(rdf_node, fda['subnet'], fda['network_connection'], fda['gateway'], ns_ui.route) def _save_ppp_firewall_rule_to_rdf(rdf_node, fda): if isinstance(fda['ip_subnet'], datatypes.IPv4Address): rdf_node.setS(ns_ui.ipAddress, rdf.IPv4Address, fda['ip_subnet']) elif isinstance(fda['ip_subnet'], datatypes.IPv4Subnet): rdf_node.setS(ns_ui.subnet, rdf.IPv4Subnet, fda['ip_subnet']) else: raise uidatahelpers.FormDataError( 'Firewall rule IP/subnet is neither IPv4Address nor IPv4Subnet' ) if fda['protocol'] == 'any': pass else: rdf_node.setS(ns_ui.protocol, rdf.String, fda['protocol']) uidatahelpers.save_optional_field_to_rdf(rdf_node, ns_ui.port, rdf.Integer, fda, 'port') rdf_node.setS(ns_ui.action, rdf.String, fda['action']) toplevel_fda = formalutils.FormDataAccessor(form, [], ctx) ui_root = helpers.get_new_ui_config() # Default route droute_fda = toplevel_fda.descend('dr_group') uidatahelpers.create_rdf_route(ui_root, None, droute_fda['network_connection'], droute_fda['gateway'], ns_ui.defaultRoute) # Additional routes add_route_fda = toplevel_fda.descend('ar_group') uidatahelpers.save_dynamic_list_to_rdf(ui_root, ns_ui.routes, ns_ui.Route, add_route_fda, _save_additional_route_to_rdf) # Source routing (forced routing) source_fda = toplevel_fda.descend('sr_group') if source_fda['source_routing_selection'] == 'off': ui_root.removeNodes(ns_ui.sourceRouting) elif source_fda['source_routing_selection'] == 'on': uidatahelpers.create_rdf_route(ui_root, None, source_fda['network_connection'], source_fda['gateway'], ns_ui.sourceRouting) else: raise uidatahelpers.FormDataError( 'Forced routing is neither on nor off.') # PPP firewall rules fwrule_fda = toplevel_fda.descend('fwrule_group') uidatahelpers.save_dynamic_list_to_rdf(ui_root, ns_ui.pppFirewallRules, ns_ui.PppFirewallRule, fwrule_fda, _save_ppp_firewall_rule_to_rdf)
def submitted(self, ctx, form, data): fda = formalutils.FormDataAccessor(form, [], ctx) pd = uidatahelpers.CreateProtocolData() # Save collapsed states first, so they feed back to next round for [rdf_uri, key] in [[ns_ui.collapseLicense, 'license_group'], [ns_ui.collapseLocale, 'locale_group'], [ns_ui.collapseProductMaintenance, 'reboot_group'], [ns_ui.collapseSnmp, 'snmp_group'], [ns_ui.collapseRemoteManagement, 'remote_group'], [ns_ui.collapseSslCertificate, 'ssl_group']]: try: # XXX: passing of the hidden _collapsedstate_ parameter is not too clean uihelpers.update_collapse_setting( rdf_uri, fda['%s._collapsedstate_' % key]) except: _log.exception('error updating collapsed state for %s' % rdf_uri) try: # global canonicalization tmp = fda.descend('license_group') if tmp.has_key('license_key') and (tmp['license_key'] is not None): tmp['license_key'] = tmp['license_key'].upper().strip() # global validation tmp = fda.descend('license_group') if tmp.has_key('license_key') and (tmp['license_key'] is not None): val, grps = None, None try: val, grps = licensekey.decode_license(tmp['license_key']) except: _log.exception('license decoding failed') if val is None: tmp.add_error('license_key', 'Invalid license key') tmp = fda.descend('remote_group') if tmp.has_key('root_password1') and tmp.has_key('root_password2'): pw1, pw2 = tmp['root_password1'], tmp['root_password2'] if pw1 is None: pw1 = '' if pw2 is None: pw2 = '' if pw1 != pw2: tmp.add_error('root_password1', 'Passwords do not match') tmp.add_error('root_password2', 'Passwords do not match') else: if not helpers.check_unix_password_characters(pw1): tmp.add_error('root_password1', 'Invalid characters in password') tmp.add_error('root_password2', 'Invalid characters in password') tmp = fda.descend('snmp_group') if tmp.has_key( 'snmp_community') and tmp['snmp_community'] is not None: if not uihelpers.check_snmp_community_characters( tmp['snmp_community']): tmp.add_error('snmp_community', 'Invalid characters') # # XXX -- How to validate SSL certificates reliably? Currently invalid # certificate / key causes VPNease to use self-signed version so it's # relatively OK. # # # XXX -- admin smtp setting validation & normalization # # Intermediate early bail out to avoid saving if there are errors fda.finalize_validation() # Deep copy UI config to 'new' UI config pd.clone_ui_config() # save data self.save_ui_data(ctx, form, data) # re-create protocol data to see if new exceptions crop up pd.save_protocol_data() except: _log.exception( 'validation failed unexpectedly, adding global error') fda.add_global_error('Unknown validation error') # finalize; raises if something wrong fda.finalize_validation() # locale settings are handled directly cfg_ui = helpers.get_new_ui_config() try: cfg_ui.setS(ns_ui.timezone, rdf.String, fda['locale_group.timezone']) cfg_ui.setS(ns_ui.keymap, rdf.String, fda['locale_group.keymap']) gnomeconfig.set_keymap_settings( cfg_ui.getS(ns_ui.keymap, rdf.String)) except: _log.exception('activating timezone and keymap settings failed') # same with root password try: tmp = fda.descend('remote_group') if tmp.has_key('root_password1') and tmp.has_key('root_password2'): pw1, pw2 = tmp['root_password1'], tmp['root_password2'] if (pw1 == '') and (pw2 == ''): pass elif (pw1 == None) and (pw2 == None): pass elif pw1 == pw2: # change password; we assume it converts to ascii nicely helpers.change_unix_password('root', str(pw1)) else: # should not come here _log.error('passwords differ after validation, ignoring') except: _log.exception('changing root password failed') # activate new config pd.activate_protocol_data() # update initial config saved flag pd.update_initial_config_saved() # # XXX: It would be cleaner if we could first stop the runner, then change the # config, and then restart it. If we do that with a deferred, then it is possible # that the user changes the config again before we have time to activate it. # Putting the config into some sort of "staging area" might help. Currently we # simply assume that runner stop (and start) are robust enough. # # # XXX: If timezone has changed, we should re-render graphs immediately so they # will have the correct timezone when status pages are loaded. # # ssl certificate - always rewrite here try: uihelpers.update_ssl_certificate_files() # reread files; we don't regenerate because we never overwrite the self-signed # certificate here self.master.reread_ssl_files() except: _log.exception('ssl certificate check failed') # stop, configure, start followup = uihelpers.build_uri(ctx, 'status/main.html') return uihelpers.reconfigure_and_restart_page(self.master, ctx, followup_uri=followup)
def save_ui_data(self, ctx, form, data): fda = formalutils.FormDataAccessor(form, [], ctx) ui_root = helpers.get_new_ui_config() # XXX: this should probably be refactored to uihelpers, in conjunction # with the access control element def _set_access(ns_pub, ns_priv, val): _log.debug('_set_access: %s' % val) if val == 'both': ui_root.setS(ns_pub, rdf.Boolean, True) ui_root.setS(ns_priv, rdf.Boolean, True) elif val == 'public': ui_root.setS(ns_pub, rdf.Boolean, True) ui_root.setS(ns_priv, rdf.Boolean, False) elif val == 'private': ui_root.setS(ns_pub, rdf.Boolean, False) ui_root.setS(ns_priv, rdf.Boolean, True) else: ui_root.setS(ns_pub, rdf.Boolean, False) ui_root.setS(ns_priv, rdf.Boolean, False) tmp = fda.descend('license_group') if tmp.has_key('license_key') and tmp['license_key'] is not None: lic_key = tmp['license_key'].upper() ui_root.setS(ns_ui.licenseKey, rdf.String, lic_key) else: # empty field (None) => clear product license ui_root.setS(ns_ui.licenseKey, rdf.String, '') tmp = fda.descend('locale_group') tmp = fda.descend('reboot_group') ui_root.setS(ns_ui.periodicRebootDay, rdf.Integer, tmp['reboot_day']) ui_root.setS(ns_ui.periodicRebootTime, rdf.Integer, tmp['reboot_time']) ui_root.setS(ns_ui.automaticUpdates, rdf.Boolean, tmp['automatic_updates']) tmp = fda.descend('snmp_group') _set_access(ns_ui.snmpAccessPublic, ns_ui.snmpAccessPrivate, tmp['snmp_access']) if tmp.has_key('snmp_community') and tmp['snmp_community'] is not None: ui_root.setS(ns_ui.snmpCommunity, rdf.String, tmp['snmp_community']) else: ui_root.setS(ns_ui.snmpCommunity, rdf.String, '') tmp = fda.descend('remote_group') _set_access(ns_ui.webAccessPublic, ns_ui.webAccessPrivate, tmp['www_administration']) _set_access(ns_ui.sshAccessPublic, ns_ui.sshAccessPrivate, tmp['ssh_connection']) tmp = fda.descend('ssl_group') if tmp.has_key('ssl_certificate_chain' ) and tmp['ssl_certificate_chain'] is not None: ui_root.setS(ns_ui.publicSslCertificateChain, rdf.String, tmp['ssl_certificate_chain']) else: ui_root.setS(ns_ui.publicSslCertificateChain, rdf.String, '') if tmp.has_key( 'ssl_private_key') and tmp['ssl_private_key'] is not None: ui_root.setS(ns_ui.publicSslPrivateKey, rdf.String, tmp['ssl_private_key']) else: ui_root.setS(ns_ui.publicSslPrivateKey, rdf.String, '')
def form_management(self, ctx): form = formal.Form() fda = formalutils.FormDataAccessor(form, [], ctx) tzhelp = uihelpers.TimezoneHelper() txt = self.mng_uitexts ### License g = formalutils.CollapsibleGroup('license_group', label=txt.license_group_caption) g.setCollapsed(uihelpers.collapse_setting(ns_ui.collapseLicense)) g.add( formalutils.Field('license_key', formal.String(required=False), label=txt.license_key_label)) form.add(g) ### Locale tzoptions = [] for tzname in tzhelp.get_timezones(): tzoptions.append((tzname, tzname)) def _tz_cmp(x, y): x_name, x_label = x y_name, y_label = y return unicode.__cmp__(unicode(x_label), unicode(y_label)) tzoptions.sort(cmp=_tz_cmp) # XXX: keymap values are truncated because they are so long keymapoptions = [] for gname, gname_escaped, human in gnomeconfig.get_keymap_list(): keymapoptions.append( (gname_escaped, uihelpers.ui_truncate(human, 56))) def _km_cmp(x, y): x_name, x_label = x y_name, y_label = y return unicode.__cmp__(unicode(x_label), unicode(y_label)) keymapoptions.sort(cmp=_km_cmp) g = formalutils.CollapsibleGroup('locale_group', label='Locale Settings') g.setCollapsed(uihelpers.collapse_setting(ns_ui.collapseLocale)) g.add( formalutils.Field('timezone', formal.String(required=True), formal.widgetFactory(formal.SelectChoice, options=tzoptions), label='Timezone')) g.add( formalutils.Field('keymap', formal.String(required=True), formal.widgetFactory(formal.SelectChoice, options=keymapoptions), label='Keyboard layout')) # XXX: it would be good if we could show a time example using the timezone # admin has selected. form.add(g) ### Reboots g = formalutils.CollapsibleGroup('reboot_group', label=txt.reboot_group_caption) g.setCollapsed( uihelpers.collapse_setting(ns_ui.collapseProductMaintenance)) g.add( formalutils.Field('reboot_day', formal.Integer(required=True), formal.widgetFactory( formal.SelectChoice, options=txt.reboot_day_options), label=txt.reboot_day_label)) g.add( formalutils.Field('reboot_time', formal.Integer(required=True), formal.widgetFactory( formal.SelectChoice, options=txt.reboot_time_options), label=txt.reboot_time_label)) # Information about the periodic reboot consequences (about 5 minutes downtime). g.add( formalutils.Field('automatic_updates', formal.Boolean(required=True), label=txt.automatic_update_label)) form.add(g) ### SNMP g = formalutils.CollapsibleGroup('snmp_group', label='SNMP Monitoring') g.setCollapsed(uihelpers.collapse_setting(ns_ui.collapseSnmp)) g.add( uihelpers.create_access_control_dropdown('snmp_access', 'SNMP read-only access')) g.add( formalutils.Field('snmp_community', formal.String(required=False), formal.widgetFactory( formalutils.SemiHiddenPassword), label='SNMP community string (password)')) form.add(g) ### Remote management g = formalutils.CollapsibleGroup('remote_group', label=txt.remote_group_caption) g.setCollapsed( uihelpers.collapse_setting(ns_ui.collapseRemoteManagement)) g.add( uihelpers.create_access_control_dropdown('www_administration', 'Web administration')) g.add( uihelpers.create_access_control_dropdown('ssh_connection', 'SSH connection')) g.add( formalutils.Field('root_password1', formal.String(required=False), formal.widgetFactory(formalutils.HiddenPassword), label='Set root password')) g.add( formalutils.Field('root_password2', formal.String(required=False), formal.widgetFactory(formalutils.HiddenPassword), label='Re-enter root password')) form.add(g) ### Admin e-mails # XXX: not yet implemented #g = formalutils.CollapsibleGroup('email_group', label='Administrator E-mail') #g.setCollapsed(uihelpers.collapse_setting(ns_ui.collapseAdminEmail)) #g.add(formalutils.Field('smtp_server', formal.String(required=False), label='SMTP server')) #g.add(formalutils.Field('smtp_from', formal.String(required=False), label='FROM address')) #g.add(formalutils.Field('smtp_to', formal.String(required=False), label='TO address(es) (comma separated)')) #form.add(g) ### SSL certificate g = formalutils.CollapsibleGroup('ssl_group', label='SSL Certificate') g.setCollapsed(uihelpers.collapse_setting( ns_ui.collapseSslCertificate)) g.add( formalutils.Field( 'ssl_certificate_chain', formal.String(required=False), formal.widgetFactory(formal.TextArea, cols=80, rows=10), label= 'SSL Certificate Chain (PEM format, server certificate first)') ) g.add( formalutils.Field('ssl_private_key', formal.String(required=False), formal.widgetFactory(formal.TextArea, cols=80, rows=10), label='SSL Private Key (PEM format)')) form.add(g) ### Submit buttons sg = formalutils.SubmitFieldGroup('buttons') sg.add( formalutils.SubmitField('submit', formal.String(), label='Save changes')) form.add(sg) form.addAction(self.submitted, name='submit', validate=False) ### Fill data to form try: self.fill_management(ctx, fda) except: # ignore failure so user has chance to edit the form _log.exception('fill_form_data failed, ignoring') return form
def submitted(self, ctx, form, data): fda = formalutils.FormDataAccessor(form, [], ctx) pd = uidatahelpers.CreateProtocolData() # Save collapsed states first, so they feed back to next round for [rdf_uri, key] in [[ns_ui.collapseRadius, 'radius']]: try: # XXX: passing of the hidden _collapsedstate_ parameter is not too clean uihelpers.update_collapse_setting( rdf_uri, fda['%s._collapsedstate_' % key]) except: _log.exception('error updating collapsed state for %s' % rdf_uri) old_radius_info = None new_radius_info = None try: # Pre-step: collect usernames and passwords in previous config; we'll need # them to deal with password changing correctly. userpw_dict = uihelpers.get_user_password_dict() # Basic validation fda = formalutils.FormDataAccessor(form, ['userlist_group'], ctx) self._validate_users(ctx, form, data, userpw_dict) self._validate_radius(ctx, form, data) # Intermediate early bail out to avoid saving if there are errors fda.finalize_validation() # Get old runner-critical RADIUS info for comparison old_radius_info = self._get_radius_info(new_ui_config=False) # Deep copy UI config to 'new' UI config pd.clone_ui_config() # Save form data to rdf database self.save_radius(ctx, form, data) self.save_user_list(ctx, form, data, userpw_dict) # Get new runner-critical RADIUS info for comparison new_radius_info = self._get_radius_info(new_ui_config=True) # Save protocol data and finalize validation pd.save_protocol_data() except: _log.exception( 'validation failed unexpectedly, adding global error') fda.add_global_error('Unknown validation error') fda.finalize_validation() # Check whether a full restart is required or not; although we can edit user # information without a full restart (in which case FreeRADIUS is reconfigured # and restarted), we can't add, remote, or edit RADIUS server addresses because # runner would not get the new server information to its monitoring list. _log.debug('old radius info: %s, new radius info: %s' % (old_radius_info, new_radius_info)) full_restart_required = (old_radius_info != new_radius_info) if full_restart_required: _log.info('radius servers changed, full restart required') # Activate new config pd.activate_protocol_data() # Update initial config saved flag pd.update_initial_config_saved() # # XXX: It would be cleaner if we could first stop the runner, then change the # config, and then restart it. If we do that with a deferred, then it is possible # that the user changes the config again before we have time to activate it. # Putting the config into some sort of "staging area" might help. Currently we # simply assume that runner stop (and start) are robust enough. # # stop, configure, start followup = uihelpers.build_uri(ctx, 'status/main.html') return uihelpers.reconfigure_and_restart_page( self.master, ctx, followup_uri=followup) else: _log.info('radius servers not changed, only freeradius restart') # Nuke unwanted PPP connections first time here, so their corresponding # protocol config is intact, leading to a clean teardown. try: pd.recheck_and_drop_ppp_connections() except: _log.exception('ppp device recheck failed') # Activate new config # XXX - just change user data here? pd.activate_protocol_data() # Update initial config saved flag pd.update_initial_config_saved() try: pd.restart_freeradius() # needs protocol config in place except: _log.exception('freeradius restart failed') # Check again for unwanted PPP devices; teardowns here will currently be ugly try: pd.recheck_and_drop_ppp_connections() except: _log.exception('ppp device recheck failed') # just a fake activation page followup = uihelpers.build_uri(ctx, 'status/main.html') return uihelpers.reconfigure_page(self.master, ctx, followup_uri=followup)
def _validate_users(self, ctx, form, data, userpw_dict): fda = formalutils.FormDataAccessor(form, ['userlist_group'], ctx) ui_root = helpers.get_ui_config() # user list validation idx = 0 users = [] while True: fda_user = fda.descend(str(idx)) if len(fda_user.keys()) == 0: break users.append(fda_user) idx += 1 s2s_server_usernames = [] if ui_root.hasS(ns_ui.siteToSiteConnections): for s2s_conn in ui_root.getS( ns_ui.siteToSiteConnections, rdf.Seq(rdf.Type(ns_ui.SiteToSiteConnection))): if s2s_conn.hasS(ns_ui.mode) and s2s_conn.getS( ns_ui.mode, rdf.String) == 'server' and s2s_conn.hasS( ns_ui.username): s2s_server_usernames.append( s2s_conn.getS(ns_ui.username, rdf.String)) usernames_found = [] fixed_ips_found = [] for fda_user_index, fda_user in enumerate(users): # username checks if fda_user.has_key('username'): if not uihelpers.check_ppp_username_characters( fda_user['username']): fda_user.add_error('username', 'Invalid characters') else: username = fda_user['username'] if username in usernames_found: fda_user.add_error('username', 'Duplicate username') elif username in s2s_server_usernames: fda_user.add_error( 'username', 'Duplicate username (already a site-to-site server-mode connection of that name)' ) elif len(username) > constants.MAX_USERNAME_LENGTH: fda_user.add_error('username', 'Username too long') else: usernames_found.append(username) # password chars if fda_user.has_key('password') and (fda_user['password'] is not None): if not uihelpers.check_ppp_password_characters( fda_user['password']): fda_user.add_error('password', 'Invalid characters') elif len(fda_user['password']) > constants.MAX_PASSWORD_LENGTH: fda_user.add_error('password', 'Password too long') # Password is a bit tricky; admin may have changed a username and we don't have # any permanent user identifiers that allow us to identify this as the same user # and keep its password despite the name change. So, we require either that the # password is set, or that a user previously existed with this username (changed # or not !) and use the old password. if fda_user.has_key('username') and (fda_user['username'] is not None) and \ (not fda_user.has_key('password') or fda_user['password'] is None or fda_user['password'] == ''): username = fda_user['username'] if userpw_dict.has_key(username): # all ok pass else: fda_user.add_error('password', 'Required for new users') # fixed ip checks # XXX: we could also check that the fixed IP is from the # PPP subnet to try to prevent admin configuration errors, # but this would be too restrictive and is currently not # done: a warning would help here. if fda_user.has_key('fixed_ip') and ( fda_user['fixed_ip'] is not None) and (fda_user['fixed_ip'] != ''): fixed_ip_errors = False fixed_ip = fda_user['fixed_ip'] iprange = ui_root.getS(ns_ui.clientAddressRange, rdf.IPv4AddressRange) pppsubnet = ui_root.getS(ns_ui.clientSubnet, rdf.IPv4Subnet) # The fixed IP may not overlap with other users fixed IP addresses if fixed_ip.toString() in fixed_ips_found: fda_user.add_error('fixed_ip', 'Duplicate fixed IP address') fixed_ip_errors = True # Check restricted addresses inside PPP subnet if pppsubnet.inSubnet(fixed_ip): # The fixed IP must not be from the PPP address range (dynamic allocation pool) if iprange.inRange(fixed_ip): fda_user.add_error( 'fixed_ip', 'Overlaps with client address range') fixed_ip_errors = True if fixed_ip < pppsubnet.getFirstUsableAddress(): fda_user.add_error( 'fixed_ip', 'First address of the client subnet prohibited') fixed_ip_errors = True elif fixed_ip == pppsubnet.getLastUsableAddress(): fda_user.add_error( 'fixed_ip', 'Last usable address of the client subnet prohibited' ) fixed_ip_errors = True elif fixed_ip > pppsubnet.getLastUsableAddress(): fda_user.add_error( 'fixed_ip', 'Last address of the client subnet prohibited') fixed_ip_errors = True if not fixed_ip_errors: fixed_ips_found.append(fixed_ip.toString())
def submitted(self, ctx, form, data): fda = formalutils.FormDataAccessor(form, [], ctx) pd = uidatahelpers.CreateProtocolData() # Save collapsed states first, so they feed back to next round for [rdf_uri, key] in [[ns_ui.collapseDefaultRoute, 'dr_group'], [ns_ui.collapseAdditionalRoutes, 'ar_group'], [ns_ui.collapseSourceRouting, 'sr_group'], [ns_ui.collapsePppFirewallRules, 'fwrule_group'], [ns_ui.collapsePortForwardingRules, 'port_forwards'], [ns_ui.collapseFirewall, 'firewall']]: try: # XXX: passing of the hidden _collapsedstate_ parameter is not too clean uihelpers.update_collapse_setting( rdf_uri, fda['%s._collapsedstate_' % key]) except: _log.exception('error updating collapsed state for %s' % rdf_uri) # Validation and config generation try: # Form global canonicalization gc = networkconfigvalidation.ConfigNetworkCanonicalizator( ctx, form, data) # Form global validation gv = networkconfigvalidation.ConfigNetworkValidator( ctx, form, data) # Check required fields. Some fields may be required because of some other fields value and thus cannot # be checked locally. gv.check_required_fields_routingfirewall() # Global checks for internet and private network connection. gv.check_route_destination_valid( ) # just checks that some destination is defined, not that e.g. private network exists gv.check_ppp_firewall_rules() # Intermediate early bail out to avoid saving if there are errors gv.finalize_validation() # XXX: we might want to add warnings here later if route subnets overlap with each other # or with site-to-site subnets # Deep copy UI config to 'new' UI config pd.clone_ui_config() # Save form data. self.save_routes_data(ctx, form, data) self.save_firewall_data(ctx, form, data) pd.save_protocol_data() except: _log.exception( 'validation failed unexpectedly, adding global error') fda.add_global_error('Unknown validation error') # Finalize raises exception if there are errors and handles disabled fields as well as copying form data to erros data. gv.finalize_validation() # Save ok, activate config pd.activate_protocol_data() # Update initial config saved flag pd.update_initial_config_saved() # # XXX: It would be cleaner if we could first stop the runner, then change the # config, and then restart it. If we do that with a deferred, then it is possible # that the user changes the config again before we have time to activate it. # Putting the config into some sort of "staging area" might help. Currently we # simply assume that runner stop (and start) are robust enough. # # stop, configure, start followup = uihelpers.build_uri(ctx, 'status/main.html') return uihelpers.reconfigure_and_restart_page(self.master, ctx, followup_uri=followup)
def submitted_select_target(self, ctx, form, data): print 'submitted_select_target' # XXX: target selection error messages as constants? fda = formalutils.FormDataAccessor(form, [], ctx) target = None recovery = False large_install = False try: target = form.data['selecttarget.target'] print 'selected target: %s' % target medium = mediahelper.get_media().get_medium_by_device_name(target) if medium.get_size() < constants.DISK_SIZE_MINIMUM: fda.add_error('selecttarget.target', 'Minimum target medium size is 2 GB') if medium.is_write_protected(): fda.add_error('selecttarget.target', 'Target medium is write-protected') if form.data.has_key('selecttarget.recovery'): recovery = form.data['selecttarget.recovery'] if medium.get_size( ) >= constants.DISK_SIZE_MINIMUM_FOR_LARGE_INSTALL: large_install = True except: fda.add_error('selecttarget.target', 'Target medium cannot be selected') fda.finalize_validation() root = livecddb.get_livecd_database_root() root.setS(ns_ui.targetDevice, rdf.String, target) root.setS(ns_ui.attemptRecovery, rdf.Boolean, recovery) root.removeNodes(ns_ui.previousConfigurationRdfXml) root.removeNodes(ns_ui.previousInstalledVersion) # Recovery check here if recovery: print 'attempting recovery from %s' % target try: prev_cfg, prev_version = installhelpers.recover_existing_configuration( target) if prev_cfg is not None: root.setS(ns_ui.previousConfigurationRdfXml, rdf.String, prev_cfg.encode('hex')) if prev_version is not None: root.setS(ns_ui.previousInstalledVersion, rdf.String, prev_version) else: pass else: raise Exception('did not find recovery data') except: print 'recovery failed' # Select installation model based on target size root.setS(ns_ui.installLargeDisk, rdf.Boolean, large_install) print livecddb.dump_livecd_database() request = inevow.IRequest(ctx) request.redirect(request.URLPath().sibling('installconfirm.html')) return ''