Skip to content

Instantly share code, notes, and snippets.

@cesarkawakami
Last active August 29, 2015 14:04
Show Gist options
  • Save cesarkawakami/c54b8707127de514e64a to your computer and use it in GitHub Desktop.
Save cesarkawakami/c54b8707127de514e64a to your computer and use it in GitHub Desktop.
application: sample
version: one
runtime: go
api_version: go1
skip_files:
- script.go
handlers:
- url: /_ah/remote_api
script: _go_app
login: admin
- url: /.*
script: _go_app
package hello
import (
_ "appengine/remote_api"
"fmt"
"net/http"
)
func init() {
http.HandleFunc("/", handler)
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello, world!")
}
$ goapp deploy -application pndtest4
01:07 AM Application: pndtest4 (was: sample); version: one
01:07 AM Host: appengine.google.com
01:07 AM
Starting update of app: pndtest4, version: one
01:07 AM Getting current resource limits.
Email: [email protected]
Password for [email protected]:
01:07 AM Scanning files on local disk.
01:07 AM Cloning 2 application files.
01:07 AM Uploading 2 files and blobs.
01:07 AM Uploaded 2 files and blobs
01:07 AM Compilation starting.
01:07 AM Compilation: 1 files left.
01:07 AM Compilation completed.
01:07 AM Starting deployment.
01:07 AM Checking if deployment succeeded.
01:07 AM Deployment successful.
01:07 AM Checking if updated app version is serving.
01:07 AM Completed update of app: pndtest4, version: one
$ goapp run ./script.go -host one-dot-pndtest4.appspot.com -email [email protected] -password_file [omitted] -kind_name SampleEntity delete
2014/08/06 01:08:15 appengine: not running under devappserver2; using some default configuration
2014/08/06 01:08:16 Successfully deleted 0 keys
$ goapp run ./script.go -host one-dot-pndtest4.appspot.com -email [email protected] -password_file [omitted] -kind_name SampleEntity add
2014/08/06 01:08:21 appengine: not running under devappserver2; using some default configuration
2014/08/06 01:08:25 Successfully created 40 entities
$ goapp run ./script.go -host one-dot-pndtest4.appspot.com -email [email protected] -password_file [omitted] -kind_name SampleEntity delete
2014/08/06 01:08:30 appengine: not running under devappserver2; using some default configuration
2014/08/06 01:08:30 Failed during query to get keys: API error 1 (datastore_v3: BAD_REQUEST): invalid handle: 4904724477798395918
exit status 1
$ goapp run ./script.go -host one-dot-pndtest4.appspot.com -email [email protected] -password_file [omitted] -kind_name SampleEntity delete_wi
th_limit
2014/08/06 01:08:37 appengine: not running under devappserver2; using some default configuration
2014/08/06 01:08:38 Successfully deleted 40 keys
$ goapp run ./script.go -host one-dot-pndtest4.appspot.com -email [email protected] -password_file [omitted] -kind_name SampleEntity delete
2014/08/06 01:08:44 appengine: not running under devappserver2; using some default configuration
2014/08/06 01:08:44 Successfully deleted 0 keys
package main
import (
"appengine/datastore"
"appengine/remote_api"
"errors"
"flag"
"io/ioutil"
"log"
"net/http"
"net/http/cookiejar"
"net/url"
"regexp"
"strings"
)
const NUM_ENTITIES_TO_INSERT = 40
const QUERY_FETCH_LIMIT = 1000
var (
host = flag.String("host", "", "hostname of application")
email = flag.String("email", "", "email of an admin user for the application")
passwordFile = flag.String("password_file", "", "file which contains the user's password")
kindName = flag.String("kind_name", "", "name of the kind (an empty one) to be used")
)
func main() {
flag.Parse()
mode := flag.Arg(0)
if *host == "" || *email == "" || *passwordFile == "" || *kindName == "" || flag.Arg(0) == "" {
log.Fatalf("-host, -email, -passwordFile, -kindName and (add|delete|delete_with_limit) are required")
}
raw_password, err := ioutil.ReadFile(*passwordFile)
if err != nil {
log.Fatalf("Failed while reading password file %a: %v", *passwordFile, err)
}
password := strings.TrimSpace(string(raw_password))
client := clientLoginClient(*host, *email, password)
context, err := remote_api.NewRemoteContext(*host, client)
if err != nil {
log.Fatalf("Failed to create context: %v", err)
}
switch mode {
case "delete":
keys, err := datastore.NewQuery(*kindName).
KeysOnly().
GetAll(context, nil)
if err != nil {
log.Fatalf("Failed during query to get keys: %v", err)
}
if err := datastore.DeleteMulti(context, keys); err != nil {
log.Fatalf("Failed during key deletion: %v", err)
}
log.Printf("Successfully deleted %v keys", len(keys))
case "delete_with_limit":
keys, err := datastore.NewQuery(*kindName).
Limit(QUERY_FETCH_LIMIT).
KeysOnly().
GetAll(context, nil)
if err != nil {
log.Fatalf("Failed during query to get keys: %v", err)
}
if err := datastore.DeleteMulti(context, keys); err != nil {
log.Fatalf("Failed during key deletion: %v", err)
}
log.Printf("Successfully deleted %v keys", len(keys))
case "add":
entities := make([]datastore.PropertyList, NUM_ENTITIES_TO_INSERT)
keys := make([]*datastore.Key, NUM_ENTITIES_TO_INSERT)
for i := 0; i < NUM_ENTITIES_TO_INSERT; i++ {
keys[i] = datastore.NewIncompleteKey(context, *kindName, nil)
}
keys, err := datastore.PutMulti(context, keys, entities)
if err != nil {
log.Fatalf("Failed while inserting entities: %v", err)
}
log.Printf("Successfully created %v entities", len(keys))
}
}
// Blatantly copied from demos/remote_api/datastore_info.go
func clientLoginClient(host, email, password string) *http.Client {
jar, err := cookiejar.New(nil)
if err != nil {
log.Fatalf("failed to make cookie jar: %v", err)
}
client := &http.Client{
Jar: jar,
}
v := url.Values{}
v.Set("Email", email)
v.Set("Passwd", password)
v.Set("service", "ah")
v.Set("source", "Misc-remote_api-0.1")
v.Set("accountType", "HOSTED_OR_GOOGLE")
resp, err := client.PostForm("https://www.google.com/accounts/ClientLogin", v)
if err != nil {
log.Fatalf("could not post login: %v", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if resp.StatusCode != http.StatusOK {
log.Fatalf("unsuccessful request: status %d; body %q", resp.StatusCode, body)
}
if err != nil {
log.Fatalf("unable to read response: %v", err)
}
m := regexp.MustCompile(`Auth=(\S+)`).FindSubmatch(body)
if m == nil {
log.Fatalf("no auth code in response %q", body)
}
auth := string(m[1])
u := &url.URL{
Scheme: "https",
Host: host,
Path: "/_ah/login",
RawQuery: "continue=/&auth=" + url.QueryEscape(auth),
}
// Disallow redirects.
redirectErr := errors.New("stopping redirect")
client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
return redirectErr
}
resp, err = client.Get(u.String())
if urlErr, ok := err.(*url.Error); !ok || urlErr.Err != redirectErr {
log.Fatalf("could not get auth cookies: %v", err)
}
defer resp.Body.Close()
body, err = ioutil.ReadAll(resp.Body)
if resp.StatusCode != http.StatusFound {
log.Fatalf("unsuccessful request: status %d; body %q", resp.StatusCode, body)
}
client.CheckRedirect = nil
return client
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment