Biblioteca de clientes de gerenciamento de contêineres do Microsoft Azure HDInsight para .NET

O Microsoft Azure HDInsgiht Containers (HDInsight On AKS) simplifica a implantação do cluster hdinsight com base no AKS.

Essa biblioteca dá suporte ao gerenciamento de recursos de contêineres do Microsoft Azure HDInsgiht.

Essa biblioteca segue as novas diretrizes do SDK do Azure e fornece muitos recursos principais:

- Support MSAL.NET, Azure.Identity is out of box for supporting MSAL.NET.
- Support [OpenTelemetry](https://opentelemetry.io/) for distributed tracing.
- HTTP pipeline with custom policies.
- Better error-handling.
- Support uniform telemetry across all languages.

Introdução

Instale o pacote (como agora estamos em versão prévia privada status, o método bellow não funciona, envie um email para Askhilo@microsoft.com para instalar o nuget do nosso feed nuget privado)

Instale a biblioteca de gerenciamento do Azure HDInsight no AKS para .NET com NuGet:

dotnet add package Azure.ResourceManager.HDInsight.Containers --prerelease

Pré-requisitos

Autenticar o Cliente

Para criar um cliente autenticado e começar a interagir com os recursos do Microsoft Azure, confira o guia de início rápido aqui.

Principais conceitos

Os principais conceitos do SDK do Microsoft Azure para .NET podem ser encontrados aqui.

Documentação

A documentação está disponível para ajudá-lo a aprender a usar este pacote:

Exemplos

Namespaces para este exemplo:

using System;
using System.Linq;
using Azure.ResourceManager;
using Azure.Identity;
using Azure.ResourceManager.Resources;
using Azure.Core;
using Azure.ResourceManager.HDInsight.Containers;
using Azure.ResourceManager.HDInsight.Containers.Models;

Ao criar seu cliente ARM pela primeira vez, escolha a assinatura na qual você trabalhará. Você pode usar os GetDefaultSubscription/GetDefaultSubscriptionAsync métodos para retornar a assinatura padrão configurada para o usuário:

ArmClient armClient = new ArmClient(new DefaultAzureCredential());
SubscriptionResource subscription = armClient.GetDefaultSubscription();

Criar pool de clusters

// define the prerequisites information: subscription, resource group and location where you want to create the resource
string subscriptionResourceId = "/subscriptions/{subscription id}"; // your subscription resource id like /subscriptions/{subscription id}
string resourceGroupName = "{your resource group name}"; // your resource group name
AzureLocation location = AzureLocation.EastUS; // your location

SubscriptionResource subscription = armClient.GetSubscriptionResource(new ResourceIdentifier(resourceId: subscriptionResourceId));
ResourceGroupResource resourceGroupResource = subscription.GetResourceGroup(resourceGroupName);
HDInsightClusterPoolCollection clusterPoolCollection = resourceGroupResource.GetHDInsightClusterPools();

// create the cluster pool
string clusterPoolName = "{your cluster pool name}";
string clusterPoolVmSize = "Standard_E4s_v3"; // the vmsize

// get the available cluster pool version
var availableClusterPoolVersion = subscription.GetAvailableClusterPoolVersionsByLocation(location).FirstOrDefault();

// initialize the ClusterPoolData instance
HDInsightClusterPoolData clusterPoolData = new HDInsightClusterPoolData(location)
{
    ComputeProfile = new ClusterPoolComputeProfile(clusterPoolVmSize),
    ClusterPoolVersion = availableClusterPoolVersion?.ClusterPoolVersionValue,
};

var clusterPoolResult = clusterPoolCollection.CreateOrUpdate(Azure.WaitUntil.Completed, clusterPoolName, clusterPoolData);

Criar cluster Trino simples

// define the prerequisites information: subscription, resource group and location where you want to create the resource
string subscriptionResourceId = "/subscriptions/{subscription id}"; // your subscription resource id like /subscriptions/{subscription id}
string resourceGroupName = "{your resource group}"; // your resource group name
AzureLocation location = AzureLocation.EastUS; // your location

SubscriptionResource subscription = armClient.GetSubscriptionResource(new ResourceIdentifier(resourceId: subscriptionResourceId));
ResourceGroupResource resourceGroupResource = subscription.GetResourceGroup(resourceGroupName);
HDInsightClusterPoolCollection clusterPoolCollection = resourceGroupResource.GetHDInsightClusterPools();

// create the cluster
string clusterPoolName = "{your cluster pool name}";
string clusterName = "{your cluster name}";
string clusterType = "Trino"; // your cluster type

// get the available cluster version
var availableClusterVersion = subscription.GetAvailableClusterVersionsByLocation(location).Where(version => version.ClusterType.Equals(clusterType, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();

// set the identity profile
string msiResourceId = "{your user msi resource id}";
string msiClientId = "{your user msi client id}";
string msiObjectId = "{your user msi object id}";
var identityProfile = new HDInsightIdentityProfile(msiResourceId: new ResourceIdentifier(msiResourceId), msiClientId: msiClientId, msiObjectId: msiObjectId);

// set the authorization profile
var userId = "{your aad user id}";
var authorizationProfile = new AuthorizationProfile();
authorizationProfile.UserIds.Add(userId);

// set the cluster node profile
string vmSize = "Standard_D8s_v3"; // your vms ize
int workerCount = 5;
ClusterComputeNodeProfile nodeProfile = new ClusterComputeNodeProfile(nodeProfileType: "worker", vmSize: vmSize, count: workerCount);

// initialize the ClusterData instance
var clusterData = new HDInsightClusterData(location)
{
    ClusterType = clusterType,
    ClusterProfile = new ClusterProfile(clusterVersion: availableClusterVersion?.ClusterVersion, ossVersion: availableClusterVersion?.OssVersion, identityProfile: identityProfile, authorizationProfile: authorizationProfile)
    {
        TrinoProfile = new TrinoProfile(),  // here is related with cluster type
    },
};
clusterData.ComputeNodes.Add(nodeProfile);

var clusterCollection = clusterPoolCollection.Get(clusterPoolName).Value.GetHDInsightClusters();

var clusterResult = clusterCollection.CreateOrUpdate(Azure.WaitUntil.Completed, clusterName, clusterData);

Criar cluster spark simples

// define the prerequisites information: subscription, resource group and location where you want to create the resource
string subscriptionResourceId = "/subscriptions/{subscription id}"; // your subscription resource id like /subscriptions/{subscription id}
string resourceGroupName = "{your resource group}"; // your resource group name
AzureLocation location = AzureLocation.EastUS; // your location

SubscriptionResource subscription = armClient.GetSubscriptionResource(new ResourceIdentifier(resourceId: subscriptionResourceId));
ResourceGroupResource resourceGroupResource = subscription.GetResourceGroup(resourceGroupName);
HDInsightClusterPoolCollection clusterPoolCollection = resourceGroupResource.GetHDInsightClusterPools();

// create the cluster
string clusterPoolName = "{your cluster pool name}";
string clusterName = "{your cluster name}";
string clusterType = "Spark"; // your cluster type here is Spark

// get the available cluster version
var availableClusterVersion = subscription.GetAvailableClusterVersionsByLocation(location).Where(version => version.ClusterType.Equals(clusterType, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();

// set the identity profile
string msiResourceId = "{your user msi resource id}";
string msiClientId = "{your user msi client id}";
string msiObjectId = "{your user msi object id}";
var identityProfile = new HDInsightIdentityProfile(msiResourceId: new ResourceIdentifier(msiResourceId), msiClientId: msiClientId, msiObjectId: msiObjectId);

// set the authorization profile
var userId = "{your aad user id}";
var authorizationProfile = new AuthorizationProfile();
authorizationProfile.UserIds.Add(userId);

// set the cluster node profile
string vmSize = "Standard_D8s_v3"; // your vms ize
int workerCount = 5;
ClusterComputeNodeProfile nodeProfile = new ClusterComputeNodeProfile(nodeProfileType: "worker", vmSize: vmSize, count: workerCount);

// initialize the ClusterData instance
var clusterData = new HDInsightClusterData(location)
{
    ClusterType = clusterType,
    ClusterProfile = new ClusterProfile(clusterVersion: availableClusterVersion?.ClusterVersion, ossVersion: availableClusterVersion?.OssVersion, identityProfile: identityProfile, authorizationProfile: authorizationProfile)
    {
        SparkProfile = new SparkProfile(),  // here is related with cluster type
    },
};
clusterData.ComputeNodes.Add(nodeProfile);

var clusterCollection = clusterPoolCollection.Get(clusterPoolName).Value.GetHDInsightClusters();

var clusterResult = clusterCollection.CreateOrUpdate(Azure.WaitUntil.Completed, clusterName, clusterData);
// define the prerequisites information: subscription, resource group and location where you want to create the resource
string subscriptionResourceId = "/subscriptions/{subscription id}"; // your subscription resource id like /subscriptions/{subscription id}
string resourceGroupName = "{your resource group}"; // your resource group name
AzureLocation location = AzureLocation.EastUS; // your location

SubscriptionResource subscription = armClient.GetSubscriptionResource(new ResourceIdentifier(resourceId: subscriptionResourceId));
ResourceGroupResource resourceGroupResource = subscription.GetResourceGroup(resourceGroupName);
HDInsightClusterPoolCollection clusterPoolCollection = resourceGroupResource.GetHDInsightClusterPools();

// create the cluster
string clusterPoolName = "{your cluster pool name}";
string clusterName = "{your cluster name}";
string clusterType = "Flink"; // cluster type

// get the available cluster version
var availableClusterVersion = subscription.GetAvailableClusterVersionsByLocation(location).Where(version => version.ClusterType.Equals(clusterType, StringComparison.OrdinalIgnoreCase)).LastOrDefault();

// set the identity profile
string msiResourceId = "{your user msi resource id}";
string msiClientId = "{your user msi client id}";
string msiObjectId = "{your user msi object id}";
var identityProfile = new HDInsightIdentityProfile(msiResourceId: new ResourceIdentifier(msiResourceId), msiClientId: msiClientId, msiObjectId: msiObjectId);

// set the authorization profile
var userId = "{your aad user id}";
var authorizationProfile = new AuthorizationProfile();
authorizationProfile.UserIds.Add(userId);

// set the cluster node profile
string vmSize = "Standard_D8s_v3"; // your vm size
int workerCount = 5;
ClusterComputeNodeProfile nodeProfile = new ClusterComputeNodeProfile(nodeProfileType: "worker", vmSize: vmSize, count: workerCount);
// initialize the ClusterData instance
var clusterData = new HDInsightClusterData(location)
{
    ClusterType = clusterType,
    ClusterProfile = new ClusterProfile(clusterVersion: availableClusterVersion?.ClusterVersion, ossVersion: availableClusterVersion?.OssVersion, identityProfile: identityProfile, authorizationProfile: authorizationProfile),
};
clusterData.ComputeNodes.Add(nodeProfile);

// set flink profile
string storageUri = "abfs://{your storage account container name}@{yoru storage account}.dfs.core.windows.net"; // your adlsgen2 storage uri
FlinkStorageProfile flinkStorageProfile = new FlinkStorageProfile(storageUri);

ComputeResourceRequirement jobManager = new ComputeResourceRequirement((float)1.0, 2048);
ComputeResourceRequirement taskManager = new ComputeResourceRequirement((float)1.0, 2048);

clusterData.ClusterProfile.FlinkProfile = new FlinkProfile(storage: flinkStorageProfile, jobManager: jobManager, taskManager: taskManager);

var clusterCollection = clusterPoolCollection.Get(clusterPoolName).Value.GetHDInsightClusters();

var clusterResult = clusterCollection.CreateOrUpdate(Azure.WaitUntil.Completed, clusterName, clusterData);

Criar cluster Trino com Hms

// define the prerequisites information: subscription, resource group and location where you want to create the resource
string subscriptionResourceId = "/subscriptions/{subscription id}"; // your subscription resource id like /subscriptions/{subscription id}
string resourceGroupName = "{your resource group}"; // your resource group name
AzureLocation location = AzureLocation.EastUS; // your location

SubscriptionResource subscription = armClient.GetSubscriptionResource(new ResourceIdentifier(resourceId: subscriptionResourceId));
ResourceGroupResource resourceGroupResource = subscription.GetResourceGroup(resourceGroupName);
HDInsightClusterPoolCollection clusterPoolCollection = resourceGroupResource.GetHDInsightClusterPools();

// create the cluster
string clusterPoolName = "{your cluster pool name}";
string clusterName = "{your cluster name}";
string clusterType = "Trino"; // your cluster type

// get the available cluster version
var availableClusterVersion = subscription.GetAvailableClusterVersionsByLocation(location).Where(version => version.ClusterType.Equals(clusterType, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();

// set the identity profile
string msiResourceId = "{your user msi resource id}";
string msiClientId = "{your user msi client id}";
string msiObjectId = "{your user msi object id}";
var identityProfile = new HDInsightIdentityProfile(msiResourceId: new ResourceIdentifier(msiResourceId), msiClientId: msiClientId, msiObjectId: msiObjectId);

// set the authorization profile
var userId = "{your aad user id}";
var authorizationProfile = new AuthorizationProfile();
authorizationProfile.UserIds.Add(userId);

// set the cluster node profile
string vmSize = "Standard_D8s_v3"; // your vms ize
int workerCount = 5;
ClusterComputeNodeProfile nodeProfile = new ClusterComputeNodeProfile(nodeProfileType: "worker", vmSize: vmSize, count: workerCount);

// initialize the ClusterData instance
var clusterData = new HDInsightClusterData(location)
{
    ClusterType = clusterType,
    ClusterProfile = new ClusterProfile(clusterVersion: availableClusterVersion?.ClusterVersion, ossVersion: availableClusterVersion?.OssVersion, identityProfile: identityProfile, authorizationProfile: authorizationProfile),
};
clusterData.ComputeNodes.Add(nodeProfile);

// set secret profile
string kvResourceId = "{your key vault resource id}";
string secretName = "{your secret reference name}";
string keyVaultObjectName = "{your key vault secret name}";

var secretReference = new ClusterSecretReference(referenceName: secretName, KeyVaultObjectType.Secret, keyVaultObjectName: keyVaultObjectName);
clusterData.ClusterProfile.SecretsProfile = new ClusterSecretsProfile(new ResourceIdentifier(kvResourceId));
clusterData.ClusterProfile.SecretsProfile.Secrets.Add(secretReference);

// set trino profile
string catalogName = "{your catalog name}";
string metastoreDbConnectionUriString = "jdbc:sqlserver://{your sql server name}.database.windows.net;database={your database name};encrypt=true;trustServerCertificate=true;loginTimeout=30;";
string metastoreDbUserName = "{your db user name}";
string metastoreDbPasswordSecret = secretName;
string metastoreWarehouseDir = "abfs://{your adlsgen2 storage account container}@{your adlsgen2 storage account}.dfs.core.windows.net/{sub folder path}";

TrinoProfile trinoProfile = new TrinoProfile();
trinoProfile.CatalogOptionsHive.Add(
    new HiveCatalogOption(
        catalogName: catalogName,
        metastoreDBConnectionPasswordSecret: metastoreDbPasswordSecret,
        metastoreDBConnectionUriString: metastoreDbConnectionUriString,
        metastoreDBConnectionUserName: metastoreDbUserName,
        metastoreWarehouseDir: metastoreWarehouseDir)
);

clusterData.ClusterProfile.TrinoProfile = trinoProfile;

var clusterCollection = clusterPoolCollection.Get(clusterPoolName).Value.GetHDInsightClusters();

var clusterResult = clusterCollection.CreateOrUpdate(Azure.WaitUntil.Completed, clusterName, clusterData);

Criar cluster spark com Hms

// define the prerequisites information: subscription, resource group and location where you want to create the resource
string subscriptionResourceId = "/subscriptions/{subscription id}"; // your subscription resource id like /subscriptions/{subscription id}
string resourceGroupName = "{your resource group}"; // your resource group name
AzureLocation location = AzureLocation.EastUS; // your location

SubscriptionResource subscription = armClient.GetSubscriptionResource(new ResourceIdentifier(resourceId: subscriptionResourceId));
ResourceGroupResource resourceGroupResource = subscription.GetResourceGroup(resourceGroupName);
HDInsightClusterPoolCollection clusterPoolCollection = resourceGroupResource.GetHDInsightClusterPools();

// create the cluster
string clusterPoolName = "{your cluster pool name}";
string clusterName = "{your cluster name}";
string clusterType = "Spark"; // your cluster type here is Spark

// get the available cluster version
var availableClusterVersion = subscription.GetAvailableClusterVersionsByLocation(location).Where(version => version.ClusterType.Equals(clusterType, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();

// set the identity profile
string msiResourceId = "{your user msi resource id}";
string msiClientId = "{your user msi client id}";
string msiObjectId = "{your user msi object id}";
var identityProfile = new HDInsightIdentityProfile(msiResourceId: new ResourceIdentifier(msiResourceId), msiClientId: msiClientId, msiObjectId: msiObjectId);

// set the authorization profile
var userId = "{your aad user id}";
var authorizationProfile = new AuthorizationProfile();
authorizationProfile.UserIds.Add(userId);

// set the cluster node profile
string vmSize = "Standard_D8s_v3"; // your vms ize
int workerCount = 5;
ClusterComputeNodeProfile nodeProfile = new ClusterComputeNodeProfile(nodeProfileType: "worker", vmSize: vmSize, count: workerCount);

// initialize the ClusterData instance
var clusterData = new HDInsightClusterData(location)
{
    ClusterType = clusterType,
    ClusterProfile = new ClusterProfile(clusterVersion: availableClusterVersion?.ClusterVersion, ossVersion: availableClusterVersion?.OssVersion, identityProfile: identityProfile, authorizationProfile: authorizationProfile),
};
clusterData.ComputeNodes.Add(nodeProfile);

// set secret profile
string kvResourceId = "{your key vault resource id}";
string secretName = "{your secret reference name}";
string keyVaultObjectName = "{your key vault secret name}";

var secretReference = new ClusterSecretReference(referenceName: secretName, KeyVaultObjectType.Secret, keyVaultObjectName: keyVaultObjectName);
clusterData.ClusterProfile.SecretsProfile = new ClusterSecretsProfile(new ResourceIdentifier(kvResourceId));
clusterData.ClusterProfile.SecretsProfile.Secrets.Add(secretReference);

// set spark profile
string defaultStorageUriString = "abfs://{your adlsgen2 storage account container}@{your adlsgen2 storage account}.dfs.core.windows.net/";
string dbServerHost = "{your sql server name}.database.windows.net";
string dbUserName = "{your db user name}";
string dbName = "{yoru db name}";
string dbPasswordSecretName = secretName;

SparkProfile sparkProfile = new SparkProfile();
sparkProfile.DefaultStorageUriString = defaultStorageUriString;
sparkProfile.MetastoreSpec = new SparkMetastoreSpec(dbServerHost: dbServerHost, dbName: dbName, dbUserName: dbUserName, dbPasswordSecretName: dbPasswordSecretName, keyVaultId: kvResourceId);

clusterData.ClusterProfile.SparkProfile = sparkProfile;

var clusterCollection = clusterPoolCollection.Get(clusterPoolName).Value.GetHDInsightClusters();

var clusterResult = clusterCollection.CreateOrUpdate(Azure.WaitUntil.Completed, clusterName, clusterData);
// define the prerequisites information: subscription, resource group and location where you want to create the resource
string subscriptionResourceId = "/subscriptions/{subscription id}"; // your subscription resource id like /subscriptions/{subscription id}
string resourceGroupName = "{your resource group}"; // your resource group name
AzureLocation location = AzureLocation.EastUS; // your location

SubscriptionResource subscription = armClient.GetSubscriptionResource(new ResourceIdentifier(resourceId: subscriptionResourceId));
ResourceGroupResource resourceGroupResource = subscription.GetResourceGroup(resourceGroupName);
HDInsightClusterPoolCollection clusterPoolCollection = resourceGroupResource.GetHDInsightClusterPools();

// create the cluster
string clusterPoolName = "{your cluster pool name}";
string clusterName = "{your cluster name}";
string clusterType = "Flink"; // cluster type

// get the available cluster version
var availableClusterVersion = subscription.GetAvailableClusterVersionsByLocation(location).Where(version => version.ClusterType.Equals(clusterType, StringComparison.OrdinalIgnoreCase)).LastOrDefault();

// set the identity profile
string msiResourceId = "{your user msi resource id}";
string msiClientId = "{your user msi client id}";
string msiObjectId = "{your user msi object id}";
var identityProfile = new HDInsightIdentityProfile(msiResourceId: new ResourceIdentifier(msiResourceId), msiClientId: msiClientId, msiObjectId: msiObjectId);

// set the authorization profile
var userId = "{your aad user id}";
var authorizationProfile = new AuthorizationProfile();
authorizationProfile.UserIds.Add(userId);

// set the cluster node profile
string vmSize = "Standard_D8s_v3"; // your vm size
int workerCount = 5;
ClusterComputeNodeProfile nodeProfile = new ClusterComputeNodeProfile(nodeProfileType: "worker", vmSize: vmSize, count: workerCount);

// initialize the ClusterData instance
var clusterData = new HDInsightClusterData(location)
{
    ClusterType = clusterType,
    ClusterProfile = new ClusterProfile(clusterVersion: availableClusterVersion?.ClusterVersion, ossVersion: availableClusterVersion?.OssVersion, identityProfile: identityProfile, authorizationProfile: authorizationProfile),
};
clusterData.ComputeNodes.Add(nodeProfile);

// set secret profile
string kvResourceId = "{your key vault resource id}";
string secretName = "{your secret reference name}";
string keyVaultObjectName = "{your key vault secret name}";

var secretReference = new ClusterSecretReference(referenceName: secretName, KeyVaultObjectType.Secret, keyVaultObjectName: keyVaultObjectName);
clusterData.ClusterProfile.SecretsProfile = new ClusterSecretsProfile(new ResourceIdentifier(kvResourceId));
clusterData.ClusterProfile.SecretsProfile.Secrets.Add(secretReference);

// set flink profile

string storageUri = "abfs://{your adlsgen2 storage account container}@{your adlsgen2 storage account}.dfs.core.windows.net";
FlinkStorageProfile flinkStorageProfile = new FlinkStorageProfile(storageUri);

ComputeResourceRequirement jobManager = new ComputeResourceRequirement((float)1.0, 2048);
ComputeResourceRequirement taskManager = new ComputeResourceRequirement((float)1.0, 2048);

// set flink catalog
string metastoreDbConnectionUriString = "jdbc:sqlserver://{your sql server name}.database.windows.net;database={your database name};encrypt=true;trustServerCertificate=true;loginTimeout=30;";
string metastoreDbUserName = "{your db user name}";
string metastoreDbPasswordSecret = secretName;

FlinkHiveCatalogOption flinkHiveCatalogOption = new FlinkHiveCatalogOption(metastoreDBConnectionPasswordSecret: metastoreDbPasswordSecret, metastoreDBConnectionUriString: metastoreDbConnectionUriString, metastoreDBConnectionUserName: metastoreDbUserName);
clusterData.ClusterProfile.FlinkProfile = new FlinkProfile(storage: flinkStorageProfile, jobManager: jobManager, taskManager: taskManager);
clusterData.ClusterProfile.FlinkProfile.CatalogOptionsHive = flinkHiveCatalogOption;

var clusterCollection = clusterPoolCollection.Get(clusterPoolName).Value.GetHDInsightClusters();
var clusterResult = clusterCollection.CreateOrUpdate(Azure.WaitUntil.Completed, clusterName, clusterData);

Mais exemplos

Mais exemplos de código para usar a biblioteca de gerenciamento para .NET podem ser encontrados nos seguintes locais

Solução de problemas

Próximas etapas

Para obter mais informações sobre o SDK do Microsoft Azure, consulte este site.

Participante

Para obter detalhes sobre como contribuir para esse repositório, consulte o guia de contribuição.

Este projeto aceita contribuições e sugestões. A maioria das contribuições exige que você concorde com um CLA (Contrato de Licença do Colaborador) declarando que você tem o direito de nos conceder, e de fato concede, os direitos de usar sua contribuição. Para obter detalhes, visite https://cla.microsoft.com.

Quando você envia uma solicitação de pull, um CLA-bot determina automaticamente se você precisa fornecer um CLA e decorar a PR adequadamente (por exemplo, rótulo, comentário). Basta seguir as instruções fornecidas pelo bot. Você só precisará executar essa ação uma vez em todos os repositórios usando nosso CLA.

Este projeto adotou o Código de Conduta de Software Livre da Microsoft. Para saber mais, confira as Perguntas frequentes sobre o Código de Conduta ou contate o opencode@microsoft.com caso tenha outras dúvidas ou comentários.