thirdparty/google_appengine/google/appengine/tools/appcfg.py
changeset 2309 be1b94099f2d
parent 2273 e4cb9c53db3e
child 2413 d0b7dac5325c
equal deleted inserted replaced
2307:81c128f487e6 2309:be1b94099f2d
   672 
   672 
   673 class LogsRequester(object):
   673 class LogsRequester(object):
   674   """Provide facilities to export request logs."""
   674   """Provide facilities to export request logs."""
   675 
   675 
   676   def __init__(self, server, config, output_file,
   676   def __init__(self, server, config, output_file,
   677                num_days, append, severity, now):
   677                num_days, append, severity, now, vhost):
   678     """Constructor.
   678     """Constructor.
   679 
   679 
   680     Args:
   680     Args:
   681       server: The RPC server to use.  Should be an instance of HttpRpcServer
   681       server: The RPC server to use.  Should be an instance of HttpRpcServer
   682         or TestRpcServer.
   682         or TestRpcServer.
   684       output_file: Output file name.
   684       output_file: Output file name.
   685       num_days: Number of days worth of logs to export; 0 for all available.
   685       num_days: Number of days worth of logs to export; 0 for all available.
   686       append: True if appending to an existing file.
   686       append: True if appending to an existing file.
   687       severity: App log severity to request (0-4); None for no app logs.
   687       severity: App log severity to request (0-4); None for no app logs.
   688       now: POSIX timestamp used for calculating valid dates for num_days.
   688       now: POSIX timestamp used for calculating valid dates for num_days.
       
   689       vhost: The virtual host of log messages to get. None for all hosts.
   689     """
   690     """
   690     self.server = server
   691     self.server = server
   691     self.config = config
   692     self.config = config
   692     self.output_file = output_file
   693     self.output_file = output_file
   693     self.append = append
   694     self.append = append
   694     self.num_days = num_days
   695     self.num_days = num_days
   695     self.severity = severity
   696     self.severity = severity
       
   697     self.vhost = vhost
   696     self.version_id = self.config.version + ".1"
   698     self.version_id = self.config.version + ".1"
   697     self.sentinel = None
   699     self.sentinel = None
   698     self.write_mode = "w"
   700     self.write_mode = "w"
   699     if self.append:
   701     if self.append:
   700       self.sentinel = FindSentinel(self.output_file)
   702       self.sentinel = FindSentinel(self.output_file)
   768            }
   770            }
   769     if offset:
   771     if offset:
   770       kwds["offset"] = offset
   772       kwds["offset"] = offset
   771     if self.severity is not None:
   773     if self.severity is not None:
   772       kwds["severity"] = str(self.severity)
   774       kwds["severity"] = str(self.severity)
       
   775     if self.vhost is not None:
       
   776       kwds["vhost"] = str(self.vhost)
   773     response = self.server.Send("/api/request_logs", payload=None, **kwds)
   777     response = self.server.Send("/api/request_logs", payload=None, **kwds)
   774     response = response.replace("\r", "\0")
   778     response = response.replace("\r", "\0")
   775     lines = response.splitlines()
   779     lines = response.splitlines()
   776     logging.info("Received %d bytes, %d records.", len(response), len(lines))
   780     logging.info("Received %d bytes, %d records.", len(response), len(lines))
   777     offset = None
   781     offset = None
  1787     rpc_server = self._GetRpcServer()
  1791     rpc_server = self._GetRpcServer()
  1788     logs_requester = LogsRequester(rpc_server, appyaml, self.args[1],
  1792     logs_requester = LogsRequester(rpc_server, appyaml, self.args[1],
  1789                                    self.options.num_days,
  1793                                    self.options.num_days,
  1790                                    self.options.append,
  1794                                    self.options.append,
  1791                                    self.options.severity,
  1795                                    self.options.severity,
  1792                                    time.time())
  1796                                    time.time(),
       
  1797                                    self.options.vhost)
  1793     logs_requester.DownloadLogs()
  1798     logs_requester.DownloadLogs()
  1794 
  1799 
  1795   def _RequestLogsOptions(self, parser):
  1800   def _RequestLogsOptions(self, parser):
  1796     """Adds request_logs-specific options to 'parser'.
  1801     """Adds request_logs-specific options to 'parser'.
  1797 
  1802 
  1811     parser.add_option("--severity", type="int", dest="severity",
  1816     parser.add_option("--severity", type="int", dest="severity",
  1812                       action="store", default=None,
  1817                       action="store", default=None,
  1813                       help="Severity of app-level log messages to get. "
  1818                       help="Severity of app-level log messages to get. "
  1814                       "The range is 0 (DEBUG) through 4 (CRITICAL). "
  1819                       "The range is 0 (DEBUG) through 4 (CRITICAL). "
  1815                       "If omitted, only request logs are returned.")
  1820                       "If omitted, only request logs are returned.")
       
  1821     parser.add_option("--vhost", type="string", dest="vhost",
       
  1822                       action="store", default=None,
       
  1823                       help="The virtual host of log messages to get. "
       
  1824                       "If omitted, all log messages are returned.")
  1816 
  1825 
  1817   def CronInfo(self, now=None, output=sys.stdout):
  1826   def CronInfo(self, now=None, output=sys.stdout):
  1818     """Displays information about cron definitions.
  1827     """Displays information about cron definitions.
  1819 
  1828 
  1820     Args:
  1829     Args:
  1832       for entry in cron_entries.cron:
  1841       for entry in cron_entries.cron:
  1833         description = entry.description
  1842         description = entry.description
  1834         if not description:
  1843         if not description:
  1835           description = "<no description>"
  1844           description = "<no description>"
  1836         print >>output, "\n%s:\nURL: %s\nSchedule: %s" % (description,
  1845         print >>output, "\n%s:\nURL: %s\nSchedule: %s" % (description,
  1837                                                           entry.schedule,
  1846                                                           entry.url,
  1838                                                           entry.url)
  1847                                                           entry.schedule)
  1839         schedule = groctimespecification.GrocTimeSpecification(entry.schedule)
  1848         schedule = groctimespecification.GrocTimeSpecification(entry.schedule)
  1840         matches = schedule.GetMatches(now, self.options.num_runs)
  1849         matches = schedule.GetMatches(now, self.options.num_runs)
  1841         for match in matches:
  1850         for match in matches:
  1842           print >>output, "%s, %s from now" % (
  1851           print >>output, "%s, %s from now" % (
  1843               match.strftime("%Y-%m-%d %H:%M:%S"), match - now)
  1852               match.strftime("%Y-%m-%d %H:%M:%S"), match - now)
  1851     parser.add_option("-n", "--num_runs", type="int", dest="num_runs",
  1860     parser.add_option("-n", "--num_runs", type="int", dest="num_runs",
  1852                       action="store", default=5,
  1861                       action="store", default=5,
  1853                       help="Number of runs of each cron job to display"
  1862                       help="Number of runs of each cron job to display"
  1854                       "Default is 5")
  1863                       "Default is 5")
  1855 
  1864 
  1856   def _CheckRequiredUploadOptions(self):
  1865   def _CheckRequiredLoadOptions(self):
  1857     """Checks that upload options are present."""
  1866     """Checks that upload/download options are present."""
  1858     for option in ["filename", "kind", "config_file"]:
  1867     for option in ["filename", "kind", "config_file"]:
  1859       if getattr(self.options, option) is None:
  1868       if getattr(self.options, option) is None:
  1860         self.parser.error("Option '%s' is required." % option)
  1869         self.parser.error("Option '%s' is required." % option)
  1861     if not self.options.url:
  1870     if not self.options.url:
  1862       self.parser.error("You must have google.appengine.ext.remote_api.handler "
  1871       self.parser.error("You must have google.appengine.ext.remote_api.handler "
  1863                         "assigned to an endpoint in app.yaml, or provide "
  1872                         "assigned to an endpoint in app.yaml, or provide "
  1864                         "the url of the handler via the 'url' option.")
  1873                         "the url of the handler via the 'url' option.")
  1865 
  1874 
  1866   def InferUploadUrl(self, appyaml):
  1875   def InferRemoteApiUrl(self, appyaml):
  1867     """Uses app.yaml to determine the remote_api endpoint.
  1876     """Uses app.yaml to determine the remote_api endpoint.
  1868 
  1877 
  1869     Args:
  1878     Args:
  1870       appyaml: A parsed app.yaml file.
  1879       appyaml: A parsed app.yaml file.
  1871 
  1880 
  1883             return "http://%s.appspot.com%s" % (app_id, handler.url)
  1892             return "http://%s.appspot.com%s" % (app_id, handler.url)
  1884           else:
  1893           else:
  1885             return "http://%s%s" % (server, handler.url)
  1894             return "http://%s%s" % (server, handler.url)
  1886     return None
  1895     return None
  1887 
  1896 
  1888   def RunBulkloader(self, **kwargs):
  1897   def RunBulkloader(self, arg_dict):
  1889     """Invokes the bulkloader with the given keyword arguments.
  1898     """Invokes the bulkloader with the given keyword arguments.
  1890 
  1899 
  1891     Args:
  1900     Args:
  1892       kwargs: Keyword arguments to pass to bulkloader.Run().
  1901       arg_dict: Dictionary of arguments to pass to bulkloader.Run().
  1893     """
  1902     """
  1894     try:
  1903     try:
  1895       import sqlite3
  1904       import sqlite3
  1896     except ImportError:
  1905     except ImportError:
  1897       logging.error("upload_data action requires SQLite3 and the python "
  1906       logging.error("upload_data action requires SQLite3 and the python "
  1898                     "sqlite3 module (included in python since 2.5).")
  1907                     "sqlite3 module (included in python since 2.5).")
  1899       sys.exit(1)
  1908       sys.exit(1)
  1900 
  1909 
  1901     sys.exit(bulkloader.Run(kwargs))
  1910     sys.exit(bulkloader.Run(arg_dict))
  1902 
  1911 
  1903   def PerformUpload(self, run_fn=None):
  1912   def _SetupLoad(self):
  1904     """Performs a datastore upload via the bulkloader.
  1913     """Performs common verification and set up for upload and download."""
  1905 
       
  1906     Args:
       
  1907       run_fn: Function to invoke the bulkloader, used for testing.
       
  1908     """
       
  1909     if run_fn is None:
       
  1910       run_fn = self.RunBulkloader
       
  1911 
       
  1912     if len(self.args) != 1:
  1914     if len(self.args) != 1:
  1913       self.parser.error("Expected <directory> argument.")
  1915       self.parser.error("Expected <directory> argument.")
  1914 
  1916 
  1915     basepath = self.args[0]
  1917     basepath = self.args[0]
  1916     appyaml = self._ParseAppYaml(basepath)
  1918     appyaml = self._ParseAppYaml(basepath)
  1917 
  1919 
  1918     self.options.app_id = appyaml.application
  1920     self.options.app_id = appyaml.application
  1919 
  1921 
  1920     if not self.options.url:
  1922     if not self.options.url:
  1921       url = self.InferUploadUrl(appyaml)
  1923       url = self.InferRemoteApiUrl(appyaml)
  1922       if url is not None:
  1924       if url is not None:
  1923         self.options.url = url
  1925         self.options.url = url
  1924 
  1926 
  1925     self._CheckRequiredUploadOptions()
  1927     self._CheckRequiredLoadOptions()
  1926 
  1928 
  1927     if self.options.batch_size < 1:
  1929     if self.options.batch_size < 1:
  1928       self.parser.error("batch_size must be 1 or larger.")
  1930       self.parser.error("batch_size must be 1 or larger.")
  1929 
  1931 
  1930     if verbosity == 1:
  1932     if verbosity == 1:
  1932       self.options.debug = False
  1934       self.options.debug = False
  1933     else:
  1935     else:
  1934       logging.getLogger().setLevel(logging.DEBUG)
  1936       logging.getLogger().setLevel(logging.DEBUG)
  1935       self.options.debug = True
  1937       self.options.debug = True
  1936 
  1938 
       
  1939   def _MakeLoaderArgs(self):
       
  1940     return dict([(arg_name, getattr(self.options, arg_name, None)) for
       
  1941                  arg_name in (
       
  1942         "app_id",
       
  1943         "url",
       
  1944         "filename",
       
  1945         "batch_size",
       
  1946         "kind",
       
  1947         "num_threads",
       
  1948         "bandwidth_limit",
       
  1949         "rps_limit",
       
  1950         "http_limit",
       
  1951         "db_filename",
       
  1952         "config_file",
       
  1953         "auth_domain",
       
  1954         "has_header",
       
  1955         "loader_opts",
       
  1956         "log_file",
       
  1957         "passin",
       
  1958         "email",
       
  1959         "debug",
       
  1960         "exporter_opts",
       
  1961         "result_db_filename",
       
  1962         )])
       
  1963 
       
  1964   def PerformDownload(self, run_fn=None):
       
  1965     """Performs a datastore download via the bulkloader.
       
  1966 
       
  1967     Args:
       
  1968       run_fn: Function to invoke the bulkloader, used for testing.
       
  1969     """
       
  1970     if run_fn is None:
       
  1971       run_fn = self.RunBulkloader
       
  1972     self._SetupLoad()
       
  1973 
       
  1974     StatusUpdate("Downloading data records.")
       
  1975 
       
  1976     args = self._MakeLoaderArgs()
       
  1977     args['download'] = True
       
  1978     args['has_header'] = False
       
  1979 
       
  1980     run_fn(args)
       
  1981 
       
  1982   def PerformUpload(self, run_fn=None):
       
  1983     """Performs a datastore upload via the bulkloader.
       
  1984 
       
  1985     Args:
       
  1986       run_fn: Function to invoke the bulkloader, used for testing.
       
  1987     """
       
  1988     if run_fn is None:
       
  1989       run_fn = self.RunBulkloader
       
  1990     self._SetupLoad()
       
  1991 
  1937     StatusUpdate("Uploading data records.")
  1992     StatusUpdate("Uploading data records.")
  1938 
  1993 
  1939     run_fn(app_id=self.options.app_id,
  1994     args = self._MakeLoaderArgs()
  1940            url=self.options.url,
  1995     args['download'] = False
  1941            filename=self.options.filename,
  1996 
  1942            batch_size=self.options.batch_size,
  1997     run_fn(args)
  1943            kind=self.options.kind,
  1998 
  1944            num_threads=self.options.num_threads,
  1999   def _PerformLoadOptions(self, parser):
  1945            bandwidth_limit=self.options.bandwidth_limit,
  2000     """Adds options common to 'upload_data' and 'download_data'.
  1946            rps_limit=self.options.rps_limit,
       
  1947            http_limit=self.options.http_limit,
       
  1948            db_filename=self.options.db_filename,
       
  1949            config_file=self.options.config_file,
       
  1950            auth_domain=self.options.auth_domain,
       
  1951            has_header=self.options.has_header,
       
  1952            loader_opts=self.options.loader_opts,
       
  1953            log_file=self.options.log_file,
       
  1954            passin=self.options.passin,
       
  1955            email=self.options.email,
       
  1956            debug=self.options.debug,
       
  1957 
       
  1958            exporter_opts=None,
       
  1959            download=False,
       
  1960            result_db_filename=None,
       
  1961            )
       
  1962 
       
  1963   def _PerformUploadOptions(self, parser):
       
  1964     """Adds 'upload_data' specific options to the 'parser' passed in.
       
  1965 
  2001 
  1966     Args:
  2002     Args:
  1967       parser: An instance of OptionsParser.
  2003       parser: An instance of OptionsParser.
  1968     """
  2004     """
  1969     parser.add_option("--filename", type="string", dest="filename",
  2005     parser.add_option("--filename", type="string", dest="filename",
  1998                       action="store",
  2034                       action="store",
  1999                       help="Name of the progress database file.")
  2035                       help="Name of the progress database file.")
  2000     parser.add_option("--auth_domain", type="string", dest="auth_domain",
  2036     parser.add_option("--auth_domain", type="string", dest="auth_domain",
  2001                       action="store", default="gmail.com",
  2037                       action="store", default="gmail.com",
  2002                       help="The name of the authorization domain to use.")
  2038                       help="The name of the authorization domain to use.")
       
  2039     parser.add_option("--log_file", type="string", dest="log_file",
       
  2040                       help="File to write bulkloader logs.  If not supplied "
       
  2041                            "then a new log file will be created, named: "
       
  2042                            "bulkloader-log-TIMESTAMP.")
       
  2043 
       
  2044   def _PerformUploadOptions(self, parser):
       
  2045     """Adds 'upload_data' specific options to the 'parser' passed in.
       
  2046 
       
  2047     Args:
       
  2048       parser: An instance of OptionsParser.
       
  2049     """
       
  2050     self._PerformLoadOptions(parser)
  2003     parser.add_option("--has_header", dest="has_header",
  2051     parser.add_option("--has_header", dest="has_header",
  2004                       action="store_true", default=False,
  2052                       action="store_true", default=False,
  2005                       help="Whether the first line of the input file should be"
  2053                       help="Whether the first line of the input file should be"
  2006                       " skipped")
  2054                       " skipped")
  2007     parser.add_option("--loader_opts", type="string", dest="loader_opts",
  2055     parser.add_option("--loader_opts", type="string", dest="loader_opts",
  2008                       help="A string to pass to the Loader.Initialize method.")
  2056                       help="A string to pass to the Loader.initialize method.")
  2009     parser.add_option("--log_file", type="string", dest="log_file",
  2057 
  2010                       help="File to write bulkloader logs.  If not supplied "
  2058   def _PerformDownloadOptions(self, parser):
  2011                            "then a new log file will be created, named: "
  2059     """Adds 'download_data' specific options to the 'parser' passed in.
  2012                            "bulkloader-log-TIMESTAMP.")
  2060 
       
  2061     Args:
       
  2062       parser: An instance of OptionsParser.
       
  2063     """
       
  2064     self._PerformLoadOptions(parser)
       
  2065     parser.add_option("--exporter_opts", type="string", dest="exporter_opts",
       
  2066                       help="A string to pass to the Exporter.initialize method."
       
  2067                       )
       
  2068     parser.add_option("--result_db_filename", type="string",
       
  2069                       dest="result_db_filename",
       
  2070                       action="store",
       
  2071                       help="Database to write entities to for download.")
  2013 
  2072 
  2014   class Action(object):
  2073   class Action(object):
  2015     """Contains information about a command line action.
  2074     """Contains information about a command line action.
  2016 
  2075 
  2017     Attributes:
  2076     Attributes:
  2119 
  2178 
  2120       "upload_data": Action(
  2179       "upload_data": Action(
  2121           function="PerformUpload",
  2180           function="PerformUpload",
  2122           usage="%prog [options] upload_data <directory>",
  2181           usage="%prog [options] upload_data <directory>",
  2123           options=_PerformUploadOptions,
  2182           options=_PerformUploadOptions,
  2124           short_desc="Upload CSV records to datastore",
  2183           short_desc="Upload data records to datastore.",
  2125           long_desc="""
  2184           long_desc="""
  2126 The 'upload_data' command translates CSV records into datastore entities and
  2185 The 'upload_data' command translates input records into datastore entities and
  2127 uploads them into your application's datastore."""),
  2186 uploads them into your application's datastore."""),
       
  2187 
       
  2188       "download_data": Action(
       
  2189           function="PerformDownload",
       
  2190           usage="%prog [options] download_data <directory>",
       
  2191           options=_PerformDownloadOptions,
       
  2192           short_desc="Download entities from datastore.",
       
  2193           long_desc="""
       
  2194 The 'download_data' command downloads datastore entities and writes them to
       
  2195 file as CSV or developer defined format."""),
  2128 
  2196 
  2129 
  2197 
  2130 
  2198 
  2131   }
  2199   }
  2132 
  2200