├── nginx ├── ok ├── .gitignore ├── Dockerfile ├── app.yaml ├── install.sh └── nginx.conf.template ├── .gitignore ├── CHANGELOG.md ├── .gitmodules ├── ssh ├── vm ├── configure_pygments.sh ├── sites │ └── phabricator.conf ├── configure_php.sh ├── configure_mailgun.sh ├── configure_submodules.sh ├── configure_users.sh ├── configure_notifications.sh ├── configure_phabricator.sh ├── configure_gcloud.sh ├── configure_hosted_repos.sh ├── configure_apache.sh ├── upgrade.sh ├── configure_ssh.sh ├── configure_sendgrid.sh ├── startup.sh ├── configure_sql.sh └── install.sh ├── sync_to_latest ├── upgrade ├── phabricator.sh.template ├── CONTRIBUTING.md ├── README.md ├── lib └── init.sh ├── LICENSE └── install /nginx/ok: -------------------------------------------------------------------------------- 1 | ok 2 | -------------------------------------------------------------------------------- /nginx/.gitignore: -------------------------------------------------------------------------------- 1 | nginx.conf 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /config 2 | /transaction.yaml 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.0 2 | 3 | * Initial release. 4 | -------------------------------------------------------------------------------- /nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:latest 2 | COPY nginx.conf /etc/nginx/nginx.conf 3 | COPY ok /usr/share/nginx/www/_ah/start 4 | COPY ok /usr/share/nginx/www/_ah/health 5 | RUN chmod -R a+rx /usr/share/nginx/www -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vm/third_party/phabricator"] 2 | path = vm/third_party/phabricator 3 | url = https://github.com/phacility/phabricator.git 4 | [submodule "vm/third_party/arcanist"] 5 | path = vm/third_party/arcanist 6 | url = https://github.com/phacility/arcanist.git 7 | [submodule "vm/third_party/libphutil"] 8 | path = vm/third_party/libphutil 9 | url = https://github.com/phacility/libphutil.git 10 | -------------------------------------------------------------------------------- /nginx/app.yaml: -------------------------------------------------------------------------------- 1 | runtime: custom 2 | vm: true 3 | api_version: 1 4 | threadsafe: yes 5 | 6 | automatic_scaling: 7 | min_num_instances: 2 8 | 9 | builtins: 10 | - appstats: on 11 | 12 | network: 13 | name: phabricator 14 | 15 | handlers: 16 | - url: /favicon.ico 17 | static_files: favicon.ico 18 | upload: favicon.ico 19 | 20 | - url: /api/.* 21 | script: dynamic 22 | 23 | - url: /res/.* 24 | script: dynamic 25 | 26 | - url: /file/data/.* 27 | script: dynamic 28 | 29 | - url: /ws/.* 30 | script: dynamic 31 | 32 | - url: /auth/register/ 33 | script: dynamic 34 | 35 | - url: /.* 36 | script: dynamic 37 | -------------------------------------------------------------------------------- /nginx/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | . ../lib/init.sh 18 | 19 | gcloud_appengine deploy --version=1 --promote app.yaml 20 | -------------------------------------------------------------------------------- /ssh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | . lib/init.sh 18 | 19 | open_ssh 20 | gcloud --project=${PROJECT} compute ssh $VM_NAME --zone=$ZONE --ssh-flag="-p $PORT" 21 | -------------------------------------------------------------------------------- /vm/configure_pygments.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -e 18 | 19 | # Install pip 20 | sudo apt-get install -y python-pip 21 | 22 | # Install pygments 23 | sudo pip install Pygments 24 | -------------------------------------------------------------------------------- /sync_to_latest: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | . lib/init.sh 18 | 19 | # Terminate execution on command failure 20 | set -e 21 | 22 | git submodule foreach "git fetch;git checkout origin/stable" 23 | -------------------------------------------------------------------------------- /vm/sites/phabricator.conf: -------------------------------------------------------------------------------- 1 | 2 | DocumentRoot /opt/phabricator/webroot 3 | SetEnvIf Request_URI "^/_ah/stop" shutdown 4 | CustomLog /usr/local/apache/logs/shutdown.log common env=shutdown 5 | CustomLog /var/log/phabricator/access.log combined 6 | ErrorLog /var/log/phabricator/apache_phabricator_err.log 7 | 8 | RewriteEngine on 9 | RewriteRule ^/_ah/health - [L,QSA] 10 | RewriteRule ^/_ah/stop - [L,QSA] 11 | RewriteRule ^/rsrc/(.*) - [L,QSA] 12 | RewriteRule ^/favicon.ico - [L,QSA] 13 | RewriteRule ^(.*)$ /index.php?__path__=$1 [B,L,QSA] 14 | 15 | # Tell Apache to allow user access to documents under 16 | # Phabricator's webroot directory. 17 | 18 | Require all granted 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /upgrade: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | . lib/init.sh 18 | 19 | # Terminate execution on command failure 20 | set -e 21 | 22 | echo "About to connect via ssh to upgrade your cluster. Press enter to continue." 23 | read 24 | 25 | open_ssh 26 | 27 | remote_exec "if [ ! -d phabricator ]; then git clone $GITHUB_REPO; else cd phabricator; git fetch; git rebase origin/master; fi" || exit 1 28 | remote_exec "cd /opt;bash ~/phabricator/vm/upgrade.sh" || exit 1 29 | -------------------------------------------------------------------------------- /vm/configure_php.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -e 18 | 19 | function disable_php { 20 | if [ $(grep -c "^$1" /etc/php5/apache2/php.ini) = 0 ]; then 21 | echo "Disabling $1..." 22 | echo "$1 = 0" | sudo tee --append /etc/php5/apache2/php.ini 23 | fi 24 | } 25 | 26 | disable_php apc.stat 27 | disable_php apc.slam_defense 28 | disable_php opcache.validate_timestamps 29 | 30 | if [ $(grep -c "^post_max_size = 8M$" /etc/php5/apache2/php.ini) -ne 0 ]; then 31 | echo "Increasing post max size to 32M."; 32 | sudo sed -i -e "s/post_max_size = 8M/post_max_size = 32M/" /etc/php5/apache2/php.ini 33 | fi 34 | 35 | -------------------------------------------------------------------------------- /phabricator.sh.template: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | ZONE= # Must provide a zone. Run `gcloud compute zones list` for a list. 18 | 19 | # Recommended. Provide if you are using Mailgun to send mail. 20 | MAILGUN_APIKEY= 21 | MAILGUN_SMTP_DOMAIN_KEY_TXT= 22 | 23 | # Recommended. Provide if you intend to serve phabricator behind a custom domain. 24 | CUSTOM_DOMAIN= 25 | CUSTOM_DOMAIN_A_RECORD= 26 | CUSTOM_DOMAIN_AAAA_RECORD= 27 | 28 | # Only applies when CUSTOM_DOMAIN is provided. 29 | NOTIFICATIONS_SUBDOMAIN=n 30 | GIT_SUBDOMAIN=git 31 | 32 | # Only modify these if installing phabricator into an existing cluster. 33 | NETWORK_NAME=phabricator 34 | DNS_NAME=phabricator 35 | SQL_NAME=phabricator 36 | ADDRESS_NAME=phabricator 37 | VM_NAME=phabricator 38 | -------------------------------------------------------------------------------- /vm/configure_mailgun.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -e 18 | 19 | if [ "$#" -lt 2 ]; then 20 | echo "Usage: ${BASH_SOURCE[0]} " 21 | exit 1 22 | fi 23 | 24 | PHABRICATOR_BASE_DOMAIN=$1 25 | MAILGUN_APIKEY=$2 26 | 27 | pushd phabricator >> /dev/null 28 | 29 | echo "Configuring Phabricator for Mailgun..." 30 | 31 | sudo ./bin/config set mailgun.api-key $MAILGUN_APIKEY 32 | sudo ./bin/config set mailgun.domain $PHABRICATOR_BASE_DOMAIN 33 | 34 | sudo ./bin/config set --database metamta.mail-adapter PhabricatorMailImplementationMailgunAdapter 35 | sudo ./bin/config set --database metamta.domain $PHABRICATOR_BASE_DOMAIN 36 | sudo ./bin/config set --database metamta.default-address noreply@$PHABRICATOR_BASE_DOMAIN 37 | 38 | popd >> /dev/null 39 | -------------------------------------------------------------------------------- /vm/configure_submodules.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -e 18 | 19 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 20 | 21 | pushd $DIR >> /dev/null 22 | git submodule update --init --recursive 23 | popd >> /dev/null 24 | 25 | function clone { 26 | if [ ! -d $1 ]; then 27 | echo "Cloning $1..." 28 | sudo git clone $DIR/third_party/$1 $1 || exit 1 29 | else 30 | pushd $1 >> /dev/null 31 | sudo git fetch $DIR/third_party/$1 32 | popd >> /dev/null 33 | fi 34 | 35 | pushd $DIR >> /dev/null 36 | sha=$(git submodule status third_party/$1 | cut -d' ' -f2) 37 | popd >> /dev/null 38 | pushd $1 >> /dev/null 39 | echo "Checking out $1/$sha..." 40 | sudo git checkout -q $sha 41 | popd >> /dev/null 42 | } 43 | 44 | clone arcanist 45 | clone libphutil 46 | clone phabricator 47 | -------------------------------------------------------------------------------- /nginx/nginx.conf.template: -------------------------------------------------------------------------------- 1 | events { 2 | worker_connections 768; 3 | } 4 | 5 | http { 6 | sendfile on; 7 | tcp_nopush on; 8 | tcp_nodelay on; 9 | keepalive_timeout 65; 10 | types_hash_max_size 2048; 11 | include /etc/nginx/mime.types; 12 | default_type application/octet-stream; 13 | client_max_body_size 100M; 14 | 15 | access_log /var/log/app_engine/app.log; 16 | error_log /var/log/app_engine/app.log; 17 | 18 | gzip on; 19 | gzip_disable "msie6"; 20 | 21 | server { 22 | listen 8080; 23 | server_name $PHABRICATOR_URL; 24 | location / { 25 | proxy_pass http://$PHABRICATOR_IP:8080; 26 | proxy_set_header Host $host; 27 | proxy_set_header X-Real-IP $remote_addr; 28 | proxy_set_header X-Forwarded-for $remote_addr; 29 | port_in_redirect off; 30 | proxy_connect_timeout 300; 31 | } 32 | location /_ah { 33 | root /usr/share/nginx/www; 34 | } 35 | } 36 | 37 | server { 38 | listen 8080; 39 | server_name $PHABRICATOR_ALTERNATE_URL; 40 | location / { 41 | proxy_pass http://$PHABRICATOR_IP:8080; 42 | proxy_set_header Host $host; 43 | proxy_set_header X-Real-IP $remote_addr; 44 | proxy_set_header X-Forwarded-for $remote_addr; 45 | port_in_redirect off; 46 | proxy_connect_timeout 300; 47 | } 48 | location /_ah { 49 | root /usr/share/nginx/www; 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /vm/configure_users.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -e 18 | 19 | if ! cat /etc/passwd | grep "^phabricator-daemon" >> /dev/null; then 20 | sudo useradd -r -s /bin/bash phabricator-daemon 21 | fi 22 | 23 | if ! cat /etc/passwd | grep "^git" >> /dev/null; then 24 | sudo useradd -r -s /bin/bash git 25 | fi 26 | 27 | if ! cat /etc/passwd | grep "^aphlict" >> /dev/null; then 28 | sudo useradd -r -s /bin/bash aphlict 29 | fi 30 | 31 | if sudo cat /etc/shadow | grep "^git:\!:" >> /dev/null; then 32 | sudo sed -i -e "s/^git:\!:/git:NP:/" /etc/shadow 33 | fi 34 | 35 | if ! sudo cat /etc/sudoers | grep "^git ALL=(phabricator-daemon)" >> /dev/null; then 36 | echo "git ALL=(phabricator-daemon) SETENV: NOPASSWD: $(whereis -b git-upload-pack | cut -d' ' -f2-), $(whereis -b git-receive-pack | cut -d' ' -f2-)" | (sudo su -c 'EDITOR="tee -a" visudo') 37 | fi 38 | -------------------------------------------------------------------------------- /vm/configure_notifications.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -e 18 | 19 | if [ "$#" -lt 1 ]; then 20 | echo "Usage: ${BASH_SOURCE[0]} " 21 | exit 1 22 | fi 23 | 24 | NOTIFICATIONS_URL=$1 25 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 26 | 27 | sudo apt-get install -y npm 28 | 29 | ln -s /usr/bin/nodejs /usr/bin/node 30 | 31 | pushd phabricator/support/aphlict/server >> /dev/null 32 | sudo npm install ws 33 | popd >> /dev/null 34 | 35 | # Start the notification server 36 | pushd phabricator >> /dev/null 37 | 38 | sudo ./bin/config set notification.servers '[{"type":"client","host":"'$NOTIFICATIONS_URL'","port":22280,"protocol":"http"},{"type":"admin","host":"127.0.0.1","port":22281,"protocol":"http"}]' 39 | 40 | sudo touch /var/log/aphlict.log 41 | sudo chmod a+w /var/log/aphlict.log 42 | sudo chown -R aphlict:aphlict /var/tmp/aphlict/ 43 | 44 | popd >> /dev/null 45 | -------------------------------------------------------------------------------- /vm/configure_phabricator.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -e 18 | 19 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 20 | 21 | pushd phabricator >> /dev/null 22 | 23 | echo "Stopping daemons..." 24 | 25 | sudo ./bin/phd stop 26 | 27 | sudo chown -R phabricator-daemon /var/tmp/phd 28 | 29 | sudo ./bin/config set phabricator.timezone America/Los_Angeles 30 | sudo ./bin/config set phabricator.show-prototypes true 31 | sudo ./bin/config set pygments.enabled true 32 | sudo ./bin/config set config.ignore-issues '{"mysql.ft_boolean_syntax":true, "mysql.ft_stopword_file": true, "daemons.need-restarting": true, "mysql.max_allowed_packet": true, "large-files": true, "mysql.innodb_buffer_pool_size": true}' 33 | sudo ./bin/config set environment.append-paths '["/usr/lib/git-core/"]' 34 | sudo ./bin/config set phd.user phabricator-daemon 35 | sudo ./bin/config set diffusion.ssh-user git 36 | 37 | popd >> /dev/null 38 | -------------------------------------------------------------------------------- /vm/configure_gcloud.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -e 18 | 19 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 20 | 21 | # Install unzip 22 | sudo apt-get install -y unzip 23 | 24 | # Remove any existing zip first 25 | sudo rm -f google-cloud-sdk.zip 26 | 27 | # Download google-cloud_sdk 28 | sudo wget https://dl.google.com/dl/cloudsdk/release/google-cloud-sdk.zip 29 | 30 | # Unzip sdk into google directory 31 | sudo unzip -uo google-cloud-sdk.zip -d /google/ 32 | 33 | sudo rm -f google-cloud-sdk.zip 34 | 35 | if [ $(grep -c "\/google\/google-cloud-sdk\/bin" /etc/profile) -eq 0 ]; then 36 | echo "Adding google cloud SDK to path..."; 37 | echo PATH=/google/google-cloud-sdk/bin:\$PATH | sudo tee --append /etc/profile 38 | fi 39 | 40 | sudo /google/google-cloud-sdk/install.sh \ 41 | --rc-path=/etc/bash.bashrc \ 42 | --usage-reporting=false \ 43 | --command-completion=true \ 44 | --path-update=true 45 | 46 | sudo /google/google-cloud-sdk/bin/gcloud config set --installation component_manager/disable_update_check True 47 | -------------------------------------------------------------------------------- /vm/configure_hosted_repos.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -e 18 | 19 | if [ ! -d /mnt/git-repos ]; then 20 | echo "Creating hosted repo folder..." 21 | sudo mkdir -p /mnt/git-repos 22 | 23 | # TODO: This is assuming that the "first" disk mounted is the git-repos one and that its name is 24 | # /dev/sdb. We should be identifying the disk name from an `instances describe` call. 25 | sudo /usr/share/google/safe_format_and_mount -m "mkfs.ext4 -F" /dev/sdb /mnt/git-repos 26 | 27 | sudo chown phabricator-daemon:phabricator-daemon /mnt/git-repos 28 | fi 29 | 30 | if [ ! -d /mnt/file-storage ]; then 31 | echo "Creating file storage folder..." 32 | sudo mkdir -p /mnt/file-storage 33 | 34 | # TODO: This is assuming that the "second" disk mounted is the git-repos one and that its name is 35 | # /dev/sdc. We should be identifying the disk name from an `instances describe` call. 36 | sudo /usr/share/google/safe_format_and_mount -m "mkfs.ext4 -F" /dev/sdc /mnt/file-storage 37 | 38 | sudo chown www-data:www-data /mnt/file-storage 39 | fi 40 | 41 | pushd phabricator >> /dev/null 42 | 43 | sudo ./bin/config set repository.default-local-path /mnt/git-repos 44 | sudo ./bin/config set storage.local-disk.path /mnt/file-storage 45 | 46 | popd >> /dev/null 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Want to contribute? Great! First, read this page (including the small print at the end). 2 | 3 | ## Pull requests 4 | 5 | Pull requests can be hard to review if they try to tackle too many things 6 | at once. Phabricator's "[Writing Reviewable Code](https://secure.phabricator.com/book/phabflavor/article/writing_reviewable_code/)" 7 | provides a set of guidelines that help increase the likelihood of your 8 | pull request getting merged. 9 | 10 | In short (slightly modified from the original article): 11 | 12 | - A pull request should be as small as possible, but no smaller. 13 | - The smallest a pull request can be is a single cohesive idea: don't 14 | make pull requests so small that they are meaningless on their own. 15 | - Turn large pull requests into small pull requests by dividing large 16 | problems into smaller problems and solving the small problems one at 17 | a time. 18 | - Write sensible pull request descriptions. 19 | 20 | ### Before you contribute 21 | 22 | Before we can use your code, you must sign the 23 | [Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual?csw=1) 24 | (CLA), which you can do online. The CLA is necessary mainly because you own the 25 | copyright to your changes, even after your contribution becomes part of our 26 | codebase, so we need your permission to use and distribute your code. We also 27 | need to be sure of various other things—for instance that you'll tell us if you 28 | know that your code infringes on other people's patents. You don't have to sign 29 | the CLA until after you've submitted your code for review and a member has 30 | approved it, but you must do it before we can put your code into our codebase. 31 | Before you start working on a larger contribution, you should get in touch with 32 | us first through the issue tracker with your idea so that we can help out and 33 | possibly guide you. Coordinating up front makes it much easier to avoid 34 | frustration later on. 35 | 36 | ### The small print 37 | 38 | Contributions made by corporations are covered by a different agreement than 39 | the one above, the [Software Grant and Corporate Contributor License Agreement](https://cla.developers.google.com/about/google-corporate). 40 | -------------------------------------------------------------------------------- /vm/configure_apache.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -e 18 | 19 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 20 | 21 | function safe_copy { 22 | if [ ! -f $2 ]; then 23 | echo "Copying $1..." 24 | sudo cp $1 $2 25 | else 26 | if ! cmp --silent $1 $2; then 27 | echo "Overwrite existing $1 at $2?" 28 | select yn in "Yes" "No"; do 29 | case $yn in 30 | Yes ) echo "Updating $2 site...";sudo cp $1 $2; break;; 31 | No ) exit;; 32 | esac 33 | done 34 | fi 35 | fi 36 | } 37 | 38 | if [ $(grep -c "^Listen 80$" /etc/apache2/ports.conf) -ne 0 ]; then 39 | echo "Listening port set to 8080."; 40 | sudo sed -i -e 's/^Listen 80$/Listen 8080/' /etc/apache2/ports.conf 41 | fi 42 | 43 | if [ -f /etc/apache2/sites-enabled/000-default.conf ]; then 44 | echo "Removing default site..." 45 | sudo rm -f /etc/apache2/sites-enabled/000-default.conf 46 | fi 47 | 48 | safe_copy $DIR/sites/phabricator.conf /etc/apache2/sites-available/phabricator.conf 49 | 50 | if [ ! -h /etc/apache2/sites-enabled/phabricator.conf ]; then 51 | echo "Activating phabricator site..." 52 | sudo ln -s /etc/apache2/sites-available/phabricator.conf /etc/apache2/sites-enabled/phabricator.conf 53 | fi 54 | 55 | if [ ! -d /usr/local/apache/logs ]; then 56 | echo "Configuring apache logs..." 57 | sudo mkdir -p /usr/local/apache/logs && sudo chown www-data:www-data /usr/local/apache/logs 58 | fi 59 | 60 | if [ ! -d /var/log/phabricator ]; then 61 | echo "Configuring phabricator logs..." 62 | sudo mkdir -p /var/log/phabricator && sudo chown www-data:www-data /var/log/phabricator 63 | fi 64 | 65 | -------------------------------------------------------------------------------- /vm/upgrade.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 18 | 19 | set -e 20 | 21 | # NOTE: This script assumes you are running it from a directory which contains 22 | # arcanist/, libphutil/, and phabricator/. 23 | 24 | pushd $DIR >> /dev/null 25 | 26 | sudo git fetch 27 | sudo git rebase origin/master 28 | sudo git submodule update 29 | 30 | popd >> /dev/null 31 | 32 | ### CYCLE WEB SERVER AND DAEMONS ############################################### 33 | 34 | pushd phabricator >> /dev/null 35 | 36 | # Stop daemons. 37 | sudo su phabricator-daemon -c "./bin/phd stop" 38 | 39 | # If running the notification server, stop it. 40 | sudo su aphlict -c "./bin/aphlict stop" 41 | 42 | # Stop the webserver. 43 | sudo apachectl stop 44 | 45 | ### UPDATE SYSTEM PACKAGES ###################################################### 46 | 47 | sudo apt-get -qq update 48 | sudo apt-get upgrade -y 49 | sudo apt-get autoremove -y 50 | 51 | # apt-get may have updated apache; ensure that it's truly stopped. 52 | sudo apachectl stop 53 | 54 | ### UPDATE WORKING COPIES ###################################################### 55 | 56 | popd >> /dev/null 57 | 58 | sudo $DIR/configure_submodules.sh 59 | 60 | pushd phabricator >> /dev/null 61 | 62 | # Upgrade the database schema. 63 | sudo ./bin/storage upgrade --force 64 | 65 | # Restart the webserver. 66 | sudo apachectl start 67 | 68 | # Restart daemons. 69 | sudo su phabricator-daemon -c "./bin/phd start" 70 | 71 | # If running the notification server, start it. 72 | if hash nodejs 2>/dev/null; then 73 | sudo su aphlict -c "./bin/aphlict start" 74 | fi 75 | 76 | popd >> /dev/null 77 | -------------------------------------------------------------------------------- /vm/configure_ssh.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -e 18 | 19 | if [ "$#" -lt 1 ]; then 20 | echo "Usage: ${BASH_SOURCE[0]} " 21 | exit 1 22 | fi 23 | 24 | GIT_URL=$1 25 | 26 | if [ $(grep -c "^Port 22$" /etc/ssh/sshd_config) -ne 0 ]; then 27 | echo "Listening port set to 222."; 28 | sudo sed -i -e 's/^Port 22$/Port 222/' /etc/ssh/sshd_config 29 | 30 | sudo service ssh restart 31 | fi 32 | 33 | sudo mkdir -p /etc/libexec/ 34 | 35 | if [ ! -f /etc/libexec/phabricator-ssh-hook.sh ]; then 36 | sudo cp phabricator/resources/sshd/phabricator-ssh-hook.sh /etc/libexec/ 37 | fi 38 | 39 | sudo sed -i -e "s/^VCSUSER=.*$/VCSUSER=\"git\"/" /etc/libexec/phabricator-ssh-hook.sh 40 | sudo sed -i -e 's:^ROOT=.*$:ROOT="'$(pwd)'/phabricator":' /etc/libexec/phabricator-ssh-hook.sh 41 | sudo chown root /etc/libexec/phabricator-ssh-hook.sh 42 | sudo chmod 755 /etc/libexec/phabricator-ssh-hook.sh 43 | 44 | if [ ! -f /etc/ssh/sshd_config.phabricator ]; then 45 | sudo cp phabricator/resources/sshd/sshd_config.phabricator.example /etc/ssh/sshd_config.phabricator 46 | fi 47 | 48 | sudo sed -i -e "s:^AuthorizedKeysCommand .*$:AuthorizedKeysCommand /etc/libexec/phabricator-ssh-hook.sh:" /etc/ssh/sshd_config.phabricator 49 | sudo sed -i -e "s:^AuthorizedKeysCommandUser .*$:AuthorizedKeysCommandUser git:" /etc/ssh/sshd_config.phabricator 50 | sudo sed -i -e "s:^AllowUsers .*$:AllowUsers git:" /etc/ssh/sshd_config.phabricator 51 | 52 | # TODO: Turn this into a service. 53 | sudo $(whereis -b sshd | cut -d' ' -f2) -f /etc/ssh/sshd_config.phabricator 54 | 55 | pushd phabricator >> /dev/null 56 | sudo ./bin/config set diffusion.ssh-host $GIT_URL 57 | popd >> /dev/null 58 | -------------------------------------------------------------------------------- /vm/configure_sendgrid.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -e 18 | 19 | sudo apt-get install postfix libsasl2-modules -y 20 | 21 | if [ $(grep -c "^default_transport" /etc/postfix/main.cf) -ne 0 ]; then 22 | echo "Disabling default_transport..."; 23 | sed -i -e "s/^default_transport/# default_transport/" /etc/postfix/main.cf 24 | fi 25 | 26 | if [ $(grep -c "^relay_transport" /etc/postfix/main.cf) -ne 0 ]; then 27 | echo "Disabling relay_transport..."; 28 | sed -i -e "s/^relay_transport/# relay_transport/" /etc/postfix/main.cf 29 | fi 30 | 31 | if [ $(grep -c "^relayhost" /etc/postfix/main.cf) -eq 0 ]; then 32 | echo "Adding relayhost..."; 33 | echo "relayhost = [smtp.sendgrid.net]:2525" >> /etc/postfix/main.cf 34 | else 35 | echo "Editing relayhost..."; 36 | sed -i -e "s/^relayhost.+$/#relayhost = [smtp.sendgrid.net]:2525/" /etc/postfix/main.cf 37 | fi 38 | 39 | if [ $(grep -c "^smtp_tls_security_level" /etc/postfix/main.cf) -eq 0 ]; then 40 | echo "Adding smtp_tls_security_level..."; 41 | echo "smtp_tls_security_level = encrypt" >> /etc/postfix/main.cf 42 | echo "smtp_sasl_auth_enable = yes" >> /etc/postfix/main.cf 43 | echo "smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd" >> /etc/postfix/main.cf 44 | echo "header_size_limit = 4096000" >> /etc/postfix/main.cf 45 | echo "smtp_sasl_security_options = noanonymous" >> /etc/postfix/main.cf 46 | fi 47 | 48 | if [ ! -f /etc/postfix/sasl_passwd.db ]; then 49 | echo "Please enter your sendmail credentials from https://app.sendgrid.com/settings/credentials" 50 | echo -n "Sendgrid Username: " 51 | read username 52 | echo 53 | echo -n "Sendgrid Password: " 54 | read -s password 55 | echo 56 | 57 | echo "[smtp.sendgrid.net]:2525 $username:$password" >> /etc/postfix/sasl_passwd 58 | postmap /etc/postfix/sasl_passwd 59 | rm /etc/postfix/sasl_passwd 60 | chmod 600 /etc/postfix/sasl_passwd.db 61 | fi 62 | 63 | echo "Restarting postfix..." 64 | /etc/init.d/postfix restart 65 | -------------------------------------------------------------------------------- /vm/startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | #VM_NAME= 18 | #DNS_NAME= 19 | #TOP_LEVEL_DOMAIN= 20 | #GIT_SUBDOMAIN= 21 | #NOTIFICATIONS_SUBDOMAIN= 22 | 23 | gcloud_instances() { 24 | sudo /google/google-cloud-sdk/bin/gcloud --quiet compute instances "$@" 25 | } 26 | 27 | VM_EXTERNAL_IP=$(gcloud_instances list | grep "\b$VM_NAME\b" | awk '{print $5}') 28 | 29 | pushd /opt/phabricator >> /dev/null 30 | 31 | sudo su phabricator-daemon -c "./bin/phd restart" 32 | sudo su aphlict -c "./bin/aphlict restart" 33 | sudo $(whereis -b sshd | cut -d' ' -f2) -f /etc/ssh/sshd_config.phabricator 34 | 35 | gcloud_dns_records() { 36 | sudo /google/google-cloud-sdk/bin/gcloud --quiet dns record-sets "$@" --zone="$DNS_NAME" 37 | } 38 | 39 | if [[ -n "$GIT_SUBDOMAIN" || -n "$NOTIFICATIONS_SUBDOMAIN" ]]; then 40 | if gcloud_dns_records transaction describe >> /dev/null 2>&1; then 41 | gcloud_dns_records transaction abort 42 | fi 43 | 44 | gcloud_dns_records transaction start 45 | if [ -n "$GIT_SUBDOMAIN" ]; then 46 | existing=$(gcloud_dns_records list | grep "$GIT_SUBDOMAIN.$TOP_LEVEL_DOMAIN." | grep "\bA\b" | awk '{print $4}') 47 | if [ -n "$existing" ]; then 48 | gcloud_dns_records transaction remove --name="$GIT_SUBDOMAIN.$TOP_LEVEL_DOMAIN." --ttl=60 --type=A "$existing" 49 | fi 50 | gcloud_dns_records transaction add --name="$GIT_SUBDOMAIN.$TOP_LEVEL_DOMAIN." --ttl=60 --type=A $VM_EXTERNAL_IP 51 | fi 52 | if [ -n "$NOTIFICATIONS_SUBDOMAIN" ]; then 53 | existing=$(gcloud_dns_records list | grep "$NOTIFICATIONS_SUBDOMAIN.$TOP_LEVEL_DOMAIN." | grep "\bA\b" | awk '{print $4}') 54 | if [ -n "$existing" ]; then 55 | gcloud_dns_records transaction remove --name="$NOTIFICATIONS_SUBDOMAIN.$TOP_LEVEL_DOMAIN." --ttl=60 --type=A "$existing" 56 | fi 57 | gcloud_dns_records transaction add --name="$NOTIFICATIONS_SUBDOMAIN.$TOP_LEVEL_DOMAIN." --ttl=60 --type=A $VM_EXTERNAL_IP 58 | fi 59 | gcloud_dns_records transaction execute 60 | fi 61 | 62 | popd >> /dev/null 63 | -------------------------------------------------------------------------------- /vm/configure_sql.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -e 18 | 19 | if [ "$#" -lt 2 ]; then 20 | echo "Usage: ${BASH_SOURCE[0]} ()" 21 | exit 1 22 | fi 23 | 24 | if ! /google/google-cloud-sdk/bin/gcloud --quiet sql instances list >> /dev/null 2> /dev/null; then 25 | PROJECT=$(gcloud info | grep Project | cut -d"[" -f2 | cut -d"]" -f1) 26 | echo 27 | echo 28 | echo " Error: Google Cloud SQL API has not been enabled for $PROJECT." 29 | echo 30 | echo " 1. Please visit https://console.developers.google.com/apis/api/sqladmin/overview?project=$PROJECT" 31 | echo " 2. Enable API button" 32 | echo " 3. Rerun this script" 33 | echo 34 | exit 1 35 | fi 36 | 37 | # TODO: Once SQL gen 2 is out of beta we may be able to use the proxy. 38 | # sudo wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 39 | # sudo mv cloud_sql_proxy.linux.amd64 cloud_sql_proxy 40 | # sudo chmod +x cloud_sql_proxy 41 | # 42 | # sudo mkdir -p /cloudsql 43 | # sudo chmod 777 /cloudsql 44 | # sudo ./cloud_sql_proxy -dir=/cloudsql -fuse & 45 | 46 | SQL_INSTANCE=$1 47 | PHABRICATOR_BASE_URI=$2 48 | if [ "$#" -eq 3 ]; then 49 | PHABRICATOR_ALTERNATE_BASE_URI=$3 50 | else 51 | PHABRICATOR_ALTERNATE_BASE_URI= 52 | fi 53 | 54 | # uuid-runtime: required to generate our root password 55 | # jq: required for parsing the sql server json details 56 | sudo apt-get install -y uuid-runtime jq 57 | 58 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 59 | 60 | pushd phabricator >> /dev/null 61 | export SQL_DETAILS="$(/google/google-cloud-sdk/bin/gcloud sql instances describe ${SQL_INSTANCE} --format=json)" 62 | if [ -z "${SQL_DETAILS}" ]; then 63 | echo "Failed to lookup details for the '${SQL_INSTANCE}' Cloud SQL instance. Make sure that you have the SQL API enabled." 64 | exit 1 65 | fi 66 | popd >> /dev/null 67 | 68 | # TODO: Once SQL gen 2 is out of beta we may be able to use the proxy. 69 | # export SQL_PROJECT=$(echo ${SQL_DETAILS} | jq -r '.project') 70 | # export SQL_REGION=$(echo ${SQL_DETAILS} | jq -r '.region') 71 | # export SQL_HOST="/cloudsql/$SQL_PROJECT:$SQL_REGION:$SQL_INSTANCE" 72 | 73 | export SQL_HOST=$(echo ${SQL_DETAILS} | jq -r '.ipAddresses[0].ipAddress') 74 | if [ -z "${SQL_HOST}" ]; then 75 | echo "Failed to create the host of the '${SQL_INSTANCE}' Cloud SQL instance" 76 | exit 1 77 | fi 78 | 79 | export SQL_USER=root 80 | echo "Setting up a connection to ${SQL_INSTANCE} at ${SQL_HOST} as ${SQL_USER}" 81 | 82 | export SQL_PASS="$(uuidgen)" 83 | sudo /google/google-cloud-sdk/bin/gcloud sql instances set-root-password --password "${SQL_PASS}" "${SQL_INSTANCE}" 84 | 85 | pushd /opt/phabricator >> /dev/null 86 | 87 | # Configure Phabricator's connection to the SQL server. 88 | sudo ./bin/config set mysql.host ${SQL_HOST} 89 | sudo ./bin/config set mysql.port 3306 90 | sudo ./bin/config set mysql.user ${SQL_USER} 91 | sudo ./bin/config set mysql.pass ${SQL_PASS} 92 | 93 | # Configure Phabricator's reference to itself. 94 | sudo ./bin/config set phabricator.base-uri ${PHABRICATOR_BASE_URI} 95 | sudo ./bin/config set security.alternate-file-domain ${PHABRICATOR_ALTERNATE_BASE_URI} 96 | sudo ./bin/config set phd.taskmasters 4 97 | 98 | popd >> /dev/null 99 | 100 | echo "Upgrading $SQL_INSTANCE db (this may take a few minutes)..." 101 | 102 | sudo phabricator/bin/storage upgrade --force 103 | -------------------------------------------------------------------------------- /vm/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | # Terminate execution on command failure 18 | set -e 19 | 20 | if [ "$#" -lt 2 ]; then 21 | echo "Usage: ${BASH_SOURCE[0]} ()" 22 | exit 1 23 | fi 24 | 25 | SQL_INSTANCE=$1 26 | PHABRICATOR_BASE_URI=$2 27 | 28 | if [ "$#" -eq 3 ]; then 29 | PHABRICATOR_ALTERNATE_BASE_URI=$3 30 | else 31 | PHABRICATOR_ALTERNATE_BASE_URI= 32 | fi 33 | 34 | confirm() { 35 | echo "Press RETURN to continue, or ^C to cancel."; 36 | read -e ignored 37 | } 38 | 39 | GIT='git' 40 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 41 | 42 | LTS="Ubuntu 10.04" 43 | ISSUE=`cat /etc/issue` 44 | if [[ $ISSUE != Ubuntu* ]] 45 | then 46 | echo "This script is intended for use on Ubuntu, but this system appears"; 47 | echo "to be something else. Your results may vary."; 48 | echo 49 | confirm 50 | elif [[ `expr match "$ISSUE" "$LTS"` -eq ${#LTS} ]] 51 | then 52 | GIT='git-core' 53 | fi 54 | 55 | echo "PHABRICATOR UBUNTU INSTALL SCRIPT"; 56 | echo "This script will install Phabricator and all of its core dependencies."; 57 | echo "Run it from the directory you want to install into."; 58 | echo 59 | 60 | ROOT=`pwd` 61 | echo "Phabricator will be installed to: ${ROOT}."; 62 | 63 | echo "Testing sudo..." 64 | sudo true 65 | if [ $? -ne 0 ]; then 66 | echo "ERROR: You must be able to sudo to run this script."; 67 | exit 1; 68 | fi; 69 | 70 | echo "Installing dependencies: git, apache, mysql, php..."; 71 | echo 72 | 73 | set +x 74 | 75 | # -qq No output except for errors 76 | sudo apt-get -qq update 77 | 78 | # Install git 79 | sudo apt-get install -y git 80 | 81 | # Install mysql 82 | sudo apt-get install -y mysql-client libmysqlclient-dev 83 | 84 | # Install Apache 85 | sudo apt-get install -y apache2 86 | 87 | # Install php 88 | sudo apt-get install -y php5 php5-mysql php5-gd php5-dev php5-curl php-apc php5-cli php5-json 89 | 90 | sudo apt-get clean 91 | 92 | # Enable mod-rewrite 93 | sudo a2enmod rewrite 94 | 95 | HAVEPCNTL=`php -r "echo extension_loaded('pcntl');"` 96 | if [ $HAVEPCNTL != "1" ] 97 | then 98 | echo "Installing pcntl..."; 99 | echo 100 | apt-get source php5 101 | PHP5=`ls -1F | grep '^php5-.*/$'` 102 | (cd $PHP5/ext/pcntl && phpize && ./configure && make && sudo make install) 103 | else 104 | echo "pcntl already installed"; 105 | fi 106 | 107 | line() { 108 | echo 109 | echo "============================================" 110 | echo "$@" 111 | } 112 | 113 | line "Configuring users..." 114 | bash $DIR/configure_users.sh || exit 1 115 | 116 | line "Configuring submodules..." 117 | bash $DIR/configure_submodules.sh || exit 1 118 | 119 | line "Configuring apache..." 120 | bash $DIR/configure_apache.sh || exit 1 121 | 122 | line "Configuring php..." 123 | bash $DIR/configure_php.sh || exit 1 124 | 125 | line "Configuring pygments..." 126 | bash $DIR/configure_pygments.sh || exit 1 127 | 128 | line "Configuring phabricator..." 129 | bash $DIR/configure_phabricator.sh || exit 1 130 | 131 | line "Configuring hosted repos..." 132 | bash $DIR/configure_hosted_repos.sh || exit 1 133 | 134 | line "Configuring gcloud..." 135 | bash $DIR/configure_gcloud.sh || exit 1 136 | 137 | line "Configuring sql..." 138 | bash $DIR/configure_sql.sh $SQL_INSTANCE $PHABRICATOR_BASE_URI $PHABRICATOR_ALTERNATE_BASE_URI || exit 1 139 | 140 | pushd phabricator >> /dev/null 141 | line "Starting daemons" 142 | sudo su phabricator-daemon -c "./bin/phd restart" 143 | popd >> /dev/null 144 | 145 | line "Restarting apache..." 146 | sudo apachectl restart 147 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Phabricator on Google's Compute Engine 2 | 3 | This script tries its darndest to automate the process of setting up a Phabricator server on 4 | Google's Compute Engine. 5 | 6 | Things that aren't automated: 7 | 8 | - Creating a Cloud engine project. 9 | - Enabling Google Cloud APIs. 10 | - Installing the gcloud APIs on your local machine. 11 | - Buying a domain. 12 | - Updating your domain's NS entries to point to Google's Cloud DNS. 13 | - Signing up for a mailgun account. 14 | - Creating a mailgun domain. 15 | 16 | This repo contains a script that handles most of the rest of the busy work. Let's go over getting a 17 | Compute Engine project started. 18 | 19 | ## Getting started 20 | 21 | ### Create a project 22 | 23 | Visit https://console.developers.google.com/project to create a new project. 24 | 25 | ### Enable APIs 26 | 27 | Visit your project's APIs library: 28 | 29 | https://console.developers.google.com/apis/library?project=your-project-name 30 | 31 | And enable the following: 32 | 33 | 1. Google Compute Engine 34 | 2. Google Cloud SQL API 35 | 3. Google Cloud DNS API 36 | 37 | You don't need to create credentials for either of the above services. 38 | 39 | Estimated time to complete: 2-5 minutes (all manual steps). 40 | 41 | ### Install gcloud tools 42 | 43 | Follow the directions located here: https://cloud.google.com/sdk/?hl=en 44 | 45 | curl https://sdk.cloud.google.com | bash 46 | 47 | NOTE for [fish shell](https://fishshell.com/) users: gcloud doesn't provide fish support out of the 48 | box. You can directly add the gcloud bin to your path by editing config.fish like so: 49 | 50 | vi ~/.config/fish/config.fish 51 | set -x PATH $PATH /path/to/google-cloud-sdk/bin 52 | 53 | Once gcloud has been installed and is available in your PATH (may require restarting terminal), run: 54 | 55 | gcloud init 56 | 57 | This configuration will ask you for the following information: 58 | 59 | - Your login credentials 60 | - A cloud project (pick your phabricator project) 61 | - The default compute zone (pick what's closest to you) 62 | - Whether or not you want to use Google's source hosting. You don't need this for this script. 63 | 64 | Estimated time to complete: 5 minutes (some manual steps). 65 | 66 | ### Create your project's configuration file 67 | 68 | The first time you run the script it will create a default configuration file for your project in 69 | `config/`. 70 | 71 | ./install -p 72 | 73 | ### Run the install script 74 | 75 | Once you've configured your project's config file you can run the install script: 76 | 77 | ./install -p 78 | 79 | Estimated time to complete: 18-20 minutes (totally automated after invocation). 80 | 81 | ### Upgrading phabricator 82 | 83 | To upgrade phabricator you may run: 84 | 85 | ./upgrade -p 86 | 87 | Estimated time to complete: 3 minutes (totally automated after invocation). 88 | 89 | ### Connecting to the phabricator instance 90 | 91 | To ssh into your instance you must run: 92 | 93 | ./ssh -p 94 | 95 | ### Shutting down the server 96 | 97 | TODO: Discuss shutting down compute engine and serving a static "update in progress page." 98 | 99 | ## Custom domains 100 | 101 | Custom domains enable the following features: 102 | 103 | - Email with Mailgun 104 | - Notifications 105 | - Git hosting 106 | 107 | ### Before you start 108 | 109 | - Choose your favorite registrar and purchase a domain name. Ensure that you are able to change the 110 | name servers for your domain. 111 | - Register for Mailgun. [Mailgun](http://www.mailgun.com/) is 112 | [Phabricator's recommended outgoing email service](https://secure.phabricator.com/book/phabricator/article/configuring_outbound_email/). 113 | Register for an account and provide it with your custom domain. 114 | 115 | NOTE: Do not use a subdomain when creating your Mailgun domain. E.g. if your website's name is 116 | `phabricatorplayground.com`, use `phabricatorplayground.com` as the domain name. 117 | 118 | ### Update your configuration 119 | 120 | Modify your `config/` file to set the following values: 121 | 122 | MAILGUN_APIKEY="your api key" 123 | CUSTOM_DOMAIN="yourdomain.com" 124 | CUSTOM_DOMAIN_A_RECORD="ip.1 ip.2 ip.3 ip.4" 125 | CUSTOM_DOMAIN_AAAA_RECORD="ip::1 ip::2 ip::3 ip::4" 126 | 127 | # Note that the above records are space-separated. There should be four for each. 128 | 129 | Re-run the installation script: 130 | 131 | ./install -p 132 | 133 | Follow the displayed steps to register your custom domain with your Cloud Engine project. 134 | 135 | #### Manual step: Change nameservers 136 | 137 | Once the install script completes you must change the name servers for your domain. 138 | 139 | Start by visiting the DNS Zones page of your project: 140 | 141 | https://console.cloud.google.com/networking/dns/zones 142 | 143 | Open your phabricator zone and look at the `NS` values listed. Enter these values in your 144 | registrar's namespace editor for your domain. These changes may take up to 24 hours to propagate. 145 | 146 | You will know once your DNS changes have propagated when you visit your Mailgun project page and 147 | your domain has been verified. 148 | 149 | #### Don't want to wait for propagation? 150 | 151 | If propagation is taking a long time you can set up a temporary mapping by modifying any of the IPs 152 | found at: 153 | 154 | https://console.cloud.google.com/appengine/settings/domains 155 | 156 | to your domain in your `/etc/hosts` file. 157 | 158 | some.ipyourdomain.com 159 | 160 | #### Troubleshooting DNS 161 | 162 | > server DNS address could not be found. 163 | 164 | Ensure that your NS entries for your custom domain on Cloud Engine match the ones set on your 165 | registrar. 166 | 167 | ## License 168 | 169 | Licensed under the Apache 2.0 license. See LICENSE for details. 170 | -------------------------------------------------------------------------------- /lib/init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | usage() { 18 | echo "Usage: ${BASH_SOURCE[0]} -p " 19 | } 20 | 21 | gcloud version >/dev/null 2>&1 || { echo >&2 "gcloud binary is missing. Download from https://cloud.google.com/sdk/?hl=en"; exit 1; } 22 | 23 | GCLOUD_VERSION=$(gcloud version | grep "^Google" | cut -d' ' -f4 | cut -d'.' -f1) 24 | GITHUB_REPO="https://github.com/GoogleCloudPlatform/compute-phabricator.git" 25 | 26 | if [ "$GCLOUD_VERSION" -lt 102 ]; then 27 | echo "Minimum gcloud version required: 102. Found $GCLOUD_VERSION instead." 28 | exit 1 29 | fi 30 | 31 | OPTIND=1 # Reset in case getopts has been used previously in the shell. 32 | 33 | # Option defaults 34 | PROJECT="" 35 | VERBOSE=0 36 | 37 | while getopts "h?vp:" opt; do 38 | case "$opt" in 39 | h|\?) 40 | usage 41 | exit 0 42 | ;; 43 | v) VERBOSE=1 44 | ;; 45 | p) PROJECT=$OPTARG 46 | ;; 47 | esac 48 | done 49 | 50 | verbose() { 51 | if [ "$VERBOSE" -eq "1" ]; then 52 | echo "$@" 53 | fi 54 | } 55 | 56 | status() { 57 | echo -n "$@" 58 | } 59 | 60 | status_no() { 61 | echo no 62 | } 63 | 64 | status_ok() { 65 | echo OK 66 | } 67 | 68 | if [ -z "$PROJECT" ]; then 69 | verbose "Inferring project from default settings..." 70 | PROJECT=$(gcloud config list 2>/dev/null | grep "^project" | cut -d' ' -f3) 71 | 72 | echo "Inferred project:" 73 | echo 74 | echo " $PROJECT" 75 | echo 76 | echo "If incorrect, please terminate this script and provide a -p argument." 77 | echo "If correct, press enter to continue." 78 | echo 79 | echo "Provide a -p argument to avoid this warning in the future." 80 | read 81 | fi 82 | 83 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 84 | mkdir -p "$DIR/../config" 85 | CONFIG_ROOT_PATH="$( cd "$DIR/../config" && pwd )" 86 | CONFIG_PATH="$CONFIG_ROOT_PATH/$PROJECT" 87 | 88 | # Check existence of a config file for this project. 89 | if [ ! -f "$CONFIG_PATH" ]; then 90 | echo "No config was found." 91 | echo "A standard one has been made for you based off phabricator.sh.template." 92 | echo "Please configure $CONFIG_PATH to your preferences." 93 | 94 | mkdir -p "$CONFIG_ROOT_PATH" 95 | cp $DIR/../phabricator.sh.template "$CONFIG_PATH" 96 | chmod +x $CONFIG_PATH 97 | 98 | default_zone=$(gcloud config list 2>/dev/null | grep "^zone" | cut -d' ' -f3) 99 | if [ ! -z "$default_zone" ]; then 100 | sed -i.bak "s/^ZONE=.*/ZONE=$default_zone/" "$CONFIG_PATH" 101 | rm "$CONFIG_PATH.bak" 102 | fi 103 | 104 | exit 1 105 | fi 106 | 107 | verbose "Reading config from $CONFIG_PATH" 108 | . "$CONFIG_PATH" 109 | 110 | # Verify that a ZONE has been provided. 111 | if [ -z "$ZONE" ]; then 112 | echo "Config file has not specified a ZONE." 113 | echo "Please specify a ZONE in $CONFIG_PATH" 114 | exit 1 115 | fi 116 | 117 | # Colors 118 | 119 | RED='\033[0;31m' 120 | NC='\033[0m' 121 | 122 | logger() { 123 | while read data; do 124 | verbose "$data" 125 | done 126 | } 127 | 128 | # Register aliases methods for interacting with gcloud 129 | 130 | gcloud_project() { 131 | gcloud --project=${PROJECT} --quiet "$@" 132 | } 133 | 134 | gcloud_networks() { 135 | gcloud_project compute networks "$@" 136 | } 137 | 138 | gcloud_instances() { 139 | gcloud_project compute instances "$@" 140 | } 141 | 142 | gcloud_addresses() { 143 | gcloud_project compute addresses "$@" 144 | } 145 | 146 | gcloud_disks() { 147 | gcloud_project compute disks "$@" --zone "$ZONE" 148 | } 149 | 150 | gcloud_attach_disk() { 151 | gcloud_project compute instances attach-disk $VM_NAME "$@" --zone "$ZONE" 152 | } 153 | 154 | gcloud_zones() { 155 | gcloud_project compute zones "$@" 156 | } 157 | 158 | gcloud_dns_zones() { 159 | gcloud_project dns managed-zones "$@" 160 | } 161 | 162 | gcloud_dns_records() { 163 | gcloud_project dns record-sets "$@" --zone="$DNS_NAME" 164 | } 165 | 166 | gcloud_firewall_rules() { 167 | gcloud_project compute firewall-rules "$@" 168 | } 169 | 170 | gcloud_appengine() { 171 | gcloud_project app "$@" 172 | } 173 | 174 | gcloud_sql_instances() { 175 | gcloud_project sql instances "$@" 176 | } 177 | 178 | # SSL utils 179 | 180 | close_ssh() { 181 | status "ssh port is closed? " 182 | if [ "$(gcloud_firewall_rules list | grep "\b$NETWORK_NAME\b" | grep "\btemp-allow-ssh\b")" ]; then 183 | status_no 184 | 185 | status "- Removing temporary $NETWORK_NAME ssh firewall rule..." 186 | gcloud_firewall_rules delete temp-allow-ssh \ 187 | 2>&1 | logger || exit 1 188 | fi 189 | status_ok 190 | } 191 | 192 | open_ssh() { 193 | export PORT="22" 194 | if [ ! -z "$(gcloud_instances describe $VM_NAME --zone=$ZONE | grep "ssh-222")" ]; then 195 | PORT="222" 196 | fi 197 | 198 | trap close_ssh EXIT 199 | 200 | if [ -z "$(gcloud_firewall_rules list | grep "\b$NETWORK_NAME\b" | grep "\btemp-allow-ssh\b")" ]; then 201 | status "- Creating temporary $NETWORK_NAME ssh firewall rule..." 202 | gcloud_firewall_rules create temp-allow-ssh \ 203 | --allow "tcp:$PORT" \ 204 | --network $NETWORK_NAME \ 205 | --target-tags "phabricator" \ 206 | --source-ranges "0.0.0.0/0" \ 207 | 2>&1 | logger || exit 1 208 | fi 209 | status_ok 210 | } 211 | 212 | remote_exec() { 213 | echo "Executing $1..." 214 | gcloud --project=${PROJECT} compute ssh $VM_NAME --zone $ZONE --ssh-flag="-p $PORT" --command "$1" || exit 1 215 | } 216 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /install: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright 2016-present Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | . lib/init.sh 18 | 19 | # Terminate execution on command failure 20 | set -e 21 | 22 | if [[ ! -z "$CUSTOM_DOMAIN" && "$CUSTOM_DOMAIN_CONFIRMED" != "$PROJECT" ]]; then 23 | echo -e ${RED} 24 | echo "You have provided a custom domain of $CUSTOM_DOMAIN" 25 | echo "In order to configure the domain you will need to perform the following steps:" 26 | echo 27 | echo " 1. Visit https://console.developers.google.com/appengine/settings/domains?project=$PROJECT" 28 | echo 29 | echo " If $CUSTOM_DOMAIN is already listed there then your work is done here, otherwise continue with step 2:" 30 | echo 31 | echo " 2. Visit https://console.developers.google.com/appengine/settings/domains/add?project=$PROJECT" 32 | echo " 3. Register your custom domain." 33 | echo 34 | echo " Learn more about custom domains at https://cloud.google.com/appengine/docs/using-custom-domains-and-ssl?hl=en" 35 | echo -e ${NC} 36 | 37 | echo "Please press enter to confirm that you've registered $CUSTOM_DOMAIN as a custom domain, or Ctrl-C to quit." 38 | read 39 | 40 | if [ $(grep -c "^CUSTOM_DOMAIN_CONFIRMED" $CONFIG_PATH) -ne 0 ]; then 41 | sed -i'.tmp' -e "s/^CUSTOM_DOMAIN_CONFIRMED=.*/CUSTOM_DOMAIN_CONFIRMED=$PROJECT/" $CONFIG_PATH 42 | rm -rf $CONFIG_PATH.tmp 43 | else 44 | echo >> $CONFIG_PATH 45 | echo "CUSTOM_DOMAIN_CONFIRMED=$PROJECT" >> $CONFIG_PATH 46 | fi 47 | fi 48 | 49 | if [[ ! -z "$CUSTOM_DOMAIN" && -z "$CUSTOM_DOMAIN_A_RECORD" ]]; then 50 | echo -e ${RED} 51 | echo "You have provided a custom domain of $CUSTOM_DOMAIN" 52 | echo "but you have not provided the necessary A records." 53 | echo 54 | echo "Retrieve the A records by visiting:" 55 | echo 56 | echo " https://console.developers.google.com/appengine/settings/domains?project=$PROJECT" 57 | echo 58 | echo "Set the semicolon-separated values in CUSTOM_DOMAIN_A_RECORD within your config path:" 59 | echo 60 | echo " $CONFIG_PATH" 61 | echo 62 | echo "Example:" 63 | echo 64 | echo " CUSTOM_DOMAIN_A_RECORD=\"216.239.32.21; 216.239.34.21; 216.239.36.21; 216.239.38.21\"" 65 | echo 66 | echo -e ${NC} 67 | exit 1 68 | fi 69 | 70 | if [[ ! -z "$CUSTOM_DOMAIN" && -z "$CUSTOM_DOMAIN_AAAA_RECORD" ]]; then 71 | echo -e ${RED} 72 | echo "You have provided a custom domain of $CUSTOM_DOMAIN" 73 | echo "but you have not provided the necessary AAAA records." 74 | echo 75 | echo "Retrieve the AAAA records by visiting:" 76 | echo 77 | echo " https://console.developers.google.com/appengine/settings/domains?project=$PROJECT" 78 | echo 79 | echo "Set the semicolon-separated values in CUSTOM_DOMAIN_A_RECORD within your config path:" 80 | echo 81 | echo " $CONFIG_PATH" 82 | echo 83 | echo "Example:" 84 | echo 85 | echo " CUSTOM_DOMAIN_A_RECORD=\"2001:4860:4802:32::15; 2001:4860:4802:34::15; 2001:4860:4802:36::15; 2001:4860:4802:38::15\"" 86 | echo 87 | echo -e ${NC} 88 | exit 1 89 | fi 90 | 91 | if [[ ! -z "$MAILGUN_APIKEY" && -z "$MAILGUN_SMTP_DOMAIN_KEY_TXT" ]]; then 92 | echo -e ${RED} 93 | echo "You have provided a mailgun API key but no domain key" 94 | echo 95 | echo " Config file: $CONFIG_PATH" 96 | echo " Likely Mailgun url: https://mailgun.com/app/domains/$CUSTOM_DOMAIN" 97 | echo 98 | echo " Search for smtp._domainkey and set its **value** as the value" 99 | echo " of MAILGUN_SMTP_DOMAIN_KEY_TXT" 100 | echo -e ${NC} 101 | exit 1 102 | fi 103 | 104 | # TODO: Might not always be appspot - how do we configure this? 105 | PHABRICATOR_URL=$PROJECT.appspot.com 106 | PHABRICATOR_VERSIONED_URL=1-dot-$PROJECT.appspot.com 107 | 108 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 109 | 110 | status "Checking gcloud auth..." 111 | if [ -z "$(gcloud auth list 2> /dev/null | grep \(active\))" ]; then 112 | status_no 113 | 114 | status " Authenticating gcloud..." 115 | gcloud auth login || { echo "Failed to authenticate gcloud."; exit 1; } 116 | fi 117 | status_ok 118 | 119 | status "APIs..." 120 | if ! gcloud_networks list >> /dev/null 2>&1; then 121 | status_no 122 | 123 | echo 124 | echo " Error: The Compute Engine API has not been enabled for $PROJECT." 125 | echo 126 | echo " Please visit https://console.developers.google.com/apis/api/compute_component/overview?project=$PROJECT" 127 | echo " 2. Enable API button" 128 | echo " 3. Rerun this script" 129 | echo 130 | exit 1 131 | fi 132 | 133 | if ! gcloud_dns_zones list >> /dev/null 2>&1; then 134 | status_no 135 | 136 | echo 137 | echo " Error: Google Cloud DNS API has not been enabled for $PROJECT." 138 | echo 139 | echo " 1. Please visit https://console.developers.google.com/apis/api/dns/overview?project=$PROJECT" 140 | echo " 2. Enable API button" 141 | echo " 3. Rerun this script" 142 | echo 143 | exit 1 144 | fi 145 | status_ok 146 | 147 | status "Network..." 148 | if [ -z "$(gcloud_networks list | grep "\b$NETWORK_NAME\b")" ]; then 149 | status_no 150 | status "- Creating $NETWORK_NAME network..." 151 | gcloud_networks create \ 152 | $NETWORK_NAME \ 153 | --mode auto \ 154 | 2>&1 | logger || exit 1 155 | fi 156 | status_ok 157 | 158 | status "Static external IP..." 159 | if [ -z "$(gcloud_addresses list | grep "\b$ADDRESS_NAME\b")" ]; then 160 | status_no 161 | 162 | status "- Requesting static external IP..." 163 | gcloud_addresses create $ADDRESS_NAME \ 164 | 2>&1 | logger || exit 1 165 | fi 166 | status_ok 167 | 168 | STATIC_EXTERNAL_IP=$(gcloud_addresses list | grep "\b$ADDRESS_NAME\b" | cut -d' ' -f3) 169 | 170 | status "Compute instances..." 171 | if [ -z "$(gcloud_instances list | grep "\b$VM_NAME\b")" ]; then 172 | status_no 173 | 174 | status "- Creating $VM_NAME compute instance..." 175 | gcloud_instances create "$VM_NAME" \ 176 | --address "$STATIC_EXTERNAL_IP" \ 177 | --boot-disk-size "10GB" \ 178 | --image "ubuntu-14-04" \ 179 | --machine-type "n1-standard-1" \ 180 | --network "$NETWORK_NAME" \ 181 | --zone "$ZONE" \ 182 | --tags "phabricator" \ 183 | --scopes sql,cloud-platform \ 184 | 2>&1 | logger || exit 1 185 | fi 186 | status_ok 187 | 188 | status " Waiting for compute instance to activate..." 189 | while [ -z "$(gcloud_instances list | grep "\b$VM_NAME\b")" ]; do 190 | sleep 10 191 | done 192 | status_ok 193 | 194 | VM_INTERNAL_IP=$(gcloud_instances list | grep "\b$VM_NAME\b" | awk '{print $4}') 195 | VM_EXTERNAL_IP=$(gcloud_instances list | grep "\b$VM_NAME\b" | awk '{print $5}') 196 | 197 | status "internal IP: $VM_INTERNAL_IP. external IP: $VM_EXTERNAL_IP. " 198 | status_ok 199 | 200 | status "SQL..." 201 | if [ -z "$(gcloud_sql_instances list 2> /dev/null | grep "\b$SQL_NAME\b")" ]; then 202 | status_no 203 | 204 | # TODO: Once 2nd generation SQL is out of beta, move to the db-n1-standard-1 tier. 205 | 206 | status "- Creating $SQL_NAME 1st generation SQL database (may take a few minutes)..." 207 | gcloud_sql_instances create "$SQL_NAME" \ 208 | --activation-policy=ALWAYS \ 209 | --authorized-networks="$VM_EXTERNAL_IP" \ 210 | --assign-ip \ 211 | --backup-start-time="00:00" \ 212 | --gce-zone "$ZONE" \ 213 | --tier="D1" \ 214 | --pricing-plan="PACKAGE" \ 215 | --database-flags="sql_mode=STRICT_ALL_TABLES,ft_min_word_len=3,max_allowed_packet=33554432" \ 216 | 2>&1 | logger || exit 1 217 | fi 218 | status_ok 219 | 220 | status " Verifying SQL..." 221 | SQL_INSTANCE_NAME=$(gcloud_sql_instances list | grep "\b$SQL_NAME\b" | cut -d " " -f 1) 222 | if [ -z "${SQL_INSTANCE_NAME}" ]; then 223 | status_no 224 | 225 | echo "Failed to load the name of the Cloud SQL instance to use for Phabricator" 226 | exit 1 227 | fi 228 | status_ok 229 | 230 | checkdisk() { 231 | name=$1 232 | status "$name disk..." 233 | if [ -z "$(gcloud_disks list | grep "\b$name\b")" ]; then 234 | status_no 235 | 236 | status "- Creating..." 237 | gcloud_disks create \ 238 | "$name" \ 239 | --size "200" \ 240 | --type "pd-standard" \ 241 | 2>&1 | logger || exit 1 242 | fi 243 | status_ok 244 | 245 | status "$name disk attached..." 246 | if [ -z "$(gcloud_instances describe $VM_NAME --zone=$ZONE | grep "$name")" ]; then 247 | status_no 248 | 249 | status "- Attaching..." 250 | gcloud_attach_disk \ 251 | --disk "$name" \ 252 | 2>&1 | logger || exit 1 253 | fi 254 | status_ok 255 | } 256 | 257 | checkdisk "git-repos" 258 | checkdisk "file-storage" 259 | 260 | status "Allow internal http..." 261 | if [ -z "$(gcloud_firewall_rules list | grep "\b$NETWORK_NAME\b" | grep "\ballow-internal-http\b")" ]; then 262 | status_no 263 | 264 | REGION=$(gcloud_zones list | grep $ZONE | awk '{print $2}') 265 | SUBNET_RANGE=$(gcloud_networks subnets list | grep $NETWORK_NAME | grep $REGION | awk '{print $4}') 266 | 267 | status "- Creating firewall rule 'allow-internal-http'..." 268 | gcloud_firewall_rules create \ 269 | allow-internal-http \ 270 | --allow "tcp:8080" \ 271 | --network "$NETWORK_NAME" \ 272 | --source-ranges "$SUBNET_RANGE" \ 273 | 2>&1 | logger || exit 1 274 | fi 275 | status_ok 276 | 277 | # Sub-domain configuration 278 | 279 | if [ ! -z "$CUSTOM_DOMAIN" ]; then 280 | status "Allow git ssh..." 281 | if [[ ! -z "$GIT_SUBDOMAIN" && -z "$(gcloud_firewall_rules list | grep "\b$NETWORK_NAME\b" | grep "\ballow-git-ssh\b")" ]]; then 282 | status_no 283 | 284 | status "- Creating firewall rule 'allow-git-ssh'..." 285 | gcloud_firewall_rules create \ 286 | allow-git-ssh \ 287 | --allow "tcp:22" \ 288 | --network "$NETWORK_NAME" \ 289 | --target-tags "phabricator" \ 290 | 2>&1 | logger || exit 1 291 | fi 292 | status_ok 293 | 294 | status "Allow notifications..." 295 | if [[ ! -z "$NOTIFICATIONS_SUBDOMAIN" && -z "$(gcloud_firewall_rules list | grep "\b$NETWORK_NAME\b" | grep "\ballow-notifications\b")" ]]; then 296 | status_no 297 | 298 | status "- Creating firewall rule 'allow-notifications'..." 299 | gcloud_firewall_rules create \ 300 | allow-notifications \ 301 | --allow "tcp:22280" \ 302 | --network "$NETWORK_NAME" \ 303 | --target-tags "phabricator" \ 304 | 2>&1 | logger || exit 1 305 | fi 306 | status_ok 307 | 308 | # Use the custom domain 309 | PHABRICATOR_URL=$CUSTOM_DOMAIN 310 | TOP_LEVEL_DOMAIN=$(echo $CUSTOM_DOMAIN | rev | cut -d'.' -f-2 | rev) 311 | 312 | status "DNS for $CUSTOM_DOMAIN..." 313 | if [ -z "$(gcloud_dns_zones list 2> /dev/null | grep "\b$DNS_NAME\b")" ]; then 314 | status_no 315 | 316 | status "- Creating DNS zone $DNS_NAME..." 317 | gcloud_dns_zones create \ 318 | --dns-name="$TOP_LEVEL_DOMAIN" \ 319 | --description="phabricator DNS" \ 320 | $DNS_NAME \ 321 | 2>&1 | logger || exit 1 322 | fi 323 | status_ok 324 | 325 | # Abort any existing transaction 326 | abort_existing_dns() { 327 | if gcloud_dns_records transaction describe >> /dev/null 2>&1; then 328 | gcloud_dns_records transaction abort 2>&1 | logger 329 | fi 330 | } 331 | 332 | status " Mailgun TXT..." 333 | if [ -z "$(gcloud_dns_records list | grep "\bTXT\b" | grep "mailgun.org")" ]; then 334 | status_no 335 | 336 | abort_existing_dns 337 | 338 | status "- Adding DNS TXT entry 'v=spf1 include:mailgun.org ~all'..." 339 | gcloud_dns_records transaction start \ 340 | 2>&1 | logger || exit 1 341 | gcloud_dns_records transaction add \ 342 | --name="$TOP_LEVEL_DOMAIN." \ 343 | --ttl=21600 \ 344 | --type=TXT "v=spf1 include:mailgun.org ~all" \ 345 | 2>&1 | logger || exit 1 346 | gcloud_dns_records transaction execute \ 347 | 2>&1 | logger || exit 1 348 | fi 349 | status_ok 350 | 351 | status " Mailgun SMTP TXT..." 352 | if [ -z "$(gcloud_dns_records list | grep "\bTXT\b" | grep "k=rsa;")" ]; then 353 | status_no 354 | 355 | abort_existing_dns 356 | 357 | status "- Adding DNS SMTP TXT entry 'smtp._domainkey'..." 358 | gcloud_dns_records transaction start \ 359 | 2>&1 | logger || exit 1 360 | gcloud_dns_records transaction add \ 361 | --name="smtp._domainkey.$TOP_LEVEL_DOMAIN." \ 362 | --ttl=21600 \ 363 | --type=TXT "$MAILGUN_SMTP_DOMAIN_KEY_TXT" \ 364 | 2>&1 | logger || exit 1 365 | gcloud_dns_records transaction execute \ 366 | 2>&1 | logger || exit 1 367 | fi 368 | status_ok 369 | 370 | status " Mailgun CNAME..." 371 | if [ -z "$(gcloud_dns_records list | grep "\bCNAME\b" | grep "mailgun.org")" ]; then 372 | status_no 373 | 374 | abort_existing_dns 375 | 376 | status "- Adding DNS CNAME entry email.$PHABRICATOR_URL. 'mailgun.org'..." 377 | gcloud_dns_records transaction start \ 378 | 2>&1 | logger || exit 1 379 | gcloud_dns_records transaction add \ 380 | --name="email.$TOP_LEVEL_DOMAIN." \ 381 | --ttl=21600 \ 382 | --type=CNAME "mailgun.org." \ 383 | 2>&1 | logger || exit 1 384 | gcloud_dns_records transaction execute \ 385 | 2>&1 | logger || exit 1 386 | fi 387 | status_ok 388 | 389 | status " Mailgun MX..." 390 | if [ -z "$(gcloud_dns_records list | grep "\bMX\b" | grep "mxa.mailgun.org")" ]; then 391 | status_no 392 | 393 | abort_existing_dns 394 | 395 | status "- Adding DNS MX entries for mailgun..." 396 | gcloud_dns_records transaction start \ 397 | 2>&1 | logger || exit 1 398 | gcloud_dns_records transaction add \ 399 | --name="$TOP_LEVEL_DOMAIN." \ 400 | --ttl=21600 \ 401 | --type=MX "10 mxa.mailgun.org." "10 mxb.mailgun.org." \ 402 | 2>&1 | logger || exit 1 403 | gcloud_dns_records transaction execute \ 404 | 2>&1 | logger || exit 1 405 | fi 406 | status_ok 407 | 408 | ensure_record() { 409 | recordtype=$1 410 | status " $recordtype record..." 411 | if [[ -z "$(gcloud_dns_records list | grep "\b$recordtype\b" | grep "^$TOP_LEVEL_DOMAIN.")" ]]; then 412 | status_no 413 | 414 | abort_existing_dns 415 | 416 | status "- Adding $recordtype entry..." 417 | gcloud_dns_records transaction start \ 418 | 2>&1 | logger || exit 1 419 | gcloud_dns_records transaction add \ 420 | --name="$TOP_LEVEL_DOMAIN." \ 421 | --ttl=21600 \ 422 | --type="$recordtype" \ 423 | "${@:2}" \ 424 | 2>&1 | logger || exit 1 425 | gcloud_dns_records transaction execute \ 426 | 2>&1 | logger || exit 1 427 | fi 428 | status_ok 429 | } 430 | 431 | if [ ! -z "$CUSTOM_DOMAIN_A_RECORD" ]; then 432 | ensure_record A $CUSTOM_DOMAIN_A_RECORD 433 | fi 434 | 435 | if [ ! -z "$CUSTOM_DOMAIN_AAAA_RECORD" ]; then 436 | ensure_record AAAA $CUSTOM_DOMAIN_AAAA_RECORD 437 | fi 438 | 439 | ensure_subdomain() { 440 | name="$1" 441 | status " Subdomain: $name..." 442 | if [[ -z "$(gcloud_dns_records list | grep "\bA\b" | grep "\b$name.$TOP_LEVEL_DOMAIN.")" ]]; then 443 | status_no 444 | 445 | abort_existing_dns 446 | 447 | status "- Adding DNS subdomain entry $name..." 448 | gcloud_dns_records transaction start \ 449 | 2>&1 | logger || exit 1 450 | gcloud_dns_records transaction add \ 451 | --name="$name.$TOP_LEVEL_DOMAIN." \ 452 | --ttl=60 \ 453 | --type=A \ 454 | $VM_EXTERNAL_IP \ 455 | 2>&1 | logger || exit 1 456 | gcloud_dns_records transaction execute \ 457 | 2>&1 | logger || exit 1 458 | fi 459 | status_ok 460 | } 461 | 462 | if [ ! -z "$NOTIFICATIONS_SUBDOMAIN" ]; then 463 | ensure_subdomain "$NOTIFICATIONS_SUBDOMAIN" 464 | fi 465 | if [ ! -z "$GIT_SUBDOMAIN" ]; then 466 | ensure_subdomain "$GIT_SUBDOMAIN" 467 | fi 468 | 469 | exit 1 470 | fi 471 | 472 | pushd $DIR/nginx >> /dev/null 473 | 474 | # TODO: Look into Network Load Balancing as an alternative to App Engine for nginx routing. 475 | # https://cloud.google.com/compute/docs/load-balancing/network/example 476 | 477 | status "Generating nginx.conf..." 478 | if [ -z "$PHABRICATOR_URL" ]; then 479 | status_no 480 | 481 | echo "No phabricator URL found...bailing out" 482 | exit 1 483 | fi 484 | 485 | if [ -z "$VM_INTERNAL_IP" ]; then 486 | status_no 487 | 488 | echo "No internal IP found...bailing out" 489 | exit 1 490 | fi 491 | 492 | cp nginx.conf.template nginx.conf 493 | sed -i.bak -e s/\\\$PHABRICATOR_URL/$PHABRICATOR_URL/ nginx.conf 494 | sed -i.bak -e s/\\\$PHABRICATOR_ALTERNATE_URL/$PHABRICATOR_VERSIONED_URL/ nginx.conf 495 | sed -i.bak -e s/\\\$PHABRICATOR_IP/$VM_INTERNAL_IP/ nginx.conf 496 | rm nginx.conf.bak 497 | status_ok 498 | 499 | COMPUTED_NGINX_SHA=$(find . -type f \( -exec shasum {} \; \) | shasum | cut -d' ' -f1) 500 | 501 | status "nginx deployed..." 502 | if [ "$COMPUTED_NGINX_SHA" != "$NGINX_SHA" ]; then 503 | status_no 504 | 505 | status "deploying nginx..." 506 | gcloud_appengine deploy --version=1 --promote app.yaml || exit 1 507 | 508 | popd >> /dev/null 509 | 510 | NOW=$(date) 511 | 512 | if [ $(grep -c "^NGINX_SHA" $CONFIG_PATH) -ne 0 ]; then 513 | sed -i'.tmp' -e "s/^NGINX_SHA=.*/NGINX_SHA=$COMPUTED_NGINX_SHA # Generated $NOW/" $CONFIG_PATH 514 | rm -rf $CONFIG_PATH.tmp 515 | else 516 | echo >> $CONFIG_PATH 517 | echo "NGINX_SHA=$COMPUTED_NGINX_SHA # Generated $NOW" >> $CONFIG_PATH 518 | fi 519 | 520 | pushd $DIR/nginx >> /dev/null 521 | fi 522 | status_ok 523 | 524 | popd >> /dev/null 525 | 526 | open_ssh 527 | 528 | ################ SERVER COMMANDS START HERE ################ 529 | 530 | remote_exec "sudo apt-get -qq update && sudo apt-get install -y git" || exit 1 531 | remote_exec "if [ ! -d phabricator ]; then git clone $GITHUB_REPO; else cd phabricator; git fetch; git rebase origin/master; fi" || exit 1 532 | remote_exec "cd /opt;bash ~/phabricator/vm/install.sh $SQL_NAME http://$PHABRICATOR_URL http://$PHABRICATOR_VERSIONED_URL" || exit 1 533 | 534 | # Configure the startup script. 535 | remote_exec "cp ~/phabricator/vm/startup.sh .; \ 536 | sed -i.bak -e s/#TOP_LEVEL_DOMAIN=/TOP_LEVEL_DOMAIN=$TOP_LEVEL_DOMAIN/ startup.sh; \ 537 | sed -i.bak -e s/#VM_NAME=/VM_NAME=$VM_NAME/ startup.sh; \ 538 | sed -i.bak -e s/#DNS_NAME=/DNS_NAME=$DNS_NAME/ startup.sh" || exit 1 539 | 540 | if [ ! -z "$MAILGUN_APIKEY" ]; then 541 | remote_exec "cd /opt;bash ~/phabricator/vm/configure_mailgun.sh $PHABRICATOR_URL $MAILGUN_APIKEY" || exit 1 542 | fi 543 | 544 | if [ ! -z "$CUSTOM_DOMAIN" ]; then 545 | if [ ! -z "$GIT_SUBDOMAIN" ]; then 546 | remote_exec "sed -i.bak -e s/#GIT_SUBDOMAIN=/GIT_SUBDOMAIN=$GIT_SUBDOMAIN/ startup.sh" || exit 1 547 | 548 | remote_exec "cd /opt;bash ~/phabricator/vm/configure_ssh.sh $GIT_SUBDOMAIN.$TOP_LEVEL_DOMAIN" || exit 1 549 | 550 | # Tag the machine so that we know how to ssh into it in the future 551 | if [ -z "$(gcloud_instances describe $VM_NAME --zone=$ZONE | grep "ssh-222")" ]; then 552 | gcloud_instances add-tags --zone=$ZONE $VM_NAME --tags ssh-222 553 | fi 554 | 555 | port="222" 556 | fi 557 | 558 | if [ ! -z "$NOTIFICATIONS_SUBDOMAIN" ]; then 559 | remote_exec "sed -i.bak -e s/#NOTIFICATIONS_SUBDOMAIN=/NOTIFICATIONS_SUBDOMAIN=$NOTIFICATIONS_SUBDOMAIN/ startup.sh" || exit 1 560 | 561 | remote_exec "cd /opt;sudo bash ~/phabricator/vm/configure_notifications.sh http://$NOTIFICATIONS_SUBDOMAIN.$TOP_LEVEL_DOMAIN" || exit 1 562 | remote_exec "cd /opt/phabricator;sudo su aphlict -c './bin/aphlict restart'" || exit 1 563 | fi 564 | fi 565 | 566 | # Install the startup script. 567 | remote_exec "sudo /google/google-cloud-sdk/bin/gcloud --quiet compute instances add-metadata $VM_NAME --metadata-from-file startup-script=startup.sh" || exit 1 568 | 569 | echo "Visit http://$PHABRICATOR_URL to set up your phabricator instance." 570 | echo "Visit https://console.developers.google.com/permissions/projectpermissions?project=$PROJECT to configure your project's permissions." 571 | echo "Setup complete." 572 | --------------------------------------------------------------------------------