Google cloud store desde web2py

60 views
Skip to first unread message

Jacinto Parga

unread,
Dec 29, 2014, 4:56:43 AM12/29/14
to web2py-...@googlegroups.com
Hola.

Estoy probando una aplicación en GAE que requiere la manipulación de ficheros mayores de 1MB. Conozco la solución de la blobstore de google, pero me gustaría saber si hay alguna forma más simple utilizando la google cloud store.

El problema que se me plantea es:
  1. Almacenar los ficheros en la google cloud store, de forma que en mi tabla pueda cambiar el campo upload por la referencia al fichero en la cloud.
  2.  cómo hacer que los ficheros almacenados sean accesibles únicamente por los usuarios que autorice a través de mi aplicación.
Modelo

db.define_table('t_mitabla',
   
Field('f_titulo', type='string', label=T('Titulo')),
   
Field('f_imagen', type='upload',label=T('Imagen')),
   
Field('f_notas', type='text',    label=T('Notas')),
    auth
.signature,
    format
='%(f_titulo)s',
    migrate
=settings.migrate)


Se agracede ayuda.

Luis Díaz

unread,
Jan 11, 2015, 2:59:22 PM1/11/15
to web2py-...@googlegroups.com
saludos, pregunto
cloud store es pago?
yo no pude implementar blobstore
si tienes un avance coméntalo porfa

El día 29 de diciembre de 2014, 5:26, Jacinto Parga
<jpa...@gmail.com> escribió:
> --
> Has recibido este mensaje porque estás suscrito al grupo "web2py-usuarios"
> de Grupos de Google.
> Para anular la suscripción a este grupo y dejar de recibir sus mensajes,
> envía un correo electrónico a web2py-usuari...@googlegroups.com.
> Para acceder a más opciones, visita https://groups.google.com/d/optout.



--
http://diazluis.com
Analista Programador
User Linux 532223

Jacinto Parga

unread,
Jan 12, 2015, 3:58:19 PM1/12/15
to web2py-...@googlegroups.com
Hola, 

es de pago, al menos tienes que tener habilitada la posibilidad de facturación. Hay un límite de almacenamiento gratuito a partir del cual empiezan a facturar: https://cloud.google.com/storage/pricing


Las cosas han cambiado mucho desde entonces. En la documentación de google se explica como utilizar la cloud store dando diversas posibilidades. Cuál es la más adecuada utilizando la Google App Engine con una aplicación desarrollada con web2py es la ayuda que pido desde este post. 

No tengo claro si vale la pena establecer un procedimiento externo para almacenar la información y luego acceder a ella a través de la API con JSON por ejemplo, o si por el contrario hay algún desarrollo para almacenar en la cloud de google directamente desde nuestra aplicación (como a mi me gustaría).

Cualquier ayuda se agradece.

samuel bonill

unread,
Jan 12, 2015, 5:22:22 PM1/12/15
to web2py-...@googlegroups.com
Creo que desde web2py no existe una relación directa con la could de Google; Pero Google provee una libreria escrita en python que interactuar con su infraestructura o puedes interactuar directamente haciendo peticiones a al api Mediante REST..

https://cloud.google.com/storage/docs/json_api/v1/libraries

https://developers.google.com/api-client-library/python/start/get_started

Saludos....

Jacinto Parga

unread,
Jan 21, 2015, 5:44:29 AM1/21/15
to web2py-...@googlegroups.com
Hola

Sí, así es.
Tengo dudas de si este método es el más ágil. Mirando en la documentación del blobstore de Google he encontrado este código completo para manipular los blobs (subirlo y bajarlo) con webapp. Me estoy armando un poco de lio a la hora de traducirlo a web2py, e integrarlo en un formulario. ¿alguna idea?

import os
import urllib
import webapp2

from google.appengine.ext import blobstore
from google.appengine.ext.webapp import blobstore_handlers

class MainHandler(webapp2.RequestHandler):
 
def get(self):
    upload_url
= blobstore.create_upload_url('/upload')
   
self.response.out.write('<html><body>')
   
self.response.out.write('<form action="%s" method="POST" enctype="multipart/form-data">' % upload_url)
   
self.response.out.write("""Upload File: <input type="file" name="file"><br> <input type="submit"
        name="
submit" value="Submit"> </form></body></html>""")

class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
 
def post(self):
    upload_files
= self.get_uploads('file')  # 'file' is file upload field in the form
    blob_info
= upload_files[0]
   
self.redirect('/serve/%s' % blob_info.key())

class ServeHandler(blobstore_handlers.BlobstoreDownloadHandler):
 
def get(self, resource):
    resource
= str(urllib.unquote(resource))
    blob_info
= blobstore.BlobInfo.get(resource)
   
self.send_blob(blob_info)

app
= webapp2.WSGIApplication([('/', MainHandler),
                               
('/upload', UploadHandler),
                               
('/serve/([^/]+)?', ServeHandler)],
                              debug
=True)

samuel bonill

unread,
Jan 21, 2015, 1:18:21 PM1/21/15
to web2py-...@googlegroups.com
Espero que esto te sirva http://www.web2pyslices.com/slice/show/1388/google-app-engine-blobstore-api-support


El 21 de enero de 2015, 5:44, Jacinto Parga <jpa...@gmail.com> escribió:
Cristo viene pronto prepárate !!

samuel bonill

unread,
Jan 21, 2015, 1:19:38 PM1/21/15
to web2py-...@googlegroups.com

Jacinto Parga

unread,
Jan 22, 2015, 4:04:48 AM1/22/15
to web2py-...@googlegroups.com
Muchas gracias Samuel. 

Pero he estado revisando la documentación de google y se decantan claramente por utilizar la google cloud store. Para ello dan dos opciones de acceso, que a mi se me están complicando supongo que por no tener experiencia suficiente con json o con el manejo de algunas librerías.

En primer lugar trato de acceder con urllib2 con un GET como dicen en: https://cloud.google.com/storage/docs/json_api/v1/bucketAccessControls/get#examples

import urllib2

def index():
   
     #Cargamos la página web
    response = urllib2.urlopen(site)
    return locals()
La api_key es correcta, puesto que cuando no la pongo bien el error es 401: UnAuthorized

Lo que obtengo es un error: 

HTTP Error 400: Bad Request


Siguiendo la opción que nos dan en: https://googlecloudplatform.github.io/gcloud-python/storage-api.html
Hago lo siguiente: 
from gcloud import storage

def index():
     bucket = storage.get_bucket(myproject, mybucket_name)
     return locals()
El error que obtengo es: 

 get_bucket() takes exactly 4 arguments (2 given)


Por último intento lo que recomiendan en el ejemplo: https://cloud.google.com/storage/docs/json_api/v1/buckets/get#examples

def index():
    req = client.buckets().get(
        bucket='mybucket',
        fields='location,website(mainPageSuffix)')    # optional
    resp = req.execute()
    return locals()

Aquí el problema lo tengo con la importación, ya que no he encontrado que librería soporta client: 

global name 'client' is not defined

Como ves hay varias posibilidades pero no he acertado con ninguna. A mi la que más me convence es las que utilizan la librería gcloud pero no consigo programarlo adecuadamente.

Se agradece ayuda

Luis Díaz

unread,
Jan 22, 2015, 8:36:34 AM1/22/15
to web2py-...@googlegroups.com

Jacinto Parga

unread,
Jan 22, 2015, 9:05:16 AM1/22/15
to web2py-...@googlegroups.com
Gracias, 

cierto, el último me ha ayudado. De hecho, lo he implementado en una aplicación y funciona perfectamente desde el localhost:

Este es el controlador que he adaptado: 
import argparse
import httplib2
import os
import sys
import json


from apiclient import discovery
from oauth2client import file
from oauth2client import client
from oauth2client import tools

# Define sample variables.
_BUCKET_NAME = 'mybucket'
_API_VERSION = 'v1'

# Parser for command-line arguments.
parser = argparse.ArgumentParser(
    description=__doc__,
    formatter_class=argparse.RawDescriptionHelpFormatter,
    parents=[tools.argparser])

# CLIENT_SECRETS is name of a file containing the OAuth 2.0 information for this
# application, including client_id and client_secret. You can see the Client ID
# and Client secret on the APIs page in the Cloud Console:
CLIENT_SECRETS = os.path.join(os.path.dirname(__file__), 'client_secrets.json')

# Set up a Flow object to be used for authentication.
# Add one or more of the following scopes. PLEASE ONLY ADD THE SCOPES YOU
# NEED. For more information on using scopes please see
FLOW = client.flow_from_clientsecrets(CLIENT_SECRETS,
  scope=[
    ],
    message=tools.message_if_missing(CLIENT_SECRETS))

def index():
  cliente=CLIENT_SECRETS
  flow= FLOW
#    va= main(sys.argv)
   # Parse the command-line flags.
#  flags = parser.parse_args(argv[1:])
    # If the credentials don't exist or are invalid run through the native client
  # flow. The Storage object will ensure that if successful the good
  # credentials will get written back to the file.
  storage = file.Storage('sample.dat')
  credentials = storage.get()
  if credentials is None or credentials.invalid:
    credentials = tools.run_flow(FLOW, storage, flags)

  # Create an httplib2.Http object to handle our HTTP requests and authorize it
  # with our good Credentials.
  http = httplib2.Http()
  http = credentials.authorize(http)

  # Construct the service object for the interacting with the Cloud Storage API.
  service = discovery.build('storage', _API_VERSION, http=http)

  try:
    req = service.buckets().get(bucket=_BUCKET_NAME)
    resp = req.execute()
    print1= json.dumps(resp, indent=2)
   

    fields_to_return = 'nextPageToken,items(name,size,contentType,metadata(my-key))'
    req = service.objects().list(bucket=_BUCKET_NAME, fields=fields_to_return)
    # If you have too many items to list in one request, list_next() will
    # automatically handle paging with the pageToken.
    while req is not None:
      resp = req.execute()
      print2= json.dumps(resp, indent=2)
      req = service.objects().list_next(req, resp)

  except client.AccessTokenRefreshError:
    aviso= "The credentials have been revoked or expired, please re-run the application to re-authorize"
    
  form=SQLFORM(db.gfile)
  return dict(print1=print1,print2=print2, form=form)


Como te decía me va perfecto y consigo el mismo resultado que ejecutando el ejemplo propuesto.

Pero para mi sorpresa, cuando lo subo a la google app engine me sale el siguiente error: 
14:49:26.005
Unable to store in FILE: /base/data/home/apps/s~merebafs/2.381697639759293929/applications/MRBFILE/controllers/default.py Traceback (most recent call last): File "/base/data/home/apps/s~merebafs/2.381697639759293929/gluon/restricted.py", line 224, in restricted exec ccode in environment File "/base/data/home/apps/s~merebafs/2.381697639759293929/applications/MRBFILE/controllers/default.py", line 12, in <module> import httplib2 File "/base/data/home/apps/s~merebafs/2.381697639759293929/gluon/custom_import.py", line 86, in custom_importer raise ImportError, 'Cannot import module %s' % str(e) ImportError: Cannot import module 'httplib2'

No lo entiendo porque supondría que la librería estaría incluida en el propio google app engine, a fin de cuentas la proponen ellos mismos. Si paso de esa librería me sale el mismo error con las siguientes, y además no funciona.??!!!

Ahora, una vez que accedo estóy intentando subir un fichero al bucket desde un formulario...

Luis Díaz

unread,
Jan 22, 2015, 10:59:45 AM1/22/15
to web2py-...@googlegroups.com
revisa la version de web2py que estes usando,
creo que la ultima tenia problemas con los import.

Jacinto Parga

unread,
Jan 23, 2015, 11:28:39 AM1/23/15
to web2py-...@googlegroups.com
Parece ser que es cosa del google app engine, que no soporta httplib2 y sí urlfetch que es la suya. No sé porque la ponen en el ejemplo.
No es de web2py porque ejecuntandolo como localhost o en pythonanywhere me va bien, me falla subirlo a GAE.

Luis Díaz

unread,
Jan 23, 2015, 1:02:30 PM1/23/15
to web2py-...@googlegroups.com
cuando termines porfa monta el codigo del controlador que funcine con gae

yo intente por una semana hacer funcionar mi codigo y tire la toalla.
al final no pude implementar un álbum fotográfico (de archivos de mas
de 2 Mb) usando google como server

Jacinto Parga

unread,
Jan 29, 2015, 4:22:52 PM1/29/15
to web2py-...@googlegroups.com
Hola, 

he conseguido que funcione con el código expuesto en GAE!!  

   respuesta= json.dumps(resp, indent=2)
 

    fields_to_return = 'nextPageToken,items(name,size,contentType,metadata(my-key))'
   req = service.objects().list(bucket=_BUCKET_NAME, fields=fields_to_return)
#Este caso sólo para cuando se tienen muchos buckets. En el ejemplo no hace falta
   # If you have too many items to list in one request, list_next() will
   # automatically handle paging with the pageToken.
   while req is not None:
     resp = req.execute()
     respuesta= json.dumps(resp, indent=2)
     req = service.objects().list_next(req, resp)

  except client.AccessTokenRefreshError:
   respuesta= "The credentials have been revoked or expired, please re-run the application to re-authorize"
   
 return dict(respuesta=respuesta)


Bien, en controlador anterior nos da un listado de los buckets de tu proyecto, el proyecto, así como los permisos de acceso los obtiene de client_secrets.json que es un archivo que debes descargar del apartado de tu consola de google developer: APIS y Autenticación -> Credenciales
Este fichero es un json que debes de almacenar en la carpeta de controllers de tu aplicación en web2py. Es la clave para obtener accesos.
El código para todos los casos (listar, borrar, crear, descargar etc..) es similar al que he puesto (obtenido de https://cloud.google.com/storage/docs/json_api/v1/json-api-python-samples ), sólo varía el código entre las líneas try: y except: con los ejemplos descritos en https://cloud.google.com/storage/docs/json_api/v1/

Por ejemplo, para borrar un objeto tomamos el ejemplo de: https://cloud.google.com/storage/docs/json_api/v1/objects/delete

client.objects().delete(
        bucket
=bucket_name,
       
object=object_name).execute()

La adaptación del código no es complicada, sólo hay que prestar atención a los parámetros que se pasan y que se recuperan. En particular cuando se suben archivos hay que controlar los caracteres no ascii, acentos y ñ me daban problemas.

El truco está más en las librerías que hay que incluir. En localhost no había tenido problema porque instalaba localmente todas las librerías que necesitaba, pero para que funcionara en GAE las he tenido que incluir en la carpeta site-packages En concreto he tenido que añadir: google-api-client, httplib2, oauth2client, uritemplate. Me falta gflags para gestionar los errores de autenticación, pero sin ella me funciona perfecto cuando la autorización es correcta.

Para incluir los ficheros utilizo un SQLFORM.factory, y para los archivo utilizo blobs en lugar de uploads.

En resumen, he utilizado las Google API Libraries, que son sencillas pero llenas de trucos para incorporarlas a la aplicación de la Google App Engine. Si tuviera más tiempo probaría un acceso directo con urllib y urllib2. Estoy haciendo un pequeño servidor para ficheros de trabajo (proyectos, planos, etc) En un par de semanas tendré una versión básica y si quieres entonces te cuento.

Un saludo

Luis Díaz

unread,
Jan 29, 2015, 4:35:59 PM1/29/15
to web2py-...@googlegroups.com
gracias men por el aporte
Reply all
Reply to author
Forward
0 new messages