apim
8 TopicsAlta Disponibilidade e Resiliência com App Gateway e Múltiplos APIMs: Uma Arquitetura Estratégica
Resiliência como Pilar do Azure Well-Architected Framework A resiliência é um dos pilares fundamentais do WAF e desempenha papel crítico na construção de arquiteturas modernas em nuvem. Este artigo explora o design de alta disponibilidade (HA) utilizando a oferta Premium Tier do Azure API Management (APIM) em cenários multi-região ou mesmo intra-região, com foco na aplicação de Availability Zones — uma prática recomendada no pilar de Confiabilidade. A configuração Premium permite que as regiões primária e secundária compartilhem a mesma instância de APIM. No entanto, dependendo dos requisitos de negócio e tolerância a falhas, pode ser estratégico operar com duas instâncias separadas, garantindo continuidade de serviço mesmo diante de falhas regionais ou em uma das instâncias. Essa abordagem está alinhada ao modelo de DR Ativo-Ativo, promovendo tolerância a falhas, escalabilidade horizontal e resiliência operacional, conforme descrito no modelo de maturidade de confiabilidade. A imagem acima representa os componentes do APIM nas regiões primária e secundária. Em cenários com instâncias separadas, esses componentes também estariam presentes em cada região. Já em uma configuração com Availability Zones, os elementos podem escalar dentro da mesma região, conforme a demanda — prática que também se conecta ao pilar de excelência operacional, ao permitir automação e monitoramento contínuo. O fluxo de comunicação entre a API e os serviços de backend pode ocorrer por rotas diretas ou por meio de balanceadores de carga, dependendo do caso de uso. Essa arquitetura inspirou uma solução personalizada para um de nossos clientes, que buscava alta disponibilidade com baixa latência, mesmo em cenários de falha regional. Configuração do APIM como gateway de saída para o cluster de aplicações Press enter or click to view image in full size Em alguns casos, por questões de compliance, não é possível operar fora de um regions específica . Ainda assim, essa arquitetura já proporciona ganhos significativos mesmo dentro da mesma região, como maior resiliência, escalabilidade e eficiência operacional. Visão Geral da Arquitetura Componentes principais: Usuário: Inicia a requisição. WAF: Protege contra ameaças e ataques na borda. AKS: Gerencia APIs e aplicações containerizadas. App Gateway (AppGW): Roteia o tráfego para os APIMs. APIM001 e APIM002: Instâncias do Azure API Management, com IPs distintos e potencialmente em regiões diferentes. Sistemas legados (kubernets / VMS): Integração com sistemas on-premises. Essa arquitetura é interessante, pois, neste caso de uso, o APIM atua como ponto de saída do cluster de aplicações — exatamente o caminho crítico que queremos proteger Com duas instâncias de APIM atrás do AppGW, é possível: Realizar manutenções planejadas em uma instância sem impactar os usuários. Redirecionar o tráfego automaticamente para a instância saudável. Garantir zero downtime, mesmo durante atualizações críticas. Essa abordagem é especialmente útil em ambientes com alta exigência de SLA, como bancos, governo e telecom. Testes Blue-Green com Segurança e Controle A arquitetura permite implementar estratégias Blue-Green com facilidade: Uma instância do APIM pode representar o ambiente “Blue” (produção atual). A outra instância representa o ambiente “Green” (nova versão). O AppGW pode direcionar parte do tráfego para o ambiente Green para testes controlados. Após validação, o tráfego pode ser totalmente migrado para o Green, promovendo a nova versão com segurança. Isso reduz riscos de regressão e permite deploys mais confiáveis Redução de Riscos em Caminhos Críticos Ao distribuir o tráfego entre dois APIMs: Reduz-se o risco de ponto único de falha. A arquitetura se torna mais resiliente a falhas regionais ou de serviço. Em caso de falha de uma instância, o AppGW garante continuidade do serviço. Essa redundância é essencial para caminhos críticos de negócio, como autenticação, transações financeiras ou integrações com sistemas legados. Outros Benefícios Estratégicos ✅ Disaster Recovery Ativo-Ativo As duas instâncias de APIM podem operar em modo ativo-ativo. Em caso de desastre em uma instancia, o tráfego é automaticamente redirecionado. Reduz o tempo de recuperação (RTO) e garante continuidade. ✅ Mitigação de Esgotamento de IPs Com múltiplas instâncias, é possível distribuir o consumo de IPs. Evita gargalos e limitações de rede. ✅ Escalabilidade Regional A arquitetura permite escalar horizontalmente com facilidade. Suporta crescimento de demanda em diferentes regiões. Como configurar o APPGW para uma POC de balanceamento entre dois APIMs O Azure Application Gateway é um balanceador de carga de camada 7 (HTTP/HTTPS) que permite gerenciar o tráfego de aplicações web com inteligência, segurança e escalabilidade. Ele opera com base em um conjunto de configurações como Listeners, Routing Rules, Backend Targets entre outras. Além disso, o Application Gateway oferece recursos avançados como WAF (Web Application Firewall), SSL offloading, redirecionamento baseado em caminho e afinidade de sessão, tornando-o ideal para cenários que exigem alta disponibilidade e proteção contra ameaças web. Press enter or click to view image in full size 📦 Descrição de cada componente do diagrama Listener (porta 80): Detecta conexões de entrada na porta especificada (ex: 80 para HTTP). É o ponto inicial onde o tráfego chega ao gateway. Routing Rule: Define como o tráfego será roteado com base em critérios como URL, cabeçalhos ou métodos. É o cérebro da decisão de encaminhamento. Backend Targets: Especifica os destinos finais para o tráfego, como VMs, instâncias de App Service ou containers. 🔁 Relação com Backend Pools: 1 para N — uma regra pode apontar para vários destinos. Backend Setting: Configurações aplicadas ao tráfego, como tempo de timeout, protocolo (HTTP/HTTPS), e afinidade de sessão. 🔁 Relação com Health Probes: 1 para 1 — cada configuração tem uma sonda associada. Backend Pools: Agrupamento lógico dos destinos (targets). Permite distribuir carga entre múltiplas instâncias. 🔁 Relação com Backend Targets: 1 para N — um pool pode conter vários destinos. Health Probes (path:/status-0123456789abcdef) Verifica a saúde dos destinos usando um caminho específico. Se um destino estiver inativo, ele é automaticamente removido do balanceador. Vamos apresentar algumas telas de configuração e destacar pontos de atenção no Application Gateway (AppGW). Um detalhe importante que acabei não mencionando: à frente do Listener existe uma configuração de Frontend IP, que define se o IP do AppGW será público ou privado. Para facilitar os testes iniciais, recomendo começar com o Frontend IP público,alem disso mantenha o Listener configurado na porta 80. Isso evita complicações com certificados SSL durante os testes. Observe a imagem abaixo: o Frontend IP está corretamente vinculado ao Listener1, como indicado. Essa associação é essencial para garantir que o tráfego seja direcionado corretamente, conforme a configuração do IP público ou privado definida no Frontend. Press enter or click to view image in full size O Listener1, configurado na porta 80, está associado à Rule1, que define como o tráfego será roteado para o backend correspondente. Press enter or click to view image in full size A Rule1 está associada às configurações de Backend Settings, que definem como o tráfego será encaminhado para os recursos de backend — incluindo o pool de servidores, o protocolo, a porta e os critérios de saúde. Press enter or click to view image in full size As Backend Settings do Application Gateway incluem configurações importantes, como “Pick host name from backend target” e a associação a um Custom Probe. Por padrão, o AppGW encaminha ao backend o mesmo cabeçalho HTTP Host recebido do cliente. No entanto, se o serviço ou aplicação no backend exigir um valor específico para o cabeçalho Host, é possível sobrescrevê-lo utilizando essa configuração. Com isso, o Application Gateway passa a usar o host do backend para resolver o balanceamento e validar o probe de integridade, garantindo compatibilidade com serviços que dependem de hostname específico para funcionar corretamente. Press enter or click to view image in full size Perceba que o Health Probe também está vinculado às Backend Settings, e utiliza a configuração “Pick host name from backend settings”. Essa associação é fundamental para garantir que o probe de integridade seja executado corretamente, especialmente em cenários onde o backend exige um cabeçalho Host específico. Ao ativar essa opção, o Application Gateway passa a usar o hostname do backend tanto para o roteamento quanto para a validação do probe, assegurando compatibilidade com serviços que dependem dessa configuração. Press enter or click to view image in full size Esse endereço /status-0123456789abcdef é o endereço de sondagem do apim (helth cehck) do APIM Voltando à Rule1, podemos observar que ela também define o Backend Target, que neste caso aponta para o serviço de backend do APIM (Azure API Management). Essa configuração é essencial para garantir que o tráfego roteado pelo Application Gateway seja direcionado corretamente ao endpoint do APIM, respeitando as regras de roteamento, cabeçalhos e probes definidos nas Backend Settings. Press enter or click to view image in full size Nos Backend Pools, temos o pool de backend do APIM, que contém duas instâncias do serviço Azure API Management. Essa configuração permite distribuir o tráfego entre as instâncias, garantindo alta disponibilidade e escalabilidade para os serviços expostos via AppGW. Press enter or click to view image in full size Do lado do APIM Para observar o processo de balanceamento entre instâncias do APIM (por exemplo, APIM A e APIM B), podemos criar uma API de mock que responda de forma simples, identificando qual instância está respondendo. Principais Objetos do APIM Políticas: São regras aplicadas às requisições HTTP, permitindo manipulações como transformação de payloads, controle de acesso, limitação de chamadas (rate limiting), entre outras. API: Representa um conjunto de operações agrupadas sob um único endpoint. Cada API pode conter múltiplas operações. Operações: São as ações HTTP específicas, como os verbos GET, POST, PUT, DELETE, etc. Cada operação define o comportamento de uma rota dentro da API. Como criar um mock no Azure API Management (APIM) Adicionar uma nova API Acesse o menu lateral e clique em “Add API”. Selecione a opção para criar uma API manualmente. Na caixa de diálogo exibida, preencha os dados necessários (nome, URL base, etc.). eu criei uma APIA, com sufixo apim Press enter or click to view image in full size Definir o response da operação Clique em “add operation” e preencha o verbo como get a url como /moq Após criar a operação desejada, clique na aba “Responses”. Clique em “Add response” e selecione o código 200. Em Content type, escolha application/json. No campo Sample, insira um JSON de exemplo para identificar a instância, como: JSON { "name": "APIMA" } Press enter or click to view image in full size Adicionar a política de mock Vá para a aba “Design” da operação. Na seção Inbound processing, clique em “Add policy”. Selecione a política “Mock response”. Verificação Após salvar, o pipeline da requisição exibirá uma tarja amarela, indicando que o mock está ativo. Press enter or click to view image in full size Repita esse processo para a instância dois. Agora já podemos testar o balanceamento de carga pelo Application Gateway Press enter or click to view image in full size Sincronização das Instâncias com o API OPS Conforme mencionado no início deste artigo, a arquitetura “by the book” foi projetada para utilizar o recurso nativo de multi-região do Azure API Management (APIM), o que elimina a necessidade de esforços adicionais para sincronizar configurações entre instâncias. No entanto, ao optarmos por manter duas instâncias separadas na mesma região, com o objetivo de obter os benefícios citados anteriormente, passamos a ter o desafio de manter ambas sincronizadas — ou seja, com as mesmas APIs, endpoints e políticas. Para atender a essa necessidade de sincronização, utilizaremos o API Ops, que automatiza o processo de publicação e atualização das configurações entre as instâncias, garantindo consistência e reduzindo o risco de divergências operacionais. Press enter or click to view image in full size Resumo do Fluxo de API Ops para Sincronização com o APIM Press enter or click to view image in full size Operadores de API executam o pipeline de extração para sincronizar o repositório Git com a instância do API Management, populando o repositório com os objetos no formato necessário. Se houver alterações detectadas na instância do APIM, é criado um Pull Request (PR) para revisão. Após aprovação, os operadores fazem o merge das mudanças no repositório. Desenvolvedores de API clonam o repositório, criam uma branch e definem as APIs usando especificações OpenAPI ou ferramentas de sua preferência. Quando um desenvolvedor envia alterações para o repositório, um novo PR é gerado para revisão. O PR pode ser aprovado automaticamente ou revisado manualmente, conforme o nível de controle exigido. Após a aprovação e o merge, o pipeline de publicação implanta as alterações na instância do API Management. Os operadores também podem criar ou modificar políticas, diagnósticos, produtos e outros objetos relevantes, e então comitar essas alterações. Após o merge, o pipeline publica as mudanças usando o processo de definição de APIs. Conclusão A adoção de uma arquitetura com App Gateway à frente de múltiplos APIMs, integrada com Akamai WAF, Azure Functions, Key Vault e sistemas legados, oferece uma solução robusta, segura e altamente disponível. Essa abordagem não apenas melhora a experiência do usuário, mas também reduz riscos operacionais e facilita a evolução contínua da plataforma. Referencias Estrutura de Well-Architected do Azure — Microsoft Azure Well-Architected Framework | Microsoft Learn Princípios de design de confiabilidade — Microsoft Azure Well-Architected Framework | Microsoft Learn Modelo de maturidade de confiabilidade — Microsoft Azure Well-Architected Framework | Microsoft Learn Links rápidos de excelência operacional — Microsoft Azure Well-Architected Framework | Microsoft Learn Implantações de API automatizadas usando APIOps — Azure Architecture Center | Microsoft Learn153Views0likes0CommentsAzure AI Foundry Agents - Azure AI and APIM integration
Azure Innovators Hub & Global AI Athens Community presents: Azure AI Foundry Agents All you need to know about building agents with Azure AI and APIM integration! 🛠️ Live Event Highlights Join us for an immersive, hands-on experience where we’ll explore: Creating and managing powerful Agents using Azure AI Foundry Handling threads, messages, and orchestrating Agent behaviors Implementing robust Agentic solutions with real-world scenarios Leveraging ready-to-use Templates to accelerate development Integrating APIM for seamless and secure API connectivity ✨ Whether you're a developer, AI enthusiast, or solution architect, you'll leave with practical skills and an end-to-end Multi-Agent Solution built during the session. 🎯 Perfect for tech professionals, innovators, newcomers and community members looking to deepen their Azure AI expertise and connect with fellow thinkers in Athens. Join Live Event143Views0likes2CommentsAzure API Management with Call Chain of Backend APIs
The backend can be rest api or soap api. The call scenario: We can integrate APIs to Azure API Management services and implement policies in API Manager to achieve this goal. Please refer to Policies Step 1 First, we need to identify what APIs are required to aggregate and their input parameters. In my case, I had two APIs; one gives profile details and the other one fetches the user tasks of that user. http://companywebapp.azurewebsites.net/api/Profile?id={accountId} http://companyebapp.azurewebsites.net/api/Task?id={accountId} The common input parameter for both APIs is accountId. Step 2 Create a new operation with name Dashboard as Get request with query parameter accountId and save. Step 3 Open the policy editor for Dashboard operation by clicking Inbound Processing-->Code view. We need to create a variable with name accountId like below. We can use this variable to pass the value into the APIs. <set-variable name="accountId" value="@(context.Request.Url.Query["accountId"].Last())" /> Step 4 Create a send-request policy for API1 and API2 which fetches profile details and profile tasks. The response-variable-name stores the response from the API. On set-url, we use the API to hit, which we want to fetch data from and stores the response to response-variable-name we declared. In set-method, we specify the HttpVerb based on the request we made. If we want to pass any values in the header we pass in set-header value. <send-request mode="new" response-variable-name="profiledetails" timeout="20" ignore-error="true"> <set-url>@($"http://companywebapp.azurewebsites.net/api/Profile?id={(string)context.Variables["accountId"]}")</set-url> <set-method>GET</set-method> <set-header name="Content-Type" exists-action="override"> <value>application/x-www-form-urlencoded</value> </set-header>> </send-request> <send-request mode="new" response-variable-name="taskdetails" timeout="20" ignore-error="true"> <set-url>@($"http://companywebapp.azurewebsites.net/api/Task?id={(string)context.Variables["accountId"]}")</set-url> <set-method>GET</set-method> <set-header name="Content-Type" exists-action="override"> <value>application/x-www-form-urlencoded</value> </set-header> </send-request> Step 5 We need to collect the response from the two APIs and use return-response policy to send the data. In return-reponse policy we need to aggregate the responses in set-body policy. In the previous step we collected the response and stored in profiledetails and taskdetails. This part is the final response, on set-body we are casting the response to JSON object and aggregating the two API response. <return-response> <set-status code="200" reason="OK" /> <set-header name="Content-Type" exists-action="override"> <value>application/json</value> </set-header> <set-body>@(new JObject(new JProperty("profiledetails",((IResponse)context.Variables["profiledetails"]).Body.As<JObject>()), new JProperty("taskdetails",((IResponse)context.Variables["taskdetails"]).Body.As<JObject>()) ).ToString())</set-body> </return-response> Summary By following these simple steps, we can aggregate two API's responses and send a single collective response. The example is very simple but in a real-time scenario, you may encounter multiple APIs with a lot of input parameters.1.7KViews0likes0CommentsThe brand new Azure AI Agent Service at your fingertips
Intro Azure AI Agent Service is a game-changer for developers. This fully managed service empowers you to build, deploy, and scale high-quality, extensible AI agents securely, without the hassle of managing underlying infrastructure. What used to take hundreds of lines of code can now be achieved in just a few lines! So here it is, a web application that streamlines document uploads, summarizes content using AI, and provides seamless access to stored summaries. This article delves into the architecture and implementation of this solution, drawing inspiration from our previous explorations with Azure AI Foundry and secure AI integrations. Architecture Overview Our Azure AI Agent Service WebApp integrates several Azure services to create a cohesive and scalable system: Azure AI Projects & Azure AI Agent Service: Powers the AI-driven summarization and title generation of uploaded documents. Azure Blob Storage: Stores the original and processed documents securely. Azure Cosmos DB: Maintains metadata and summaries for quick retrieval and display. Azure API Management (APIM): Manages and secures API endpoints, ensuring controlled access to backend services. This architecture ensures a seamless flow from document upload to AI processing and storage, providing users with immediate access to summarized content. Azure AI Agent Service – Frontend Implementation The frontend of the Azure AI Agent Service WebApp is built using Vite and React, offering a responsive and user-friendly interface. Key features include: Real-time AI Chat Interface: Users can interact with an AI agent for various queries. Document Upload Functionality: Supports uploading documents in various formats, which are then processed by the backend AI services. Document Repository: Displays a list of uploaded documents with their summaries and download links. This is the main UI , ChatApp.jsx. We can interact with Chat Agent for regular chat, while the keyword “upload:” activates the hidden upload menu. Azure AI Agent Service – Backend Services The backend is developed using Express.js, orchestrating various services to handle: File Uploads: Accepts documents from the frontend and stores them in Azure Blob Storage. AI Processing: Utilizes Azure AI Projects to extract text, generate summaries, and create concise titles. Metadata Storage: Saves document metadata and summaries in Azure Cosmos DB for efficient retrieval. One of the Challenges was to not recreate the Agents each time our backend reloads. So a careful plan is configured, with several files – modules for the Azure AI Agent Service interaction and Agents creation. The initialization for example is taken care by a single file-module: const { DefaultAzureCredential } = require('@azure/identity'); const { SecretClient } = require('@azure/keyvault-secrets'); const { AIProjectsClient, ToolUtility } = require('@azure/ai-projects'); require('dotenv').config(); // Keep track of global instances let aiProjectsClient = null; let agents = { chatAgent: null, extractAgent: null, summarizeAgent: null, titleAgent: null }; async function initializeAI(app) { try { // Setup Azure Key Vault const keyVaultName = process.env.KEYVAULT_NAME; const keyVaultUrl = `https://${keyVaultName}.vault.azure.net`; const credential = new DefaultAzureCredential(); const secretClient = new SecretClient(keyVaultUrl, credential); // Get AI connection string const secret = await secretClient.getSecret('AIConnectionString'); const AI_CONNECTION_STRING = secret.value; // Initialize AI Projects Client aiProjectsClient = AIProjectsClient.fromConnectionString( AI_CONNECTION_STRING, credential ); // Create code interpreter tool (shared among agents) const codeInterpreterTool = ToolUtility.createCodeInterpreterTool(); const tools = [codeInterpreterTool.definition]; const toolResources = codeInterpreterTool.resources; console.log('🚀 Creating AI Agents...'); // Create chat agent agents.chatAgent = await aiProjectsClient.agents.createAgent("gpt-4o-mini", { name: "chat-agent", instructions: "You are a helpful AI assistant that provides clear and concise responses.", tools, toolResources }); console.log('✅ Chat Agent created'); // Create extraction agent agents.extractAgent = await aiProjectsClient.agents.createAgent("gpt-4o-mini", { name: "extract-agent", instructions: "Process and clean text content while maintaining structure and important information.", tools, toolResources }); console.log('✅ Extract Agent created'); // Create summarization agent agents.summarizeAgent = await aiProjectsClient.agents.createAgent("gpt-4o-mini", { name: "summarize-agent", instructions: "Create concise summaries that capture main points and key details.", tools, toolResources }); console.log('✅ Summarize Agent created'); // Create title agent agents.titleAgent = await aiProjectsClient.agents.createAgent("gpt-4o-mini", { name: "title-agent", instructions: `You are a specialized title generation assistant. Your task is to create titles for documents following these rules: 1. Generate ONLY the title text, no additional explanations 2. Maximum length of 50 characters 3. Focus on the main topic or theme 4. Use proper capitalization (Title Case) 5. Avoid special characters and quotes 6. Make titles clear and descriptive 7. Respond with nothing but the title itself Example good responses: Digital Transformation Strategy 2025 Market Analysis: Premium Chai Tea Cloud Computing Implementation Guide Example bad responses: "Here's a title for your document: Digital Strategy" (no explanations needed) This document appears to be about digital transformation (just the title needed) The title is: Market Analysis (no extra text)`, tools, toolResources }); console.log('✅ Title Agent created'); // Store in app.locals app.locals.aiProjectsClient = aiProjectsClient; app.locals.agents = agents; console.log('✅ All AI Agents initialized successfully'); return { aiProjectsClient, agents }; } catch (error) { console.error('❌ Error initializing AI:', error); throw error; } } // Export both the initialization function and the shared instances module.exports = { initializeAI, getClient: () => aiProjectsClient, getAgents: () => agents }; Our backend utilizes 4 agents, creating the Azure AI Agent Service Agents and we will find them in the portal, when the Backend deploys At the same time, each interaction is stored and managed as thread and that’s how we are interacting with the Azure AI Agent Service. Deployment and Security of Azure AI Agent Service WebApp Ensuring secure and efficient deployment is crucial. We’ve employed: Azure API Management (APIM): Secures API endpoints, providing controlled access and monitoring capabilities. Azure Key Vault: Manages sensitive information such as API keys and connection strings, ensuring data protection. Every call to the backend service is protected with Azure API Management Basic Tier. We have only the required endpoints pointing to the matching Endpoints of our Azure AI Agent Service WebApp backend. Also we are storing the AIConnectionString variable in Key Vault and we can move all Variables in Key Vault as well, which i recommend ! Get started with Azure AI Agent Service To get started with Azure AI Agent Service, you need to create an Azure AI Foundry hub and an Agent project in your Azure subscription. Start with the quickstart guide if it’s your first time using the service. You can create a AI hub and project with the required resources. After you create a project, you can deploy a compatible model such as GPT-4o. When you have a deployed model, you can also start making API calls to the service using the SDKs. There are already 2 Quick-starts available to get your Azure AI Agent Service up and running, the Basic and the Standard. I have chosen the second one the Standard plan, since we have a WebApp, and the whole Architecture comes very handy ! We just added the CosmosDB interaction and the API Management to extend to an enterprise setup ! Our own Azure AI Agent Service deployment, allows us to interact with the Agents, and utilize tools and functions very easy. Conclusion By harnessing the power of Azure’s cloud services, we’ve developed a scalable and efficient web application that simplifies document management through AI-driven processing. This solution not only enhances productivity but also ensures secure and organized access to essential information. References Azure AI Agent Service Documentation What is Azure AI Agent Service Azure AI Agent Service Quick starts Azure API Management Azure AI Foundry Azure AI Foundry Inference Demo645Views1like2CommentsAI Community Day - Boost AI Workflow Productivity
Hey everyone! Thanks for joining out session today at the AI Community Day. Here you can find the resources that have been shared during the session and our contact links. Resources Gen APIM Samples Repository The Azure Developer CLI Azure OpenAI Assistants Liam Hampton LinkedIn Chris Noring LinkedIn155Views0likes0CommentsAzure API Center: Centralizando a Gestão de APIs para Melhoria da Descoberta e Governança
Explore como o Azure API Center pode revolucionar a gestão de suas APIs, centralizando o controle, melhorando a descoberta e aprimorando a governança. Saiba mais sobre suas funcionalidades, benefícios e acesse o treinamento gratuito no Microsoft Learn hoje mesmo!1.7KViews0likes0Comments