A API Namespaces permite-lhe ativar facilmente a multilocação na sua aplicação, bastando selecionar uma string de espaço de nomes para cada inquilino em appengine_config.py através do pacote namespace_manager.
Definir o espaço de nomes atual
Pode obter, definir e validar espaços de nomes através do namespace_manager. O gestor de espaços de nomes permite-lhe definir um espaço de nomes atual para APIs ativadas para espaços de nomes. Configura um espaço de nomes atual antecipadamente através de appengine_config.py, e o datastore e o memcache usam automaticamente esse espaço de nomes.
A maioria dos programadores do App Engine usa o respetivo domínio do Google Workspace (anteriormente denominado G Suite) como o espaço de nomes atual. O Google Workspace permite-lhe implementar a sua app em qualquer domínio que possua, para que possa usar facilmente este mecanismo para configurar diferentes espaços de nomes para diferentes domínios. Em seguida, pode usar esses espaços de nomes separados para segregar os dados nos domínios. Para mais informações, consulte o artigo Mapear domínios personalizados.
O seguinte exemplo de código mostra como definir o espaço de nomes atual para o domínio do Google Workspace que foi usado para mapear o URL. Em particular, esta string é igual para todos os URLs mapeados através do mesmo domínio do Google Workspace.
Para definir um espaço de nomes em Python, use o sistema de configuração do App Engine appengine_config.py
no diretório raiz da sua aplicação. O exemplo simples seguinte demonstra como usar o seu domínio do Google Workspace como o espaço de nomes atual:
from google.appengine.api import namespace_manager
# Called only if the current namespace is not set.
def namespace_manager_default_namespace_for_request():
# The returned string will be used as the Google Apps domain.
return namespace_manager.google_apps_namespace()
Se não especificar um valor para namespace, o espaço de nomes é definido como uma string vazia. A string namespace é arbitrária, mas também está limitada a um máximo de 100 carateres alfanuméricos, pontos, sublinhados e hífenes. Mais explicitamente, as strings de espaço de nomes têm de corresponder à expressão regular [0-9A-Za-z._-]{0,100}.
Por convenção, todos os espaços de nomes que começam por "_" (sublinhado) estão reservados para utilização do sistema. Esta regra do espaço de nomes do sistema não é aplicada, mas pode facilmente deparar-se com consequências negativas indefinidas se não a seguir.
appengine_config.py, consulte o artigo Configuração do módulo Python.
Evitar fugas de dados
Um dos riscos frequentemente associados a apps multi-inquilino é o perigo de fuga de dados entre espaços de nomes. As fugas de dados não intencionais podem surgir de várias origens, incluindo:
- Usar espaços de nomes com APIs do App Engine que ainda não suportam espaços de nomes. Por exemplo, o Blobstore não suporta espaços de nomes. Se usar namespaces com o Blobstore, tem de evitar usar consultas do Blobstore para pedidos de utilizadores finais ou chaves do Blobstore de origens não fidedignas.
- Usar um meio de armazenamento externo (em vez de memcache e datastore), através de
URL Fetchou algum outro mecanismo, sem fornecer um esquema de compartimentalização para espaços de nomes. - Definir um espaço de nomes com base no domínio de email de um utilizador. Na maioria dos casos, não quer que todos os endereços de email de um domínio acedam a um espaço de nomes. A utilização do domínio de email também impede que a sua aplicação utilize um espaço de nomes até o utilizador iniciar sessão.
Implementar espaços de nomes
As secções seguintes descrevem como implementar espaços de nomes com outras ferramentas e APIs do App Engine.
Criar espaços de nomes por utilizador
Algumas aplicações têm de criar espaços de nomes por utilizador. Se quiser compartimentar os dados ao nível do utilizador para utilizadores com sessão iniciada, considere usar o User.user_id(), que devolve um ID exclusivo e permanente para o utilizador. O seguinte exemplo de código demonstra como usar a API Users para este fim:
from google.appengine.api import users
def namespace_manager_default_namespace_for_request():
# assumes the user is logged in.
return users.get_current_user().user_id()
Normalmente, as apps que criam espaços de nomes por utilizador também fornecem páginas de destino específicas a diferentes utilizadores. Nestes casos, a aplicação tem de fornecer um esquema de URL que determine a página de destino a apresentar a um utilizador.
Usar espaços de nomes com o Datastore
Por predefinição, o datastore usa a definição do espaço de nomes atual no gestor de espaços de nomes para pedidos do datastore. A API aplica este espaço de nomes atual a objetos Key ou Query quando são criados. Por conseguinte, tem de ter cuidado se uma aplicação armazenar objetos Key ou Query em formas serializadas, uma vez que o espaço de nomes é preservado nessas serializações.
Se estiver a usar objetos Key e Query desserializados, certifique-se de que têm o comportamento pretendido. A maioria das aplicações simples que usam o armazenamento de dados (put/query/get) sem usar outros mecanismos de armazenamento funciona como esperado definindo o espaço de nomes atual antes de chamar qualquer API do armazenamento de dados.
Os objetos Query e Key demonstram os seguintes comportamentos únicos relativamente aos espaços de nomes:
- Os objetos
QueryeKeyherdam o espaço de nomes atual quando são construídos, a menos que defina um espaço de nomes explícito. - Quando uma aplicação cria um novo
Keya partir de um elemento antecessor, o novoKeyherda o espaço de nomes do elemento antecessor.
O exemplo de código seguinte mostra um controlador de pedidos de amostra que incrementa um contador no arquivo de dados para o espaço de nomes global e um espaço de nomes especificado arbitrariamente.
Usar espaços de nomes com o Memcache
Por predefinição, o memcache usa o espaço de nomes atual do gestor de espaços de nomes para pedidos de memcache. Na maioria dos casos, não precisa de definir explicitamente um espaço de nomes na memcache, e fazê-lo pode introduzir erros inesperados.
No entanto, existem algumas instâncias únicas em que é adequado definir explicitamente um espaço de nomes na memcache. Por exemplo, a sua aplicação pode ter dados comuns partilhados em todos os espaços de nomes (como uma tabela que contenha códigos de países).
O seguinte fragmento de código demonstra como definir explicitamente o espaço de nomes na cache de memória:
Com a API Python para memcache, pode obter o espaço de nomes atual a partir do gestor de espaços de nomes ou defini-lo explicitamente quando cria o serviço memcache.
O exemplo de código seguinte mostra um controlador de pedidos de exemplo que incrementa um contador na memcache para o espaço de nomes global e um espaço de nomes especificado arbitrariamente.
O exemplo abaixo define o espaço de nomes explicitamente quando armazena um valor na memcache:
// Store an entry to the memcache explicitly memcache.add("key", data, namespace='abc')
Usar espaços de nomes com a fila de tarefas
Por predefinição, as filas de envio usam o espaço de nomes atual, conforme definido no gestor de espaços de nomes no momento em que a tarefa foi criada. Na maioria dos casos, não precisa de definir explicitamente um espaço de nomes na fila de tarefas. Se o fizer, pode introduzir erros inesperados.
Os nomes das tarefas são partilhados em todos os namespaces. Não pode criar duas tarefas com o mesmo nome, mesmo que usem espaços de nomes diferentes. Se quiser usar o mesmo nome de tarefa para muitos namespaces, pode simplesmente anexar cada namespace ao nome da tarefa.
Quando uma nova tarefa chama o método add() da fila de tarefas, a fila de tarefas copia o espaço de nomes atual e (se aplicável) o domínio do Google Workspace do gestor do espaço de nomes. Quando a tarefa é executada, o espaço de nomes atual e o espaço de nomes do Google Workspace são restaurados.
Se o espaço de nomes atual não estiver definido no pedido de origem (por outras palavras, se get_namespace() devolver ''), pode usar set_namespace() para definir o espaço de nomes atual para a tarefa.
Existem algumas instâncias únicas em que é adequado definir explicitamente um espaço de nomes para uma tarefa que funciona em todos os espaços de nomes. Por exemplo, pode criar uma tarefa que agregue estatísticas de utilização em todos os espaços de nomes. Em seguida, pode definir explicitamente o espaço de nomes da tarefa. O seguinte exemplo de código demonstra como definir explicitamente os espaços de nomes com a fila de tarefas.
Usar espaços de nomes com o Blobstore
O Blobstore não está segmentado por espaço de nomes. Para preservar um espaço de nomes no Blobstore, tem de aceder ao Blobstore através de um suporte de armazenamento que tenha conhecimento do espaço de nomes (atualmente, apenas memcache, datastore e fila de tarefas). Por exemplo, se o Key de um blob estiver armazenado numa entidade de banco de dados, pode aceder ao mesmo com um Key ou um Query do banco de dados que tenha conhecimento do espaço de nomes.
Se a aplicação estiver a aceder ao Blobstore através de chaves armazenadas no armazenamento com reconhecimento de espaço de nomes, o próprio Blobstore não precisa de ser segmentado por espaço de nomes. As aplicações têm de evitar fugas de blobs entre espaços de nomes através do seguinte:
- Não usar
BlobInfo.gql()para pedidos de utilizadores finais. Pode usar consultas BlobInfo para pedidos administrativos (como gerar relatórios sobre todos os blobs de aplicações), mas usá-las para pedidos de utilizadores finais pode resultar em fugas de dados, porque todos os registos BlobInfo não estão compartimentados por espaço de nomes. - Não usar chaves do Blobstore de origens não fidedignas.
Definir espaços de nomes para consultas do Datastore
Na Google Cloud consola, pode definir o espaço de nomes para consultas do Datastore.
Se não quiser usar o predefinido, selecione o espaço de nomes que quer usar no menu pendente.
Usar espaços de nomes com o carregador em massa
O carregador em massa suporta uma flag --namespace=NAMESPACE que lhe permite especificar o espaço de nomes a usar. Cada espaço de nomes é processado separadamente e, se quiser aceder a todos os espaços de nomes, tem de iterar através deles.
Usar espaços de nomes com a Pesquisa
Quando cria uma nova instância de Index, esta é atribuída ao espaço de nomes atual por predefinição:
# set the current namespace
namespace_manager.set_namespace("aSpace")
index = search.Index(name="myIndex")
# index namespace is now fixed to "aSpace"
Também pode atribuir um espaço de nomes explicitamente no construtor:
index = search.Index(name="myIndex", namespace="aSpace")
Depois de criar uma especificação de índice, não é possível alterar o respetivo espaço de nomes:
# change the current namespace
namespace_manager.set_namespace("anotherSpace")
# the namespaceof 'index' is still "aSpace" because it was bound at create time
index.search('hello')