diff --git a/README.md b/README.md index b0b48a7..b0be47d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![AppScale Logo](http://www.appscale.com/img/appscale-logo.png) +![AppScale Logo](http://www.appscale.com/img/logos/appscale-logo-349x83.jpg) # Appscake - Web Frontend for AppScale Tools # @@ -12,47 +12,87 @@ are not familiar with general cloud principles or those who are not comfortable working with a traditional command line interface can get started with deploying AppScale clouds. -AppsCake has been developed using the Python programming language and is -based on Django. +AppsCake has been developed using the Python programming language and uses Django. ## Prerequisites ## - Python 2.7 -- Django 1.5 (get the tar ball here: https://www.djangoproject.com/download/1.5.1/tarball/) +- Django 1.5 (get the tar ball here: https://www.djangoproject.com/download/1.5.1/tarball/) or + run "easy_install django" - Git - Expect (http://downloads.sourceforge.net/project/expect/Expect/5.45/expect5.45.tar.gz or ```apt-get install expect```) -# Tools Install Process ## -Run ```bash get_tools.sh```. +## Install Process ## +Run ```bash get_tools.sh```, which downloads the AppScale Tools and puts them in the +appscake directory. -### On an AppScale Image ### -Install the tools for python2.7 by going into appscale/tools/src_install and running -```bash appscale_install.sh``` - -### For Mac OSX ### -Install the tools by going into appscale-tools/osx and running -```bash appscale_install.sh``` - -### For Debian based systems ### -Install the tools by going into appscale-tools/debian and running -```bash appscale_install.sh``` - -### Source Install ### -Install the tools for python2.7 by going into appscale/tools/src_install -```bash appscale_install.sh``` +Next, install the tools dependencies by going into the appscake/debian directory +and running +```bash appscake_dependencies_install.sh``` # Running AppsCake # ```python2.7 manage.py runserver localhost:8000``` Go to http://localhost:8000 with a browser. -If you are running AppsCake on the image that you will be starting AppScale: +If you are running AppsCake on the image that you will be starting AppScale, start AppsCake by running: ```/usr/local/Python-2.7.3/python manage.py runserver :8090``` -Go to http://:8090 with a browser. +Go to `http://:8090` with a browser. ### Issues ### -Contact us if you have problems at: support@appscale.com or visit our IRC channel #appscale on freenode.net. +Contact us if you have problems at support@appscale.com or visit our IRC channel, #appscale on freenode.net. + +*** + +# AppsCake w/ virtualenv # +Prerequisites: Python 2.6+, pip/easy_install + +1. Installing virtualenv/virtualenvwrapper via the terminal: +``` +sudo pip install virtualenvwrapper +``` + +2. Create the AppsCake virtualenv working directory: +``` +virtualenv appscake-env +``` + +3. Open newly created virtualenv working directory: +``` +cd appscake +``` + +4. Activate the AppsCake virtualenv: +``` +source bin/activate +``` + +5. Installing dependencies for debian systems -- for Mac OSX ensure git and expect are installed in your path (if not use Homebrew to install): +``` +sudo apt-get install git-core +sudo apt-get install expect +``` + +6. Cloning the AppsCake repository: +``` +git clone https://github.com/AppScale/appscake.git +``` + +7. Installing the AppScale Tools and requirements: +``` +cd appscake +bash get_tools.sh +sudo pip install -r requirements.txt +``` + +8. Running AppsCake: +``` +python manage.py runserver +``` + +9. Navigate to the URL returned from the command above to use AppsCake. + License @@ -61,3 +101,7 @@ This software is licensed under the [New BSD License][BSD]. For more information, read the file ``LICENSE``. [BSD]: http://opensource.org/licenses/BSD-3-Clause + + +[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/DrOctogon/appscake/trend.png)](https://bitdeli.com/free "Bitdeli Badge") + diff --git a/appscake.god b/appscake.god new file mode 100644 index 0000000..59a7f7f --- /dev/null +++ b/appscake.god @@ -0,0 +1,5 @@ +God.watch do |w| + w.name = "appscake" + w.start = "cd /root/appscake && python manage.py runserver `python get_my_ip.py`:8000" + w.keepalive +end \ No newline at end of file diff --git a/debian/appscake_dependencies_install.sh b/debian/appscake_dependencies_install.sh new file mode 100644 index 0000000..d1a2cee --- /dev/null +++ b/debian/appscake_dependencies_install.sh @@ -0,0 +1,26 @@ +echo "Installing setuptools if needed." +set +e +hash easy_install > /dev/null 2>&1 +if [ $? -ne 0 ]; then + set -e + echo "setuptools not found - installing." + mkdir -pv downloads + cd downloads + wget https://s3.amazonaws.com/appscale-build/setuptools-0.6c11.tar.gz + tar zxvf setuptools-0.6c11.tar.gz + pushd setuptools-0.6c11 + python setup.py install + popd + rm -fr setuptools-0.6c11* +fi +set -e + +easy_install termcolor +easy_install SOAPpy +easy_install pyyaml +easy_install boto==2.6 +easy_install argparse +easy_install django +easy_install google-api-python-client +apt-get -y install expect + diff --git a/generate_nginx_config.py b/generate_nginx_config.py new file mode 100644 index 0000000..627df99 --- /dev/null +++ b/generate_nginx_config.py @@ -0,0 +1,13 @@ +import jinja2 +import os +import socket + +my_public_ip = os.popen("curl -L http://metadata/computeMetadata/v1beta1/instance/network-interfaces/0/access-configs/0/external-ip").read() +my_private_ip = socket.gethostbyname(socket.gethostname()) + +template_contents = open('/root/appscake/nginx_config').read() +template = jinja2.Template(template_contents) +rendered_template = template.render(my_private_ip=my_private_ip, my_public_ip=my_public_ip) + +with open('/etc/nginx/sites-available/default', 'w') as file_handle: + file_handle.write(rendered_template) \ No newline at end of file diff --git a/generate_ssl_cert.py b/generate_ssl_cert.py new file mode 100644 index 0000000..8b9c930 --- /dev/null +++ b/generate_ssl_cert.py @@ -0,0 +1,58 @@ +import subprocess + +class NginxCert(): + + # The path on the local filesystem where we can read and write + # AppScale deployment metadata. + LOCAL_NGINX_PATH = "/etc/nginx/" + + + @classmethod + def get_certificate_location(cls, keyname): + """Determines the location where the self-signed certificate for this + AppScale deployment can be found. + + Args: + keyname: A str that indicates the name of the SSH keypair that + uniquely identifies this AppScale deployment. + Returns: + A str that indicates where the self-signed certificate can be found. + """ + return cls.LOCAL_NGINX_PATH + keyname + "-cert.pem" + + + @classmethod + def get_private_key_location(cls, keyname): + """Determines the location where the private key used to sign the + self-signed certificate used for this AppScale deployment can be found. + + Args: + keyname: A str that indicates the name of the SSH keypair that + uniquely identifies this AppScale deployment. + Returns: + A str that indicates where the private key can be found. + """ + return cls.LOCAL_NGINX_PATH + keyname + "-key.pem" + + + @classmethod + def generate_ssl_cert(cls, keyname): + """Generates a self-signed SSL certificate that AppScale services can use + to encrypt traffic with. + + Args: + keyname: A str representing the SSH keypair name used for this AppScale + deployment. + is_verbose: A bool that indicates if we want to print out the certificate + generation to stdout or not. + """ + subprocess.call("openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 " + \ + "-subj '/C=US/ST=Foo/L=Bar/O=AppScale/CN=appscale.com' " + \ + "-keyout {0} -out {1}".format(NginxCert.get_private_key_location(keyname), + NginxCert.get_certificate_location(keyname)), shell=True) + +def main(): + NginxCert.generate_ssl_cert('appscake') + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/get_my_ip.py b/get_my_ip.py new file mode 100644 index 0000000..90aad4d --- /dev/null +++ b/get_my_ip.py @@ -0,0 +1,2 @@ +import socket +print socket.gethostbyname(socket.gethostname()) diff --git a/get_tools.sh b/get_tools.sh index 61f256e..18c958e 100644 --- a/get_tools.sh +++ b/get_tools.sh @@ -1,2 +1,2 @@ # Fetches the latest and greatest AppScale tools from github modified for Appscake. -git clone https://github.com/AppScale/appscale-tools.git appscale-tools --branch appscake +git clone https://github.com/AppScale/appscale-tools.git appscale-tools diff --git a/nginx_config b/nginx_config new file mode 100644 index 0000000..e2498c9 --- /dev/null +++ b/nginx_config @@ -0,0 +1,31 @@ +upstream app_server { + server {{ my_public_ip }}:8000 fail_timeout=0; +} + +server { + listen 80; + server_name {{ my_public_ip }}; + rewrite ^ https://$server_name$request_uri? permanent; +} + +server { + listen 443 ssl; + server_name {{ my_public_ip }}; + ssl on; + ssl_certificate /etc/nginx/appscake-cert.pem; + ssl_certificate_key /etc/nginx/appscake-key.pem; + client_max_body_size 4G; + keepalive_timeout 5; + root /root/appscake; + + location / { + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $http_host; + proxy_redirect off; + if (!-f $request_filename) { + proxy_pass http://app_server; + break; + } + } + error_page 500 502 503 504 /500.html; +} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e6ba62c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +boto +django +soappy +pyyaml +termcolor + diff --git a/src/appscale_tools_thread.py b/src/appscale_tools_thread.py index 442f8ba..2c1e284 100644 --- a/src/appscale_tools_thread.py +++ b/src/appscale_tools_thread.py @@ -7,6 +7,12 @@ import sys import threading +sys.path.append(os.path.join(os.path.dirname(__file__),".")) +# Since AppScake doesn't run the tools on the main thread, use a fake +# implementation of the signal class. +import fake_signal +sys.modules['signal'] = __import__('fake_signal').FakeSignal + sys.path.append(os.path.join(os.path.dirname(__file__),"../appscale-tools/lib")) from appscale_tools import AppScaleTools from custom_exceptions import BadConfigurationException @@ -106,7 +112,8 @@ def appscale_down(self): if self.deployment_type == CLOUD: terminate_args.extend(["--EC2_SECRET_KEY", self.ec2_secret, "--EC2_ACCESS_KEY", self.ec2_access, - "--EC2_URL", self.ec2_url]) + "--EC2_URL", self.ec2_url, + "--test"]) try: logging.info("Starting terminate instances.") @@ -360,6 +367,7 @@ def run_advance_cloud_deploy(self): "--machine", self.machine, "--ips_layout", self.ips_yaml_b64, "--group", self.keyname, + "--force", "--EC2_SECRET_KEY", self.ec2_secret, "--EC2_ACCESS_KEY", self.ec2_access, "--EC2_URL", self.ec2_url]) @@ -376,6 +384,7 @@ def run_simple_cloud_deploy(self): "--machine", self.machine, "--max", self.max_nodes, "--group", self.keyname, + "--force", "--EC2_SECRET_KEY", self.ec2_secret, "--EC2_ACCESS_KEY", self.ec2_access, "--EC2_URL", self.ec2_url]) diff --git a/src/fake_signal.py b/src/fake_signal.py new file mode 100644 index 0000000..e9d93b1 --- /dev/null +++ b/src/fake_signal.py @@ -0,0 +1,21 @@ +class FakeSignal(): + """ + FakeSignal implements the methods of the signal class that + AppScale uses in the AppControllerClient class. The reason we + have a FakeSignal class is because signal can only run on the + main thread, and AppsCake does not run the AppScale tools on + the main thread. + """ + + # Class variable that AppScale uses, needs to be mocked out. + SIGALRM = 1 + + + @staticmethod + def alarm(arg1): + pass + + + @staticmethod + def signal(arg1, arg2): + pass