Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Initial PHP support from AppFog #105

Closed
wants to merge 17 commits into from

2 participants

@cardmagic

Initial Cloud Foundry support for PHP using standard Apache + mod_php tools. The technology for these pull requests comes out of the knowledge and expertise of running phpfog.com

Related pull requests:

cloudfoundry-attic/vmc#29

cloudfoundry-attic/vcap-tests#6

@pbozeman

Pulled.

@pbozeman pbozeman closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 8, 2011
  1. Support for deploying PHP applications through a standard Apache conf…

    Lucas Carlson authored
    …iguration with built-in support for APC, memcache, mongo and redis.
Commits on Jul 15, 2011
  1. Adding RAM limits to php.ini

    Lucas Carlson authored
  2. Adding php specs

    Lucas Carlson authored
  3. Adding Lucas Carlson to the AUTHORS list

    Lucas Carlson authored
Commits on Aug 12, 2011
  1. Support for deploying PHP applications through a standard Apache conf…

    Lucas Carlson authored
    …iguration with built-in support for APC, memcache, mongo and redis.
  2. Adding RAM limits to php.ini

    Lucas Carlson authored
  3. Adding php specs

    Lucas Carlson authored
  4. Adding Lucas Carlson to the AUTHORS list

    Lucas Carlson authored
  5. Merge branch 'initial-php-support' of github.com:phpfog/vcap into ini…

    Lucas Carlson authored
    …tial-php-support
Commits on Aug 20, 2011
  1. Fixing typo in apache start.sh for php

    Lucas Carlson authored
Commits on Aug 23, 2011
  1. Adding php postgres bindings

    Lucas Carlson authored
  2. Merge branch 'initial-php-support' of github.com:phpfog/vcap into ini…

    Lucas Carlson authored
    …tial-php-support
Commits on Aug 24, 2011
  1. Fixing php ini support

    Lucas Carlson authored
  2. Merge branch 'master' into initial-php-support

    Lucas Carlson authored
    Conflicts:
    	cloud_controller/app/models/app.rb
This page is out of date. Refresh to see the latest.
View
1  AUTHORS
@@ -32,3 +32,4 @@
- Vadim Spivak { email: vspivak@vmware.com }
- Wilson Bilkovich { email: wilsonb@vmware.com }
- Woon Jung { email: whj@vmware.com }
+- Lucas Carlson { email: lucas@phpfog.com, company: "PHP Fog" }
View
4 cloud_controller/app/models/app.rb
@@ -19,8 +19,8 @@ class App < ActiveRecord::Base
AppStates = %w[STOPPED STARTED]
PackageStates = %w[PENDING STAGED FAILED]
- Runtimes = %w[ruby18 ruby19 java node erlangR14B02]
- Frameworks = %w[sinatra rails3 java_web spring grails node otp_rebar lift unknown]
+ Runtimes = %w[ruby18 ruby19 java node php erlangR14B02]
+ Frameworks = %w[sinatra rails3 java_web spring grails node php otp_rebar lift unknown]
validates_presence_of :name, :framework, :runtime
View
1  cloud_controller/spec/fixtures/apps/phpinfo/source/index.php
@@ -0,0 +1 @@
+<?php phpinfo(); ?>
View
55 cloud_controller/spec/staging/php_spec.rb
@@ -0,0 +1,55 @@
+require 'spec_helper'
+
+describe "A PHP application being staged" do
+ before do
+ app_fixture :phpinfo
+ end
+
+ it "is packaged with a startup script" do
+ stage :php do |staged_dir|
+ executable = '%VCAP_LOCAL_RUNTIME%'
+ start_script = File.join(staged_dir, 'startup')
+ start_script.should be_executable_file
+ webapp_root = staged_dir.join('app')
+ webapp_root.should be_directory
+ script_body = File.read(start_script)
+ script_body.should == <<-EXPECTED
+#!/bin/bash
+env > env.log
+ruby resources/generate_apache_conf $VCAP_APP_PORT $HOME $VCAP_SERVICES 512m
+cd apache
+bash ./start.sh > ../logs/stdout.log 2> ../logs/stderr.log &
+STARTED=$!
+echo "$STARTED" >> ../run.pid
+echo "#!/bin/bash" >> ../stop
+echo "kill -9 $STARTED" >> ../stop
+echo "kill -9 $PPID" >> ../stop
+chmod 755 ../stop
+wait $STARTED
+ EXPECTED
+ end
+ end
+
+ it "requests the specified amount of memory from PHP" do
+ environment = { :resources => {:memory => 256} }
+ stage(:php, environment) do |staged_dir|
+ start_script = File.join(staged_dir, 'startup')
+ start_script.should be_executable_file
+ script_body = File.read(start_script)
+ script_body.should == <<-EXPECTED
+#!/bin/bash
+env > env.log
+ruby resources/generate_apache_conf $VCAP_APP_PORT $HOME $VCAP_SERVICES 256m
+cd apache
+bash ./start.sh > ../logs/stdout.log 2> ../logs/stderr.log &
+STARTED=$!
+echo "$STARTED" >> ../run.pid
+echo "#!/bin/bash" >> ../stop
+echo "kill -9 $STARTED" >> ../stop
+echo "kill -9 $PPID" >> ../stop
+chmod 755 ../stop
+wait $STARTED
+ EXPECTED
+ end
+ end
+end
View
17 cloud_controller/staging/apache_common/apache.rb
@@ -0,0 +1,17 @@
+require 'nokogiri'
+require 'fileutils'
+
+class Apache
+ def self.resource_dir
+ File.join(File.dirname(__FILE__), 'resources')
+ end
+
+ def self.prepare(dir)
+ FileUtils.cp_r(resource_dir, dir)
+ output = %x[cd #{dir}; unzip -q resources/apache.zip]
+ raise "Could not unpack Apache: #{output}" unless $? == 0
+ FileUtils.rm(File.join(dir, "resources", "apache.zip"))
+ dir
+ end
+
+end
View
BIN  cloud_controller/staging/apache_common/resources/apache.zip
Binary file not shown
View
88 cloud_controller/staging/apache_common/resources/generate_apache_conf
@@ -0,0 +1,88 @@
+#!/usr/bin/env ruby
+
+# This script executes at app startup time because the
+# actual appserver port must be in the apache conf.
+
+apache_port = ARGV[0]
+base_dir = ARGV[1]
+vcap_services = ARGV[2]
+php_ram = ARGV[3]
+exit 1 unless apache_port && base_dir && vcap_services && php_ram
+
+require 'erb'
+output_path = "apache/sites-available/default"
+
+template = <<-ERB
+<VirtualHost *:<%= apache_port %>>
+ ServerAdmin webmaster@localhost
+ DocumentRoot <%= base_dir %>/app
+ ErrorLog ${APACHE_LOG_DIR}/error.log
+ CustomLog ${APACHE_LOG_DIR}/access.log combined
+ SetEnv VCAP_SERVICES <%= vcap_services %>
+</VirtualHost>
+ERB
+
+template = ERB.new(template)
+File.open(File.expand_path(output_path), 'wb') do |file|
+ file.puts(template.result(binding))
+end
+
+system "cd apache/sites-enabled && ln -s ../sites-available/default 000-default && cd ../.."
+
+output_path = 'apache/envvars'
+
+template = <<-ERB
+unset HOME
+export APACHE_BASEDIR=<%= base_dir %>/apache
+export APACHE_RUN_USER=www-data
+export APACHE_RUN_GROUP=www-data
+export APACHE_PID_FILE=<%= base_dir %>/run.pid
+export APACHE_RUN_DIR=$APACHE_BASEDIR/run/apache2
+export APACHE_LOCK_DIR=$APACHE_BASEDIR/lock/apache2
+export APACHE_LOG_DIR=<%= base_dir %>/logs
+export LANG=C
+export PHP_INI_SCAN_DIR=$APACHE_BASEDIR/php
+ERB
+
+template = ERB.new(template)
+File.open(File.expand_path(output_path), 'wb') do |file|
+ file.puts(template.result(binding))
+end
+
+output_path = 'apache/ports.conf'
+
+template = <<-ERB
+NameVirtualHost *:<%= apache_port %>
+Listen <%= apache_port %>
+ERB
+
+template = ERB.new(template)
+File.open(File.expand_path(output_path), 'wb') do |file|
+ file.puts(template.result(binding))
+end
+
+output_path = 'apache/start.sh'
+
+template = <<-ERB
+#!/bin/bash
+source <%= base_dir %>/apache/envvars
+/usr/sbin/apache2 -d <%= base_dir %>/apache -f <%= base_dir %>/apache/apache2.conf -D FOREGROUND
+ERB
+
+template = ERB.new(template)
+File.open(File.expand_path(output_path), 'wb') do |file|
+ file.puts(template.result(binding))
+end
+
+`cp -r /etc/php5/conf.d/* apache/php`
+
+output_path = 'apache/php/memory.ini'
+
+template = <<-ERB
+memory_limit = <%= php_ram %>
+ERB
+
+template = ERB.new(template)
+File.open(File.expand_path(output_path), 'wb') do |file|
+ file.puts(template.result(binding))
+end
View
22 cloud_controller/staging/manifests/php.yml
@@ -0,0 +1,22 @@
+---
+name: "php"
+runtimes:
+ - "php":
+ description: "PHP 5"
+ version: "5.3"
+ executable: "php"
+ default: true
+app_servers:
+ - "apache":
+ description: "Apache"
+ executable: "false"
+ default: true
+detection:
+ - "*.php": true
+staged_services:
+ - "name": "mysql"
+ "version": "*"
+ - "name": "postgresql"
+ "version": "*"
+
+# vim: filetype=yaml
View
41 cloud_controller/staging/php/plugin.rb
@@ -0,0 +1,41 @@
+require File.expand_path('../../apache_common/apache', __FILE__)
+
+class PhpPlugin < StagingPlugin
+ def framework
+ 'php'
+ end
+
+ def stage_application
+ Dir.chdir(destination_directory) do
+ create_app_directories
+ Apache.prepare(destination_directory)
+ copy_source_files
+ create_startup_script
+ end
+ end
+
+ # The Apache start script runs from the root of the staged application.
+ def change_directory_for_start
+ "cd apache"
+ end
+
+ def start_command
+ "bash ./start.sh"
+ end
+
+ private
+
+ def startup_script
+ vars = environment_hash
+ generate_startup_script(vars) do
+ <<-PHPEOF
+env > env.log
+ruby resources/generate_apache_conf $VCAP_APP_PORT $HOME $VCAP_SERVICES #{application_memory}m
+ PHPEOF
+ end
+ end
+
+ def apache_server_root
+ File.join(destination_directory, 'apache')
+ end
+end
View
7 cloud_controller/staging/php/stage
@@ -0,0 +1,7 @@
+#!/usr/bin/env ruby
+require File.expand_path('../../common', __FILE__)
+plugin_class = StagingPlugin.load_plugin_for('php')
+plugin_class.validate_arguments!
+plugin_class.new(*ARGV).stage_application
+
+# vim: ts=2 sw=2 filetype=ruby
View
5 dea/config/dea.yml
@@ -43,6 +43,11 @@ runtimes:
version: 1.6.0
version_flag: '-version'
environment:
+ php:
+ executable: php
+ version: 5.3.[2-6]
+ version_flag: '-v'
+ environment:
erlangR14B02:
executable: /var/vcap/runtimes/erlang-R14B02/bin/erl
version: ".* 5.8.3"
View
51 docs/php.md
@@ -0,0 +1,51 @@
+# PHP Support
+
+## Architecture
+
+PHP applications are deployed using Apache and mod_php. For each CloudFoundry instance of the application, an Apache instance is started.
+
+## Demo: Installing Wordpress ##
+The Wordpress CMS can be run using CloudFoundry PHP support with very minimal changes.
+
+Steps to get the application to run:
+
+1. <code>curl -O http://wordpress.org/latest.tar.gz</code>
+2. <code>tar -xzf latest.tar.gz</code>
+3. <code>rm latest.tar.gz</code>
+4. <code>cd wordpress</code>
+5. <code>echo "<?php" > wp-salt.php</code>
+6. <code>curl https://api.wordpress.org/secret-key/1.1/salt/ >> wp-salt.php</code>
+7. Create wp-config.php, and set it to:
+
+ <?php
+ $services = getenv("VCAP_SERVICES");
+ $services_json = json_decode($services,true);
+ $mysql_config = $services_json["mysql-5.1"][0]["credentials"];
+
+ // ** MySQL settings from resource descriptor ** //
+ define('DB_NAME', $mysql_config["name"]);
+ define('DB_USER', $mysql_config["user"]);
+ define('DB_PASSWORD', $mysql_config["password"]);
+ define('DB_HOST', $mysql_config["hostname"]);
+ define('DB_PORT', $mysql_config["port"]);
+
+ define('DB_CHARSET', 'utf8');
+ define('DB_COLLATE', '');
+ define ('WPLANG', '');
+ define('WP_DEBUG', false);
+
+ require('wp-salt.php');
+
+ $table_prefix = 'wp_';
+
+ /* That's all, stop editing! Happy blogging. */
+
+ /** Absolute path to the WordPress directory. */
+ if ( !defined('ABSPATH') )
+ define('ABSPATH', dirname(__FILE__) . '/');
+
+ /** Sets up WordPress vars and included files. */
+ require_once(ABSPATH . 'wp-settings.php');
+8. <code>vmc push wordpresscf --url wordpresscf.vcap.me -n</code>
+9. <code>vmc create-service mysql --bind wordpresscf</code>
+10. Visit http://wordpresscf.vcap.me and enjoy your Wordpress install!
View
36 setup/vcap_setup
@@ -255,6 +255,38 @@ if [[ $DEA == true || $ALL == true ]]; then
rm -fr node-v$NODE_VERSION
fi
+ # For PHP
+ if [[ $PLATFORM == 'Linux' ]]; then
+ apt-get install -qqy libpcre3 libpcre3-dev apache2 php5 php5-mysql php5-mysqli php5-pgsql php5-dev php-pear php5-gd libapr1 libaprutil1 php5-common php5-curl php5-mcrypt php5-imagick php5-xmlrpc zend-framework php5-imap
+
+ /etc/init.d/apache2 stop
+ update-rc.d -f apache2 remove
+
+ pear channel-discover pear.phpunit.de
+ pear channel-discover pear.symfony-project.com
+ pear channel-discover components.ez.no
+ pear install phpunit/PHPUnit
+ yes | pecl install apc
+ yes | pecl install memcache
+ yes | pecl install mongo
+ git clone git://github.com/owlient/phpredis.git
+ cd phpredis
+ phpize
+ ./configure
+ make && make install
+ cd ..
+ rm -rf phpredis
+
+ echo "extension=apc.so" > /etc/php5/apache2/conf.d/cf.ini
+ echo "extension=memcache.so" >> /etc/php5/apache2/conf.d/cf.ini
+ echo "extension=mongo.so" >> /etc/php5/apache2/conf.d/cf.ini
+ echo "extension=mysql.so" >> /etc/php5/apache2/conf.d/cf.ini
+ echo "extensions=pgsql.so" >> /etc/php5/apache2/conf.d/cf.ini
+
+ elif [[ $PLATFORM == 'MacOSX' ]]; then
+ echo -e "\033[31mFIXME: Implement for MacOSX \033[0m"
+ fi
+
ERLANG_VERSION=R14B02
if [ ! -d "/var/vcap/runtimes/erlang-$ERLANG_VERSION" ]; then
@@ -293,6 +325,10 @@ if [[ $DEA == true || $ALL == true ]]; then
node -v
echo ""
+ echo -e "\nPHP should now be installed -->"
+ php -v
+ echo ""
+
echo -e "\nErlang should now be installed -->"
erl -version
echo ""
Something went wrong with that request. Please try again.