def ProcessCronNode(self, node): """Processes XML <cron> nodes into Cron objects. The following information is parsed out: description: Describing the purpose of the cron job. url: The location of the script. schedule: Written in groc; the schedule according to which the job is executed. timezone: The timezone that the schedule runs in. target: Which version of the app this applies to. Args: node: <cron> XML node in cron.xml. """ tag = xml_parser_utils.GetTag(node) if tag != 'cron': self.errors.append('Unrecognized node: <%s>' % tag) return cron = Cron() cron.url = xml_parser_utils.GetChildNodeText(node, 'url') cron.timezone = xml_parser_utils.GetChildNodeText(node, 'timezone') cron.target = xml_parser_utils.GetChildNodeText(node, 'target') cron.description = xml_parser_utils.GetChildNodeText( node, 'description') cron.schedule = xml_parser_utils.GetChildNodeText(node, 'schedule') validation_error = self._ValidateCronEntry(cron) if validation_error: self.errors.append(validation_error) else: self.crons.append(cron)
def ProcessBlacklistNode(self, node): """Processes XML <blacklist> nodes into BlacklistEntry objects. The following information is parsed out: subnet: The IP, in CIDR notation. description: (optional) If there are no errors, the data is loaded into a BlackListEntry object and added to a list. Upon error, a description of the error is added to a list and the method terminates. Args: node: <blacklist> XML node in dos.xml. """ tag = xml_parser_utils.GetTag(node) if tag != 'blacklist': self.errors.append('Unrecognized node: <%s>' % tag) return entry = BlacklistEntry() entry.subnet = xml_parser_utils.GetChildNodeText(node, 'subnet') entry.description = xml_parser_utils.GetChildNodeText( node, 'description') validation = self._ValidateEntry(entry) if validation: self.errors.append(validation) return self.blacklist_entries.append(entry)
def ProcessBasicScalingNode(self, node): basic_scaling = BasicScaling() basic_scaling.max_instances = xml_parser_utils.GetChildNodeText( node, 'max-instances').strip() basic_scaling.idle_timeout = xml_parser_utils.GetChildNodeText( node, 'idle-timeout').strip() self.app_engine_web_xml.basic_scaling = basic_scaling
def ProcessDispatchNode(self, node): """Processes XML <dispatch> nodes into DispatchEntry objects. The following information is parsed out: url: The URL or URL pattern to route. module: The module to route it to. If there are no errors, the data is loaded into a DispatchEntry object and added to a list. Upon error, a description of the error is added to a list and the method terminates. Args: node: <dispatch> XML node in dos.xml. """ tag = xml_parser_utils.GetTag(node) if tag != 'dispatch': self.errors.append('Unrecognized node: <%s>' % tag) return entry = DispatchEntry() entry.url = xml_parser_utils.GetChildNodeText(node, 'url') entry.module = xml_parser_utils.GetChildNodeText(node, 'module') validation = self._ValidateEntry(entry) if validation: self.errors.append(validation) return self.dispatch_entries.append(entry)
def ProcessMimeMappingNode(self, node): extension = xml_parser_utils.GetChildNodeText(node, 'extension') mime_type = xml_parser_utils.GetChildNodeText(node, 'mime-type') if not extension: self.errors.append('<mime-type> without extension') return self.web_xml.mime_mappings[extension] = mime_type
def ProcessBackendNode(self, node): """Processes XML nodes labeled 'backend' into a Backends object.""" tag = xml_parser_utils.GetTag(node) if tag != 'backend': self.errors.append('Unrecognized node: <%s>' % tag) return backend = Backend() name = xml_parser_utils.GetAttribute(node, 'name') if not name: self.errors.append('All backends must have names') backend.name = '-' else: backend.name = name instance_class = xml_parser_utils.GetChildNodeText(node, 'class') if instance_class: backend.instance_class = instance_class instances = xml_parser_utils.GetChildNodeText(node, 'instances') if instances: try: backend.instances = int(instances) except ValueError: self.errors.append( '<instances> must be an integer (bad value %s) in backend %s' % (instances, backend.name)) max_concurrent_requests = xml_parser_utils.GetChildNodeText( node, 'max-concurrent-requests') if max_concurrent_requests: try: backend.max_concurrent_requests = int(max_concurrent_requests) except ValueError: self.errors.append( '<max-concurrent-requests> must be an integer ' '(bad value %s) in backend %s' % (max_concurrent_requests, backend.name)) options_node = xml_parser_utils.GetChild(node, 'options') if options_node is not None: for sub_node in options_node.getchildren(): tag = xml_parser_utils.GetTag(sub_node) if tag not in ('fail-fast', 'dynamic', 'public'): self.errors.append( '<options> only supports values fail-fast, ' 'dynamic, and public (bad value %s) in backend %s' % (tag, backend.name)) continue tag = tag.replace('-', '') if xml_parser_utils.BooleanValue(sub_node.text): backend.options.add(tag) else: if tag in backend.options: backend.options.remove(tag) self.backends.append(backend)
def ProcessAutomaticScalingNode(self, node): """Sets automatic scaling settings.""" automatic_scaling = AutomaticScaling() automatic_scaling.min_pending_latency = xml_parser_utils.GetChildNodeText( node, 'min-pending-latency').strip() automatic_scaling.max_pending_latency = xml_parser_utils.GetChildNodeText( node, 'max-pending-latency').strip() automatic_scaling.min_idle_instances = xml_parser_utils.GetChildNodeText( node, 'min-idle-instances').strip() automatic_scaling.max_idle_instances = xml_parser_utils.GetChildNodeText( node, 'max-idle-instances').strip() self.app_engine_web_xml.automatic_scaling = automatic_scaling
def ProcessXml(self, xml_str): """Parses XML string and returns object representation of relevant info. Args: xml_str: The XML string. Returns: A QueueXml object containing information about task queue specifications from the XML. Raises: AppEngineConfigException: In case of malformed XML or illegal inputs. """ try: self.errors = [] xml_root = ElementTree.fromstring(xml_str) if xml_parser_utils.GetTag(xml_root) != 'queue-entries': raise AppEngineConfigException( 'Root tag must be <queue-entries>') self.queue_xml = QueueXml() self.queue_xml.queues = [] self.queue_xml.total_storage_limit = xml_parser_utils.GetChildNodeText( xml_root, 'total-storage-limit') for child in xml_parser_utils.GetNodes(xml_root, 'queue'): self.ProcessQueueNode(child) if self.errors: raise AppEngineConfigException('\n'.join(self.errors)) return self.queue_xml except ElementTree.ParseError as e: raise AppEngineConfigException('Bad input -- not valid XML: %s' % e)
def ProcessSecurityConstraintNode(self, node): """Pulls data from the security constraint node and adds to WebXml object. Args: node: An ElementTree Xml node that looks something like the following: <security-constraint> <web-resource-collection> <url-pattern>/profile/*</url-pattern> </web-resource-collection> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint> """ security_constraint = SecurityConstraint() resources_node = xml_parser_utils.GetChild(node, 'web-resource-collection') security_constraint.patterns = [ xml_parser_utils.GetNodeText(sub_node) for sub_node in xml_parser_utils.GetNodes(resources_node, 'url-pattern') ] constraint = xml_parser_utils.GetChild(node, 'auth-constraint') if constraint is not None: role_name = xml_parser_utils.GetChildNodeText( constraint, 'role-name').lower() if role_name: if role_name not in ('none', '*', 'admin'): self.errors.append( 'Bad value for <role-name> (%s), must be none, ' '*, or admin' % role_name) security_constraint.required_role = role_name user_constraint = xml_parser_utils.GetChild(node, 'user-data-constraint') if user_constraint is not None: guarantee = xml_parser_utils.GetChildNodeText( user_constraint, 'transport-guarantee').lower() if guarantee not in ('none', 'integral', 'confidential'): self.errors.append( 'Bad value for <transport-guarantee> (%s), must be' ' none, integral, or confidential' % guarantee) security_constraint.transport_guarantee = guarantee self.web_xml.security_constraints.append(security_constraint)
def ProcessQueueNode(self, node): """Processes XML <queue> nodes into Queue objects. The following information is parsed out: name mode: can be either push or pull retry-parameters: task-retry-limit ---- push queues only ---- task-age-limit min-backoff-seconds max-back-off-seconds max-doubling bucket-size max-concurrent-requests rate: how often tasks are processed on this queue. target: version of application on which tasks on this queue will be invoked. ---- pull queues only ---- acl: access control list - lists user and writer email addresses. Args: node: Current <queue> XML node being processed. """ name = xml_parser_utils.GetChildNodeText(node, 'name') if not name: self.errors.append('Must specify a name for each <queue> entry') return mode = xml_parser_utils.GetChildNodeText(node, 'mode', 'push') if mode not in ('push', 'pull'): self.errors.append(BAD_MODE_ERROR_MESSAGE % (mode, name)) return if mode == 'pull': queue = PullQueue() queue.name = name self._ProcessPullQueueNode(node, queue) else: queue = PushQueue() queue.name = name self._ProcessPushQueueNode(node, queue) self.queue_xml.queues.append(queue)
def _ProcessPushQueueNode(self, node, queue): if xml_parser_utils.GetChild(node, 'acl') is not None: self.errors.append('The element <acl> is not defined for push ' "queues; bad <queue> entry with name '%s'" % queue.name) for tag in PUSH_QUEUE_TAGS: field_name = tag.replace('-', '_') setattr(queue, field_name, xml_parser_utils.GetChildNodeText(node, tag)) self._ProcessRetryParametersNode(node, queue)
def _ProcessRetryParametersNode(node, cron): """Converts <retry-parameters> in node to cron.retry_parameters.""" retry_parameters_node = xml_parser_utils.GetChild(node, 'retry-parameters') if retry_parameters_node is None: cron.retry_parameters = None return retry_parameters = _RetryParameters() cron.retry_parameters = retry_parameters for tag in _RETRY_PARAMETER_TAGS: if xml_parser_utils.GetChild(retry_parameters_node, tag) is not None: setattr( retry_parameters, tag.replace('-', '_'), xml_parser_utils.GetChildNodeText(retry_parameters_node, tag))
def _ProcessRetryParametersNode(self, node, queue): """Pulls information out of <retry-parameters> node.""" retry_parameters_node = xml_parser_utils.GetChild( node, 'retry-parameters') if retry_parameters_node is None: queue.retry_parameters = None return retry_parameters = RetryParameters() queue.retry_parameters = retry_parameters retry_parameters.task_retry_limit = xml_parser_utils.GetChildNodeText( retry_parameters_node, 'task-retry-limit') for tag in PUSH_QUEUE_RETRY_PARAMS: if xml_parser_utils.GetChild(retry_parameters_node, tag) is not None: if isinstance(queue, PullQueue): self.errors.append(RETRY_PARAM_ERROR_MESSAGE % (tag, queue.name)) else: setattr( retry_parameters, tag.replace('-', '_'), xml_parser_utils.GetChildNodeText( retry_parameters_node, tag))
def ProcessErrorPageNode(self, node): """Process error page specifications. If one of the supplied error codes is 404, allow fall through to runtime. Args: node: An ElementTreeNode which looks something like the following. <error-page> <error-code>500</error-code> <location>/errors/servererror.jsp</location> </error-page> """ error_code = xml_parser_utils.GetChildNodeText(node, 'error-code') if error_code == '404': self.web_xml.fall_through_to_runtime = True
def ProcessManualScalingNode(self, node): manual_scaling = ManualScaling() manual_scaling.instances = xml_parser_utils.GetChildNodeText( node, 'instances').strip() self.app_engine_web_xml.manual_scaling = manual_scaling
def ProcessVpcAccessConnectorNode(self, node): """Sets vpc access connector settings.""" vpc_access_connector = VpcAccessConnector() vpc_access_connector.name = xml_parser_utils.GetChildNodeText( node, 'name').strip() self.app_engine_web_xml.vpc_access_connector = vpc_access_connector