blob: b97947b3f76e22a5f63de4b396b8547608619e4f [file] [log] [blame]
TODO(devlin): MD docs seem to be the new hotness; this should probably be
converted.
--------
Overview
This is a Google App Engine server which serves the documentation for Chrome
apps and extensions. At time of this writing, the primary URL is:
http://developer.chrome.com/.
---------------------
Developing the Server
You shouldn't need app engine locally to develop the server, preview.py should
be sufficient. If for some reason you want to test against the app engine SDK:
1. Download the python Google App Engine SDK from:
https://developers.google.com/appengine/downloads
2. Run './start_dev_server.py <path/to/dev_appserver.py>'
(dev_appserver.py is part of the App Engine)
3. View docs at http://localhost:8080/(apps|extensions)/<doc_name>
NOTE: The dev server will not work right way: you need to populate its
Datastore. You will need a local datastore cache in the working directory where
you started the dev server, and you will need to manually instruct the dev
server to pull data from that file:
1. Run './update_cache.py --no-push --save-file=FOOCACHE'. This will take
a very long time (30-40 minutes). It is advisable that you keep a copy
of this file around if you plan use the dev server often. It can be
updated much faster (< 3 minutes) in that case by also including
--load-file=FOOCACHE on subsequent update_cache.py runs.
You MUST have branch heads fetched in your local repo in order for your
local data set to be populated correctly. You can accomplish this by
running:
gclient sync --with_branch_heads
git fetch origin
You may also specify --commit=<commitish> when running update_cache.py in
order to update the cache from a specific commit. This may be a commit ID,
or a partial commit ID, or a local branch ref, etc. To test local changes,
you MUST commit them locally and use the local commit to update your cache.
2. Once you have a cache (e.g. FOOCACHE) in the working directory of your
dev server, visit the URL:
http://localhost:8080/_update_cache/FOOCACHE
If you see errors about the FOOCACHE file not existing, the server may be
looking for the file in the root chromium directory (under src/), even if
you launched the server from the server2 directory. Try moving the FOOCACHE
file there.
The server should take about a minute to fully populate its Datastore
from the data in your FOOCACHE file. Now you have a working dev server!
------------------------------------------------------------
Using Google Cloud Storage content providers with preview.py
1. create a directory "[...]/server2/local_debug/gcs/<bucketname>" for every
gcs bucket referenced in content_providers.json
2. copy files to the respective local bucket directories. Preview.py has
no access to the real Google Cloud Storage.
--------------------
Deploying the Server
You will need to have access to the http://chrome-apps-doc.appspot.com app.
Contact rdevlin.cronin@chromium.org or another extensions team member to obtain
access.
Once you have access:
1. Increment the version in app.yaml so we can roll back if the update breaks.
2. Land your patch in chromium. Resync/pull.
3. Run build_server.py. This copies some depenencies from /third_party into the
server directory so that they get uploaded to App Engine.
4. Run appcfg.py (supplied with the App Engine SDK) to upload the server code:
appcfg.py update .
5. When prompted for your credentials, enter the information for the account
that has access to the production app.
Note: Steps 1 - 5 can be completed (mostly) synchronously. However, once the
version is pushed, the docserver will need to repopulate its cache, which runs
from a cron job. (Theoretically, this job runs a few times a day - in practice,
it has been observered to be late.)
6. Go to http://www.appspot.com, select the docs project, click "versions" in
the sidebar. CHECK THE VERSION YOU DEPLOYED WORKS. You can do this by
clicking the version with the "popout" link, which should send you to a link
like "https://3-50-3-dot-chrome-apps-doc.appspot.com". This should work, and
you should be able to see documentation by going to /extensions,
/extensions/webRequest, /extensions/contentScripts, etc. If you see a
"Not found" error, this means the version does not work. Likely, this is
because the cache hasn't been fully updated.
If the newly-deployed version works, migrate traffic to the new version. This
happens nearly instantly, so you should immediately double-check the live
site at developer.chrome.com/extensions.
If you get an error about too many versions when deploying, go into this
view and delete the version which was deployed the longest time ago. Then
try to deploy again.
----------------------
Updating the Datastore
Even when the server code hasn't changed, new data is constantly flowing into
the chromium repo and some of that data includes changes to new or existing
content hosted by the server. In order for the front-end to reflect these
changes, new data must be pushed into the project's Datastore.
This is done periodically by a Compute Engine instance running the
update_cache.py tool. While it is possible to push from other hosts if you
get all the right credentials in all the right places, it is strongly
discouraged and also therefore not documented.
To force a push safely from the VM, navigate to the developer console under
Compute -> Compute Engine -> VM instances and open SSH for the "git-processor"
instance. From within the SSH session, first switch to user "git-processor":
sudo su - git-processor
You can run './update-docs.sh' from the home directory there. This will
automatically fetch any new objects from the upstream repository and then
perform a full update if there are pending changes.
It's almost never necessary to use this tool. For one interesting example,
consider the case where no new commits are landing in the chrome repository
but a change was just pushed to one of the GCS providers (like say, the
chromedocs-multidevice bucker). In this case, you may want to force an update
of only the content_providers data.
./update_docs.sh --data-source=content_providers --force
This will safely do the push for you, ensuring that the automated job
does not collide with your own.
----------------------
Server architecture
The server is composed of two parts:
1) A compute engine VM instance which runs a cron job to periodicially pull the
chromium repo and uses the update_cache.py script to push the new data to the
cloud datastore and clear the existing memcache for the App engine instance
to ensure stale data is not served. All the keys in the cloud datastore are
indexed by the app version specified in app.yaml.
2) A python app engine app which reads the data in the cloud datastore and
serves the website.
Hence, even if we were to stop the compute engine VM instance, the website
should still keep running. But it won't update, since the cloud datastore won't
get updated.
-----------------------------------------------
Updating Docs served from Google Cloud Storage.
Some docs (e.g. webstore docs) are served using Google Cloud Storage buckets. To
update files in these docs, follow these steps:
1) Go the project homepage and then to the Storage section.
2) Go to the relevant storage bucket. For example, to update webstore docs, go
to the page for "chromedocs-webstore".
3) Modify an existing file or upload a new file. Edit file permissions if
necessary to ensure these are accessible to Public. (Ideally these should be
only accessible to the cron job running on the compute engine VM instance.)
4) After the next cron job on the compute engine completes, the modifications
should be live.
5) In order to expedite 4), a manual datastore update can be performed by
running "./update_docs.sh --data-source=content_providers --force" on the VM
instance.
Note: these steps shouldn't require a server version bump. If they do, please
file a bug.
---------------------------------------
VM: Some notes and troubleshooting tips
Q1: How is the datastore populated in the VM?
A: /home/git-processor/update-docs-full.sh
This script is run every 2 hours through cron to sync the chromium git repo
in this machine. Once it has done so, it will populate docserver data store
and write that in /home/git-processor/.docserver_cache. Docserver uses this
file as data sources to populate its documentation.
Q2: Is chromium repo in the VM in sync?
A: Check the git logs on the repo.
$ sudo su git-processor
$ cd ~/chrome/src
$ git log
Verify that chromium checkout is up-to-date by looking at the latest git log
results.
Q3: Did the last run to populate .docserver_cache succeed?
A: Check the logs.
Logs can be checked from the Cloud dashboard. Go to the project homepage and
select Logging > Logs. Choose the VM instance and "syslog" from the filter
options.
Alternatively, run
$ sudo -s # You need to be root.
$ vi /var/log/user.log
Jan 19 21:51:39 git-processor logger: Acquiring docserver update lock...
Jan 19 21:51:39 git-processor logger: INFO:root:Starting refresh from commit 1ee51d53b10f8d2688a225d6cbd33dfdf8965403...
...
Specifically you want to see some logs about writing keys to the
cache file, e.g.:
Jan 19 21:33:21 git-processor logger: INFO:root:Saved 644 keys to /home/git-processor/.docserver_cache.
Q4: Docs stopped updating for a while, what to do?
A: Start by checking whether the appengine instance contains datastore *close*
to HEAD. You can do this by visiting
https://developer.chrome.com/_query_commit/master
Then check the commit hash. If the commit hash is behind by more than few
days from HEAD then this means that last run(s) to populate .docserver_cache
failed in the VM. An example of this happening can be found in:
https://crbug.com/682376.
Start checking the logs (Q3). If you see that there are no logs after
"Acquiring docserver update lock..", then the script might have hung. The
script uses /var/lock/docserver-update.lock lock file with flock. The
process/script probably is still running (I don't know why that happens
yet). You'd need to verify that this is the case.
For example, I ran:
$ ps -e -o lstart,pid,ppid,cmd | grep update-docs
Sat Oct 1 15:00:00 2016 10230 10229 /bin/sh -c /usr/bin/env bash /home/git-processor/update-docs-full.sh 2>&1 | /usr/bin>
Sat Oct 1 15:00:00 2016 10231 10230 bash /home/git-processor/update-docs-full.sh
Wed Dec 14 19:50:01 2016 10744 10743 /bin/sh -c /usr/bin/env bash /home/git-processor/update-docs-full.sh 2>&1 | /usr/bin>
Wed Dec 14 19:50:01 2016 10745 10744 bash /home/git-processor/update-docs-full.sh
Once you're sure that one or more of these processes are running for a
while, you'd want to kill them, which should be "safe" (endorsed by rockot@)
in most of the cases. If that doesn't work, then delete the lock file. This
will let subsequent cron runs to update docserver.
Also ensure that the App engine's current version is in sync with the
version specified in app.yaml on ToT.
Some other miscellaneous debugging tips:
- Viewing updates made by last cron job
To view the contents of the data persisted by the last cron job, inspect
the .docserver_cache file on the Compute Engine instance. See
/home/git-processor/tools/dump_keys.py for an example of how to do so.
- Viewing actual datastore entries
Go to the project homepage and then move to the "Datastore" section. From
the dropdowns, choose "Namespace" = [default], "Kind"=
"PersistentObjectStoreItem" and click on "Filter Entities" and then enter
the key to inspect. Example search:
Key(PersistentObjectStoreItem, 'class=APIListDataSource&category=LocalGitFileSystem@master&app_version=3-65-0/api_data')
The data here should be the same as the one in .docserver_cache.
- Debugging live App Engine instance
Go the Project homepage, and head over to the "Debug" section. Using
Stackdriver debugging, it's possible to take live snapshots and inspect
the state of the live App Engine instance. E.g. it allows you to inspect
variables, see the stack trace etc. by setting a "logpoint".
Q5: How to migrate to a new VM instance? (Say to update the operating system).
ROUGH steps:
1) Stop the old VM.
2) Backup the cloud datastore to a cloud storage bucket (optional).
3) Clone the persistent disk (not the boot disk) from the old VM. Else just
create a new disk and copy necessary data (in /home/git-processor) later.
4) Create a new VM instance (Use configuration from the old VM) and attach
the new persistent disk to the new VM. Make sure that new VM has the same
API access scopes as the old one (for e.g. it can write to the cloud
datastore).
5) Mount the persistent disk at /home/git-processor (Modify /etc/fstab so
that the disk is automatically mounted on restarts).
6) Ensure the data in /home/git-processor is the same as the old VM (if you
had not cloned the disk, use some other tool to copy the data).
7) Increment the app engine version in the chromium repo and commit the
change (so that we don't somehow affect the currently serving production
version).
8) On the VM, fetch chrome in /home/git-processor with all the branch heads.
9) Ensure app.yaml in the chrome repo has the new app version.
10) Install any necessary dependencies. For e.g. /home/git-processor/gcd is
a python virtual environment used by update-docs-full.sh (which is run
as part of the cron job). Hence pip, virtualenv need to be installed and
it needs to be ensured that the virtualenv at /home/git-processor/gcd is
correctly configured. Requirements file generated by pip can be used for
this purpose.
11) Run update-docs-full.sh and ensure it works fine. (After it runs, the
new app engine version should work fine and have the latest changes).
12) If it does, add a cronjob for the git-processor user to regularly run
update-docs-full.sh.
13) Ensure the cron job is running fine and serve all the traffic from the
new app engine version.
14) Delete the old VM, persistent disk after some time.
15) (Optional) Install logging agent on the VM so that the syslog from the
VM can be seen from the cloud dashboard.