Commit 20ce8427 by IBM Bluemix

Import from JazzHub

parents
#!/bin/sh
rm -f ./public/goweb.zip
zip -r ../goweb.zip ./* > /dev/null 2>&1
mv ../goweb.zip ./public/
echo "This assume that you are already logged in a Bluemix instance"
# Uncomment if you do not want to use the manifest file
#cf push goweb -b https://github.com/michaljemala/cloudfoundry-buildpack-go --no-manifest
# This uses the manifest.yml file in the root folder
cf push
\ No newline at end of file
The MIT License (MIT)
Copyright (c) 2014 Michele Crudele
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
\ No newline at end of file
# Goweb Application
Simple application demonstrating how CloudFoundry-based clouds can host web applications written in [Go language](http://golang.org/).
It does simple *maths* like calculating prime factors of a number and listing the first N prime numbers.
You can use the following clouds for testing:
- [IBM Bluemix](https://www.bluemix.net)
- [Pivotal](https://run.pivotal.io).
You can play with an instance of the app running in Bluemix at [this link](http://goweb.mybluemix.net/),
as well as getting the code from JazzHub at [this link](https://hub.jazz.net/project/mcrudele/Goweb).
Once you get the code you can run *Goweb* directly on your desktop: the only requirement is the `Go Programming Language`
binary distribution that you can download from the official site.
Thereafter the instructions on how to deploy a Go App on CloudFoundry-based clouds. Feel free to take them as example
for deploying your own app.
## Creating the deployment artifacts
Once you have done with the code, you need to create a couple of files on the root folder of your app before deploying it in the cloud:
- `.godir`
The file should contain the desired name of the final go libary. E.g.:
`example.com/goweb`
NOTE - CloudFoundry may ignore files beginning with `.`. In that case rename
`.godir` to `_godir`
- `Procfile`
The file contains the command to start the web app. E.g.:
`web: goweb`
## Deploying the app
Unless your cloud provide support for Go language, you need to use a custom
*buildpack* to deploy a Go web application.
The one used in the example below has been modified to work with CloudFoundry-based clouds by [Michal Jemala](https://github.com/michaljemala).
Though this is an experimental Cloudfoundry buildpack for Go, it does its job well (at least on Bluemix and Pivotal clouds).
So, login to your cloud and run the `cf` command below from the root folder of your application:
```
cf push goweb -b https://github.com/michaljemala/cloudfoundry-buildpack-go
```
To deploy this *Goweb* application run the script `.push-this.sh` that you should find on the root folder: it performs some preparation steps before
calling the `cf push`.
```
./.push-this.sh
```
This is what you should get to your console:
```
...
0 of 1 instances running, 1 down
0 of 1 instances running, 1 starting
1 of 1 instances running
App started
Showing health and status for app goweb in org your.name-org / space dev as your.name@your.mail...
OK
requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: goweb.mybluemix.net
state since cpu memory disk
#0 running 2014-02-04 06:18:38 PM 0.0% 1.5M of 256M 8.7M of 1G
```
<?xml version="1.0" encoding="UTF-8"?>
<project basedir="." default="build" name="Goweb">
<property name="debuglevel" value="source,lines,vars" />
<property name="target" value="1.5" />
<property name="source" value="1.5" />
<property name="warname" value="${ant.project.name}.war" />
<property name="artifact_dir" value="${ARCHIVE_DIR}"/>
<path id="classpathDir">
<pathelement location="bin" />
</path>
<target name="init">
<mkdir dir="bin" />
<copy includeemptydirs="false" todir="bin">
<fileset dir="src">
<exclude name="**/*.java" />
</fileset>
</copy>
<copy includeemptydirs="false" todir="bin">
<fileset dir="WebContent" />
</copy>
<echo message="Copy files to ${artifact_dir} for deployment"/>
<copy todir="${artifact_dir}">
<fileset file="manifest.yml" />
</copy>
</target>
<target name="clean">
<delete dir="bin" />
</target>
<target name="build" depends="build-project,build-war" />
<target name="cleanall" depends="clean" />
<target name="build-project" depends="init">
<echo message="${ant.project.name}: ${ant.file}" />
<javac debug="true" debuglevel="${debuglevel}" destdir="bin" source="${source}" target="${target}" includeantruntime="false">
<src path="src" />
<classpath>
<pathelement path="${classpathDir}"/>
<fileset dir="lib">
<include name="**/*.jar"/>
</fileset>
</classpath>
</javac>
</target>
<target name="build-war" depends="build-project">
<war destfile="${artifact_dir}/${warname}" basedir="bin" />
</target>
</project>
package main
import (
"html/template"
"net/http"
"log"
"os"
"strconv"
"fmt"
)
type Results struct {
Title string // Indicates success or failure
Message string // the result message
Details string // the details of the message
}
const (
DEFAULT_PORT = "4001"
primesHeader = `
<html>
<head>
<title>Go Sample App - {{.Title}}</title>
<link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>
<h1>{{.Title}}</h1>
<p><div>{{.Message}}</div></p>
<div>
`
primesFooter = `
</div>
<p><div><a href="/">Back home</a></div></p>
</body>
</html>
`
)
var resultsTemplate = template.Must(template.ParseFiles("templates/results.html"))
var primesHeaderTemplate = template.Must(template.New("header").Parse(primesHeader))
var primesFooterTemplate = template.Must(template.New("footer").Parse(primesFooter))
// Display the index html page
//
func publicHandler(w http.ResponseWriter, r *http.Request) {
log.Println(">> publicHandler")
defer log.Println("<< publicHandler")
if r.Method != "GET" {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
path := "public" + r.URL.Path
if path == "public/" {
path = "public/index.html"
}
log.Printf("Serving file: %+v\n", path)
http.ServeFile(w, r, path)
}
// Put in another file and make it a library
//
type InvalidArgument uint
func (n InvalidArgument) Error() string {
return fmt.Sprintf("Invalid argument number %d", n)
}
type Factor struct {
Num uint64
Pow uint
}
// Return a sorted array of Factor, where each element is the
// prime factor with the associated power
//
func PrimeFactors(n uint64) ([]Factor, error) {
if n < 2 {
return nil, InvalidArgument(n)
}
factors := make([]Factor, 0)
var i uint
for i=0; n%2 == 0; i++ { n /= 2 }
if i > 0 { factors = append(factors, Factor{Num: 2, Pow:i}) }
for p:=uint64(3); (p*p) <= n; p+=2 {
for i=0; n%p == 0; i++ { n /= p }
if i > 0 { factors = append(factors, Factor{Num: p, Pow:i}) }
}
if n > 1 { factors = append(factors, Factor{Num: n, Pow:1}) }
return factors, nil
}
// Calculate first n prime numbers and send them
// over a channel
//
func FirstNPrimeNumbers(n uint, ch chan uint64) (error) {
log.Println(">> FirstNPrimeNumbers")
defer log.Println("<< FirstNPrimeNumbers")
if n < 3 {
return InvalidArgument(n)
}
primes := make([]uint64, n)
primes[0] = 2
primes[1] = 3
primes[2] = 5
cprime := uint64(7)
ch <- primes[0]
ch <- primes[1]
ch <- primes[2]
for i:=uint(3); i<n; cprime+=2 {
if (cprime%5) != 0 {
isprime := true
for p := 0; (primes[p]*primes[p]) <= cprime; p++ {
if (cprime%primes[p]) == 0 {
isprime = false
break
}
}
if isprime {
primes[i] = cprime
i++
ch <- cprime
}
}
}
return nil
}
func prettyPrintPrimeFactors(n uint64, f []Factor) string {
s := fmt.Sprintf("Prime Factors of %+v = ", n)
for i, _ := range f {
if i==0 {
s += fmt.Sprintf("%v^%v", f[i].Num, f[i].Pow)
} else {
s += fmt.Sprintf(" * %v^%v", f[i].Num, f[i].Pow)
}
}
return s
}
// Rest handler to get prime factors of a number
// GET /primefactors?number=[the number]
//
func primeFactorsHandler(w http.ResponseWriter, r *http.Request) {
log.Println(">> primeFactorsHandler")
defer log.Println("<< primeFactorsHandler")
if r.Method != "POST" {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
num_s := r.FormValue("number")
log.Printf("Got number from input form: %+v\n", num_s)
var results *Results
if num, err := strconv.Atoi(num_s); err==nil {
// calculate prime factors
if num > 0 {
if factors, err := PrimeFactors(uint64(num)); err == nil {
ss := prettyPrintPrimeFactors(uint64(num), factors)
results = &Results{Title: "Success", Message: ss}
} else {
results = &Results{Title: "Error",
Message: fmt.Sprintf("Cannot calculate prime factors of %+v", num),
Details: err.Error()}
}
} else {
results = &Results{Title: "Error",
Message: fmt.Sprintf("Cannot calculate prime factors of %+v", num),
Details: "It must be greather than zero."}
}
} else {
results = &Results{Title: "Error",
Message: "Invalid number",
Details: err.Error()}
}
renderResults(w, results)
}
func primeNumbersHandler(w http.ResponseWriter, r *http.Request) {
log.Println(">> primeNumbersHandler")
defer log.Println("<< primeNumbersHandler")
if r.Method != "POST" {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
num_s := r.FormValue("limit")
log.Printf("Got limit from input form: %+v\n", num_s)
var results *Results
if num, err := strconv.Atoi(num_s); err==nil {
// calculate first limit prime numbers
if num > 0 {
ch := make(chan uint64, 1)
quit := make(chan *Results, 1)
go func() {
if err := FirstNPrimeNumbers(uint(num), ch); err != nil {
results = &Results{Title: "Error",
Message: fmt.Sprintf("Cannot calculate first %+v prime numbers", num),
Details: err.Error()}
}
// signal the normal end of calculation
quit <- results
}()
writeHead := true
tab := 0
for {
select {
case v := <- ch:
if writeHead {
// do write header
primesHeaderTemplate.Execute(w, &Results{Title: "Success", Message: fmt.Sprintf("First %+v prime numbers:\n", num)})
writeHead = false
}
fmt.Fprintf(w, "%+v ", v)
if tab++; tab > 14 {
fmt.Fprintf(w, "<br>")
tab = 0
}
case res := <- quit:
if res == nil {
primesFooterTemplate.Execute(w, nil)
} else {
renderResults(w, results)
}
return
}
}
} else {
results = &Results{Title: "Error",
Message: fmt.Sprintf("Cannot calculate first %+v prime numbers", num),
Details: "Limit must be greather than zero."}
}
} else {
results = &Results{Title: "Error",
Message: "Invalid number",
Details: err.Error()}
}
if results != nil {
log.Printf("Renedring results %+v\n", results) // debug only
renderResults(w, results)
}
}
func renderResults(w http.ResponseWriter, results *Results) {
log.Println(">> renderResults")
defer log.Println("<< renderResults")
if err := resultsTemplate.ExecuteTemplate(w, "results.html", results); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func main() {
// Configure the standard logger
log.SetFlags(log.Lmicroseconds|log.Ldate|log.Lshortfile)
log.Println(">> GoWeb")
defer log.Println("<< GoWeb")
var port string
if port = os.Getenv("VCAP_APP_PORT"); len(port)==0 {
log.Printf("Warning, VCAP_APP_PORT not set. Defaulting to %+v\n", DEFAULT_PORT)
port = DEFAULT_PORT
}
http.HandleFunc("/primefactors", primeFactorsHandler)
http.HandleFunc("/primenumbers", primeNumbersHandler)
http.HandleFunc("/", publicHandler)
log.Printf("Starting GoWeb on port %+v\n", port)
http.ListenAndServe(":" + port, nil)
}
---
applications:
- name: samplego
memory: 32M
domain: mybluemix.net
instances: 1
host: ${random-word}
path: .
buildpack: https://github.com/michaljemala/cloudfoundry-buildpack-go
<!DOCTYPE html>
<html>
<head>
<title>Go Sample App</title>
<link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>
<h1>Go Sample App</h1>
<p>Welcome to Go Sample Web App.
<p>This is an example web application written in <a href="http://golang.org">Go language</a> running in <a href="http://ng.bluemix.net">BlueMix</a>.
<br>It does some simple <em>maths</em> for you. Check the links below if you want to try.
<p>You can get the source code of this App <a href="/goweb.zip" mimetype="text/plain">here</a>.
<p>You can read how to deploy it in BlueMix <a href="https://hub.jazz.net/project/mcrudele/Goweb/overview">here</a>.
<ul>
<li><a href="/primefactors.html">Calculate the prime factors of a number</a></li>
<li><a href="/primes.html">See prime numbers</a></li>
</ul>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Go Sample App - Prime Factors</title>
<link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>
<h1>Calculate the prime factors of a number</h1>
<div>
<form id="primeFactors" action="/primefactors" method="POST">
<label for="number"> Number: <input id="number" type="number" name="number"></label>
<p></p>
<input type="submit" value="Submit">
</form>
</div>
<p></p><div><a href="/">Back home</a></div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Go Sample App - Prime Numbers</title>
<link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>
<h1>Calculate the first N prime numbers</h1>
<div>
<form id="primeNumbers" action="/primenumbers" method="POST">
<label for="limit"> Limit: <input id="limit" type="number" name="limit"></label>
<p></p>
<input type="submit" value="Submit">
</form>
</div>
<p></p><div><a href="/">Back home</a></div>
</body>
</html>
body {
padding: 50px;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
}
a {
color: #00B7FF;
}
\ No newline at end of file
<html>
<head>
<title>Go Sample App - {{.Title}}</title>
<link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>
<h1>{{.Title}}</h1>
<div>{{.Message}}</div>
<div>{{printf "%s" .Details}}</div>
<p><div><a href="/">Back home</a></div></p>
</body>
</html>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment