Merge branch 'endgame-202407' into endgame-202407.next

This commit is contained in:
Flanker32 2024-07-30 11:07:50 +08:00
Родитель f3f68606a9 1f905b9478
Коммит b5e00fd6a6
115 изменённых файлов: 1192 добавлений и 301 удалений

Просмотреть файл

@ -27,7 +27,7 @@
<parent>
<groupId>com.microsoft.azuretools</groupId>
<artifactId>utils</artifactId>
<version>3.91.0-SNAPSHOT</version>
<version>3.91.0</version>
</parent>
<groupId>com.microsoft.azuretools</groupId>
<artifactId>com.microsoft.azuretools.sdk.lib</artifactId>
@ -39,9 +39,9 @@
</organization>
<properties>
<azuretool.version>3.91.0-SNAPSHOT</azuretool.version>
<azuretool.version>3.91.0</azuretool.version>
<azuretool.sdk.version>3.32.0.qualifier</azuretool.sdk.version>
<azure.toolkit-lib.version>0.47.0-SNAPSHOT</azure.toolkit-lib.version>
<azure.toolkit-lib.version>0.47.0</azure.toolkit-lib.version>
</properties>
<dependencyManagement>
<dependencies>

Просмотреть файл

@ -43,4 +43,4 @@ Export-Package: com.microsoft.azuretools.appservice,
com.microsoft.azuretools.appservice.handlers,
com.microsoft.azuretools.appservice.ui
Bundle-ClassPath: .,
target/lib/azure-toolkit-ide-appservice-lib-0.47.0-SNAPSHOT.jar
target/lib/azure-toolkit-ide-appservice-lib-0.47.0.jar

Просмотреть файл

@ -13,7 +13,7 @@
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-toolkit-ide-appservice-lib</artifactId>
<version>0.47.0-SNAPSHOT</version>
<version>0.47.0</version>
</dependency>
</dependencies>
<repositories>

Просмотреть файл

@ -23,7 +23,7 @@ Require-Bundle: org.eclipse.ui,
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .,
target/lib/azure-toolkit-ide-springcloud-lib-0.47.0-SNAPSHOT.jar
target/lib/azure-toolkit-ide-springcloud-lib-0.47.0.jar
Import-Package: com.microsoft.azuretools.core.actions,
org.eclipse.core.expressions,
org.eclipse.jface.text.hyperlink,

Просмотреть файл

@ -13,7 +13,7 @@
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-toolkit-ide-springcloud-lib</artifactId>
<version>0.47.0-SNAPSHOT</version>
<version>0.47.0</version>
</dependency>
</dependencies>
<build>

Просмотреть файл

@ -30,10 +30,12 @@
<option value="$PROJECT_DIR$/azure-intellij-plugin-hdinsight-lib" />
<option value="$PROJECT_DIR$/azure-intellij-plugin-integration-services" />
<option value="$PROJECT_DIR$/azure-intellij-plugin-keyvault" />
<option value="$PROJECT_DIR$/azure-intellij-plugin-keyvault-java" />
<option value="$PROJECT_DIR$/azure-intellij-plugin-lib" />
<option value="$PROJECT_DIR$/azure-intellij-plugin-lib-java" />
<option value="$PROJECT_DIR$/azure-intellij-plugin-monitor" />
<option value="$PROJECT_DIR$/azure-intellij-plugin-redis" />
<option value="$PROJECT_DIR$/azure-intellij-plugin-redis-java" />
<option value="$PROJECT_DIR$/azure-intellij-plugin-samples" />
<option value="$PROJECT_DIR$/azure-intellij-plugin-service-explorer" />
<option value="$PROJECT_DIR$/azure-intellij-plugin-servicebus" />
@ -41,6 +43,7 @@
<option value="$PROJECT_DIR$/azure-intellij-plugin-springcloud" />
<option value="$PROJECT_DIR$/azure-intellij-plugin-sqlserverbigdata" />
<option value="$PROJECT_DIR$/azure-intellij-plugin-storage" />
<option value="$PROJECT_DIR$/azure-intellij-plugin-storage-java" />
<option value="$PROJECT_DIR$/azure-intellij-plugin-synapse" />
<option value="$PROJECT_DIR$/azure-intellij-plugin-vm" />
<option value="$PROJECT_DIR$/azure-intellij-resource-connector-aad" />

Просмотреть файл

@ -20,6 +20,7 @@ dependencies {
implementation(project(":azure-intellij-plugin-containerapps"))
// runtimeOnly project(path: ":azure-intellij-plugin-containerapps", configuration: "instrumentedJar")
implementation("com.github.docker-java:docker-java:3.3.0")
implementation("com.microsoft.azure:azure-toolkit-identity-lib")
implementation("com.microsoft.azure:azure-toolkit-appservice-lib")
implementation("com.microsoft.azure:azure-toolkit-ide-appservice-lib")
implementation("com.microsoft.azure:azure-toolkit-ide-containerapps-lib")

Просмотреть файл

@ -16,7 +16,7 @@ import com.microsoft.azure.toolkit.intellij.connector.dotazure.AzureModule;
import com.microsoft.azure.toolkit.intellij.connector.dotazure.DotEnvBeforeRunTaskProvider;
import com.microsoft.azure.toolkit.intellij.legacy.common.AzureRunProfileState;
import com.microsoft.azure.toolkit.intellij.legacy.function.runner.core.FunctionUtils;
import com.microsoft.azure.toolkit.intellij.storage.connection.StorageAccountResourceDefinition;
import com.microsoft.azure.toolkit.intellij.storage.connection.BaseStorageAccountResourceDefinition;
import com.microsoft.azure.toolkit.lib.appservice.config.FunctionAppConfig;
import com.microsoft.azure.toolkit.lib.appservice.function.FunctionApp;
import com.microsoft.azure.toolkit.lib.appservice.function.FunctionAppBase;
@ -99,7 +99,7 @@ public class FunctionDeploymentState extends AzureRunProfileState<FunctionAppBas
final Map<String, String> appSettings = functionDeployConfiguration.getConfig().appSettings();
loadDotEnvBeforeRunTask.loadEnv().stream()
.filter(pair -> !(StringUtils.equalsIgnoreCase(pair.getKey(), "AzureWebJobsStorage") &&
StringUtils.equalsIgnoreCase(pair.getValue(), StorageAccountResourceDefinition.LOCAL_STORAGE_CONNECTION_STRING))) // workaround to remove local connections
StringUtils.equalsIgnoreCase(pair.getValue(), BaseStorageAccountResourceDefinition.LOCAL_STORAGE_CONNECTION_STRING))) // workaround to remove local connections
.forEach(env -> appSettings.put(env.getKey(), env.getValue()));
}
}

Просмотреть файл

@ -12,8 +12,10 @@ import com.microsoft.azure.toolkit.ide.common.action.ResourceCommonActionsContri
import com.microsoft.azure.toolkit.intellij.common.AzureArtifact;
import com.microsoft.azure.toolkit.intellij.common.AzureArtifactManager;
import com.microsoft.azure.toolkit.intellij.common.RunProcessHandler;
import com.microsoft.azure.toolkit.intellij.connector.*;
import com.microsoft.azure.toolkit.intellij.connector.dotazure.AzureModule;
import com.microsoft.azure.toolkit.intellij.connector.dotazure.DotEnvBeforeRunTaskProvider;
import com.microsoft.azure.toolkit.intellij.connector.dotazure.Profile;
import com.microsoft.azure.toolkit.intellij.legacy.common.AzureRunProfileState;
import com.microsoft.azure.toolkit.lib.Azure;
import com.microsoft.azure.toolkit.lib.appservice.config.AppServiceConfig;
@ -24,6 +26,7 @@ import com.microsoft.azure.toolkit.lib.appservice.model.DeployType;
import com.microsoft.azure.toolkit.lib.appservice.model.WebAppArtifact;
import com.microsoft.azure.toolkit.lib.appservice.task.CreateOrUpdateWebAppTask;
import com.microsoft.azure.toolkit.lib.appservice.task.DeployWebAppTask;
import com.microsoft.azure.toolkit.lib.appservice.webapp.WebApp;
import com.microsoft.azure.toolkit.lib.appservice.webapp.WebAppBase;
import com.microsoft.azure.toolkit.lib.appservice.webapp.WebAppDeploymentSlot;
import com.microsoft.azure.toolkit.lib.common.action.Action;
@ -36,10 +39,14 @@ import com.microsoft.azure.toolkit.lib.common.model.AzResource;
import com.microsoft.azure.toolkit.lib.common.operation.AzureOperation;
import com.microsoft.azure.toolkit.lib.common.operation.OperationContext;
import com.microsoft.azure.toolkit.lib.common.task.AzureTaskManager;
import com.microsoft.azure.toolkit.lib.identities.Identity;
import com.microsoft.azure.toolkit.lib.identities.ManagedIdentitySupport;
import com.microsoft.azure.toolkit.lib.identities.model.IdentityConfiguration;
import com.microsoft.azuretools.telemetry.TelemetryConstants;
import com.microsoft.azuretools.telemetrywrapper.Operation;
import com.microsoft.azuretools.telemetrywrapper.TelemetryManager;
import com.microsoft.azuretools.utils.WebAppUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.compress.utils.FileNameUtils;
import org.apache.commons.io.FilenameUtils;
@ -54,8 +61,10 @@ import java.io.FileNotFoundException;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.microsoft.azure.toolkit.intellij.common.AzureBundle.message;
import static com.microsoft.azure.toolkit.intellij.connector.IManagedIdentitySupported.*;
public class WebAppRunState extends AzureRunProfileState<WebAppBase<?, ?, ?>> {
private static final String LIBS_ROOT = "/home/site/wwwroot/libs/";
@ -90,27 +99,79 @@ public class WebAppRunState extends AzureRunProfileState<WebAppBase<?, ?, ?>> {
if (!artifact.exists()) {
throw new FileNotFoundException(message("webapp.deploy.error.noTargetFile", artifact.getAbsolutePath()));
}
final WebAppBase<?, ?, ?> deployTarget = getOrCreateDeployTarget();
final AzureModule module = Optional.ofNullable(this.webAppConfiguration.getModule()).map(AzureModule::from)
.or(() -> Optional.ofNullable(getTargetPath())
.map(f -> VfsUtil.findFile(Path.of(f), true))
.map(f -> AzureModule.from(f, this.project))).orElse(null);
final WebAppBase<?, ?, ?> deployTarget = getOrCreateDeployTarget(module);
// todo: remove workaround after fix reset issue in toolkit lib
if (deployTarget instanceof AzResource.Draft<?, ?> draft) {
draft.reset();
}
if (deployTarget instanceof WebApp app) {
Optional.ofNullable(module).map(AzureModule::getDefaultProfile).ifPresent(p -> updateResourceConnectionWithIdentity(app, p));
Optional.ofNullable(module).map(AzureModule::getDefaultProfile).ifPresent(p -> validatePermissionForIdentityConnections(app, p));
}
webAppConfiguration.setWebApp(deployTarget);
deployArtifactsToWebApp(deployTarget, artifact, webAppSettingModel.isDeployToRoot());
return deployTarget;
}
public static <T extends ManagedIdentitySupport> void validatePermissionForIdentityConnections(T target, Profile profile) {
final IdentityConfiguration configuration = target.getIdentityConfiguration();
final List<Connection<?, ?>> list = profile.getConnections().stream().filter(Connection::isManagedIdentityConnection).toList();
list.forEach(con -> {
final Resource<?> resource = con.getResource();
final IManagedIdentitySupported<?> definition = (IManagedIdentitySupported<?>) resource.getDefinition();
// todo: replace with real permission check
if (MapUtils.isEmpty(definition.getBuiltInRoles())) {
return;
}
final AbstractAzResource<?,?,?> data = (AbstractAzResource<?,?,?>) resource.getData();
final String identity = con.getAuthenticationType() == AuthenticationType.SYSTEM_ASSIGNED_MANAGED_IDENTITY ?
configuration.getPrincipalId() : Objects.requireNonNull(con.getUserAssignedManagedIdentity()).getData().getPrincipalId();
final String identityName = con.getAuthenticationType() == AuthenticationType.SYSTEM_ASSIGNED_MANAGED_IDENTITY ?
target instanceof AzResource ? ((AzResource)target).getName() : target.toString() :
Objects.requireNonNull(con.getUserAssignedManagedIdentity()).getData().getName();
if (resource instanceof AzureServiceResource<?> serviceResource && !checkPermission(serviceResource, identity)) {
if (!IManagedIdentitySupported.grantPermission(serviceResource, identity)) {
final String message = String.format("The managed identity %s (%s) doesn't have enough permission to access resource %s.", identity, identityName, resource.getName());
final Action<?> openIdentityConfigurationAction = getOpenIdentityConfigurationAction(serviceResource);
final Action<?> grantPermissionAction = getGrantPermissionAction(serviceResource, identity);
AzureMessager.getMessager().warning(message, openIdentityConfigurationAction, grantPermissionAction);
}
}
});
}
public static <T extends ManagedIdentitySupport> void updateResourceConnectionWithIdentity(T target, Profile profile) {
final IdentityConfiguration current = target.getIdentityConfiguration();
final boolean currentSystemIdentityEnabled = Optional.ofNullable(current).map(IdentityConfiguration::isEnableSystemAssignedManagedIdentity).orElse(false);
final List<Identity> currentIdentities = Optional.ofNullable(current).map(IdentityConfiguration::getUserAssignedManagedIdentities).orElse(Collections.emptyList());
final List<Connection<?, ?>> list = profile.getConnections().stream().filter(Connection::isManagedIdentityConnection).toList();
final boolean shouldEnableSystemManagedIdentity = list.stream().anyMatch(c -> c.getAuthenticationType() == AuthenticationType.SYSTEM_ASSIGNED_MANAGED_IDENTITY);
final List<Identity> connectionIdentities = list.stream()
.map(Connection::getUserAssignedManagedIdentity).filter(Objects::nonNull).map(Resource::getData).filter(Objects::nonNull).toList();
if (shouldEnableSystemManagedIdentity == currentSystemIdentityEnabled && CollectionUtils.containsAll(currentIdentities, connectionIdentities)) {
return;
}
final List<Identity> identities = Stream.concat(currentIdentities.stream(), connectionIdentities.stream()).toList();
final IdentityConfiguration updatedConfiguration = IdentityConfiguration.builder()
.enableSystemAssignedManagedIdentity(shouldEnableSystemManagedIdentity || currentSystemIdentityEnabled)
.userAssignedManagedIdentities(identities)
.build();
if (!Objects.equals(updatedConfiguration, current)) {
target.updateIdentityConfiguration(updatedConfiguration);
}
}
@NotNull
private WebAppBase<?, ?, ?> getOrCreateDeployTarget() {
private WebAppBase<?, ?, ?> getOrCreateDeployTarget(@Nullable final AzureModule module) {
final AppServiceConfig appServiceConfig = webAppConfiguration.getAppServiceConfig();
applyResourceConnections(webAppConfiguration, appServiceConfig);
cleanupRemovedAppSettings(appServiceConfig);
final WebAppBase<?, ?, ?> result = new CreateOrUpdateWebAppTask(appServiceConfig).execute();
final AzureTaskManager tm = AzureTaskManager.getInstance();
final AzureModule module = Optional.ofNullable(this.webAppConfiguration.getModule()).map(AzureModule::from)
.or(() -> Optional.ofNullable(getTargetPath())
.map(f -> VfsUtil.findFile(Path.of(f), true))
.map(f -> AzureModule.from(f, this.project))).orElse(null);
if (Objects.nonNull(module)) {
final AbstractAzResource<?, ?, ?> target = result instanceof WebAppDeploymentSlot ? result.getParent() : result;
tm.runOnPooledThread(() -> tm.runLater(() -> tm.write(() -> module.initializeWithDefaultProfileIfNot().addApp(target).save())));

Просмотреть файл

@ -42,8 +42,8 @@ allprojects {
}
ext {
azureToolkitLibsVersion = "0.47.0-SNAPSHOT"
azureToolkitIdeLibsVersion = "0.47.0-SNAPSHOT"
azureToolkitLibsVersion = "0.47.0"
azureToolkitIdeLibsVersion = "0.47.0"
}
dependencyManagement {

Просмотреть файл

@ -1,4 +1,4 @@
pluginVersion=3.91.0-SNAPSHOT
pluginVersion=3.91.0
intellijDisplayVersion=2024.2
intellij_version=IU-242-EAP-SNAPSHOT
scala_plugin=org.intellij.scala:2024.2.5

Просмотреть файл

@ -2,7 +2,7 @@
xmlns:xi="http://www.w3.org/2001/XInclude">
<id>com.microsoft.tooling.msservices.intellij.azure</id>
<name>Azure Toolkit</name>
<version>3.91.0-SNAPSHOT</version>
<version>3.91.0</version>
<vendor email="java@microsoft.com" url="http://www.microsoft.com">Microsoft</vendor>
<description>

Просмотреть файл

@ -16,6 +16,8 @@ dependencies {
implementation("com.microsoft.azure:azure-toolkit-cosmos-lib")
implementation("com.microsoft.azure:azure-toolkit-ide-common-lib")
implementation("com.microsoft.azure:azure-toolkit-ide-cosmos-lib")
implementation("com.microsoft.azure:azure-toolkit-identity-lib")
intellijPlatform {
intellijIdeaUltimate(properties("platformVersion").get())
// Plugin Dependencies. Uses `platformBundledPlugins` property from the gradle.properties file for bundled IntelliJ Platform plugins.

Просмотреть файл

@ -41,6 +41,9 @@ public class CosmosDatabaseResourcePanel<T extends ICosmosDatabase, E extends Co
this.cbDatabase.setRequired(true);
this.cbSubscription.addItemListener(this::onSubscriptionChanged);
this.cbAccount.addItemListener(this::onAccountChanged);
this.cbDatabase.addValueChangedListener(ignore -> Optional.ofNullable(getValue()).ifPresent(this::fireValueChangedEvent));
}
private void onSubscriptionChanged(ItemEvent e) {

Просмотреть файл

@ -1,12 +1,15 @@
package com.microsoft.azure.toolkit.intellij.cosmos.connection;
import com.azure.resourcemanager.authorization.models.BuiltInRole;
import com.intellij.openapi.project.Project;
import com.microsoft.azure.toolkit.ide.common.icon.AzureIcons;
import com.microsoft.azure.toolkit.intellij.common.AzureFormJPanel;
import com.microsoft.azure.toolkit.intellij.connector.AuthenticationType;
import com.microsoft.azure.toolkit.intellij.connector.AzureServiceResource;
import com.microsoft.azure.toolkit.intellij.connector.Connection;
import com.microsoft.azure.toolkit.intellij.connector.Resource;
import com.microsoft.azure.toolkit.intellij.connector.function.FunctionSupported;
import com.microsoft.azure.toolkit.intellij.connector.spring.SpringManagedIdentitySupported;
import com.microsoft.azure.toolkit.intellij.connector.spring.SpringSupported;
import com.microsoft.azure.toolkit.lib.Azure;
import com.microsoft.azure.toolkit.lib.common.model.Subscription;
@ -18,16 +21,13 @@ import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class SqlCosmosDBAccountResourceDefinition extends AzureServiceResource.Definition<SqlDatabase>
implements SpringSupported<SqlDatabase>, FunctionSupported<SqlDatabase> {
implements SpringSupported<SqlDatabase>, FunctionSupported<SqlDatabase>, SpringManagedIdentitySupported<SqlDatabase> {
public static final SqlCosmosDBAccountResourceDefinition INSTANCE = new SqlCosmosDBAccountResourceDefinition();
public SqlCosmosDBAccountResourceDefinition() {
@ -96,4 +96,43 @@ public class SqlCosmosDBAccountResourceDefinition extends AzureServiceResource.D
public String getResourceConnectionString(@Nonnull SqlDatabase resource) {
return resource.getModule().getParent().getCosmosDBAccountPrimaryConnectionString().getConnectionString();
}
@Override
public Map<String, String> initIdentityEnv(Connection<SqlDatabase, ?> data, Project project) {
final SqlDatabase database = data.getResource().getData();
final CosmosDBAccount account = database.getParent();
final HashMap<String, String> env = new HashMap<>();
env.put(String.format("%s_ENDPOINT", Connection.ENV_PREFIX), account.getDocumentEndpoint());
env.put(String.format("%s_DATABASE", Connection.ENV_PREFIX), database.getName());
if (data.getAuthenticationType() == AuthenticationType.USER_ASSIGNED_MANAGED_IDENTITY) {
Optional.ofNullable(data.getUserAssignedManagedIdentity()).map(Resource::getData)
.ifPresent(identity -> env.put(String.format("%s_CLIENT_ID", Connection.ENV_PREFIX), identity.getClientId()));
}
return env;
}
@Override
public List<String> getRequiredPermissions() {
return List.of("Microsoft.DocumentDB/databaseAccounts/readMetadata",
"Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*",
"Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*");
}
@Nullable
@Override
public Map<String, BuiltInRole> getBuiltInRoles() {
return null;
}
@Override
public List<Pair<String, String>> getSpringPropertiesForManagedIdentity(String key, Connection<?, ?> connection) {
final List<Pair<String, String>> properties = new ArrayList<>();
properties.add(Pair.of("spring.cloud.azure.cosmos.endpoint", String.format("${%s_ENDPOINT}", Connection.ENV_PREFIX)));
properties.add(Pair.of("spring.cloud.azure.cosmos.database", String.format("${%s_DATABASE}", Connection.ENV_PREFIX)));
// properties.add(Pair.of("spring.cloud.azure.cosmos.credential.managed-identity-enabled", String.valueOf(true)));
if (connection.getAuthenticationType() == AuthenticationType.USER_ASSIGNED_MANAGED_IDENTITY) {
properties.add(Pair.of("spring.cloud.azure.cosmos.credential.client-id", String.format("${%s_CLIENT_ID}", Connection.ENV_PREFIX)));
}
return properties;
}
}

Просмотреть файл

@ -0,0 +1,20 @@
dependencies {
implementation(project(":azure-intellij-plugin-lib"))
// runtimeOnly project(path: ":azure-intellij-plugin-lib", configuration: "instrumentedJar")
implementation(project(":azure-intellij-resource-connector-lib"))
// runtimeOnly project(path: ":azure-intellij-resource-connector-lib", configuration: "instrumentedJar")
implementation(project(":azure-intellij-resource-connector-lib-java"))
// runtimeOnly project(path: ":azure-intellij-resource-connector-lib-java", configuration: "instrumentedJar")
implementation(project(":azure-intellij-plugin-keyvault"))
// runtimeOnly project(path: ":azure-intellij-plugin-keyvault", configuration: "instrumentedJar")
implementation("com.microsoft.azure:azure-toolkit-keyvault-lib")
implementation("com.microsoft.azure:azure-toolkit-ide-common-lib")
implementation("com.microsoft.azure:azure-toolkit-ide-keyvault-lib")
implementation("com.microsoft.azure:azure-toolkit-identity-lib")
intellijPlatform {
// Plugin Dependencies. Uses `platformBundledPlugins` property from the gradle.properties file for bundled IntelliJ Platform plugins.
bundledPlugin("com.intellij.java")
bundledPlugin("org.jetbrains.plugins.yaml")
bundledPlugin("com.intellij.properties")
}
}

Просмотреть файл

@ -0,0 +1,29 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
package com.microsoft.azure.toolkit.intellij.keyvault;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.microsoft.azure.toolkit.ide.common.IActionsContributor;
import com.microsoft.azure.toolkit.ide.common.action.ResourceCommonActionsContributor;
import com.microsoft.azure.toolkit.intellij.connector.AzureServiceResource;
import com.microsoft.azure.toolkit.intellij.connector.ConnectorDialog;
import com.microsoft.azure.toolkit.intellij.keyvault.connection.KeyVaultResourceDefinition;
import com.microsoft.azure.toolkit.lib.common.action.AzureActionManager;
import com.microsoft.azure.toolkit.lib.common.model.AzResource;
import com.microsoft.azure.toolkit.lib.common.task.AzureTaskManager;
import com.microsoft.azure.toolkit.lib.keyvault.KeyVault;
public class IntellijJavaKeyVaultActionsContributor implements IActionsContributor {
@Override
public void registerHandlers(AzureActionManager am) {
am.<AzResource, AnActionEvent>registerHandler(ResourceCommonActionsContributor.CONNECT, (r, e) -> r instanceof KeyVault,
(r, e) -> AzureTaskManager.getInstance().runLater(() -> {
final ConnectorDialog dialog = new ConnectorDialog(e.getProject());
dialog.setResource(new AzureServiceResource<>(((KeyVault) r), KeyVaultResourceDefinition.INSTANCE));
dialog.show();
}));
}
}

Просмотреть файл

@ -5,46 +5,34 @@
package com.microsoft.azure.toolkit.intellij.keyvault.connection;
import com.azure.resourcemanager.authorization.models.BuiltInRole;
import com.intellij.openapi.project.Project;
import com.microsoft.azure.toolkit.ide.common.icon.AzureIcons;
import com.microsoft.azure.toolkit.intellij.common.AzureFormJPanel;
import com.microsoft.azure.toolkit.intellij.connector.AzureServiceResource;
import com.microsoft.azure.toolkit.intellij.connector.AuthenticationType;
import com.microsoft.azure.toolkit.intellij.connector.Connection;
import com.microsoft.azure.toolkit.intellij.connector.Resource;
import com.microsoft.azure.toolkit.intellij.connector.spring.SpringManagedIdentitySupported;
import com.microsoft.azure.toolkit.intellij.connector.spring.SpringSupported;
import com.microsoft.azure.toolkit.lib.Azure;
import com.microsoft.azure.toolkit.lib.auth.AzureCloud;
import com.microsoft.azure.toolkit.lib.keyvault.AzureKeyVault;
import com.microsoft.azure.toolkit.lib.keyvault.KeyVault;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
@Getter
public class KeyVaultResourceDefinition extends AzureServiceResource.Definition<KeyVault> implements SpringSupported<KeyVault> {
public class KeyVaultResourceDefinition extends BaseKeyVaultResourceDefinition
implements SpringSupported<KeyVault>, SpringManagedIdentitySupported<KeyVault> {
public static final KeyVaultResourceDefinition INSTANCE = new KeyVaultResourceDefinition();
public KeyVaultResourceDefinition() {
super("Microsoft.KeyVault", "Azure Key Vault", AzureIcons.KeyVault.MODULE.getIconPath());
}
@Override
public String getDefaultEnvPrefix() {
return "KEY_VAULT";
}
@Override
public Map<String, String> initEnv(AzureServiceResource<KeyVault> vaultDef, Project project) {
final KeyVault vault = vaultDef.getData();
final HashMap<String, String> env = new HashMap<>();
env.put(String.format("%s_ENDPOINT", Connection.ENV_PREFIX), vault.getVaultUri());
return env;
public AzureFormJPanel<Resource<KeyVault>> getResourcePanel(Project project) {
return new KeyVaultResourcePanel();
}
@Override
@ -67,19 +55,42 @@ public class KeyVaultResourceDefinition extends AzureServiceResource.Definition<
}
@Override
public KeyVault getResource(String dataId, final String id) {
return Azure.az(AzureKeyVault.class).getById(dataId);
public List<Pair<String, String>> getSpringPropertiesForManagedIdentity(String key, Connection<?, ?> connection) {
final ArrayList<Pair<String, String>> result = new ArrayList<>(getSpringProperties(key));
result.add(Pair.of("spring.cloud.azure.keyvault.secret.property-sources[0].credential.managed-identity-enabled", String.valueOf(Boolean.TRUE)));
if (connection.getAuthenticationType() == AuthenticationType.USER_ASSIGNED_MANAGED_IDENTITY) {
result.add(Pair.of("spring.cloud.azure.keyvault.secret.property-sources[0].credential.client-id", String.format("${%s_CLIENT_ID}", Connection.ENV_PREFIX)));
}
return result;
}
@Override
public List<Resource<KeyVault>> getResources(Project project) {
return Azure.az(AzureKeyVault.class).list().stream()
.flatMap(m -> m.getKeyVaultModule().list().stream())
.map(this::define).toList();
public Map<String, String> initIdentityEnv(Connection<KeyVault, ?> data, Project project) {
final KeyVault vault = data.getResource().getData();
final HashMap<String, String> env = new HashMap<>();
env.put(String.format("%s_ENDPOINT", Connection.ENV_PREFIX), vault.getVaultUri());
if (data.getAuthenticationType() == AuthenticationType.USER_ASSIGNED_MANAGED_IDENTITY) {
Optional.ofNullable(data.getUserAssignedManagedIdentity()).map(Resource::getData)
.ifPresent(identity -> env.put(String.format("%s_CLIENT_ID", Connection.ENV_PREFIX), identity.getClientId()));
}
return env;
}
@Override
public AzureFormJPanel<Resource<KeyVault>> getResourcePanel(Project project) {
return new KeyVaultResourcePanel();
public List<String> getRequiredPermissions() {
return List.of(
"Microsoft.KeyVault/vaults/secrets/getSecret/action",
"Microsoft.KeyVault/vaults/secrets/readMetadata/action",
"Microsoft.KeyVault/vaults/keys/read"
);
}
@Nullable
@Override
public Map<String, BuiltInRole> getBuiltInRoles() {
return Map.of(
"4633458b-17de-408a-b874-0445c86b69e6", BuiltInRole.KEY_VAULT_SECRETS_USER,
"12338af0-0e69-4776-bea7-57ae8d297424", BuiltInRole.KEY_VAULT_CRYPTO_USER
);
}
}

Просмотреть файл

@ -48,6 +48,7 @@ public class KeyVaultResourcePanel implements AzureFormJPanel<Resource<KeyVault>
this.vaultComboBox.clear();
}
});
this.vaultComboBox.addValueChangedListener(ignore -> Optional.ofNullable(getValue()).ifPresent(this::fireValueChangedEvent));
}
@Override
@ -64,7 +65,7 @@ public class KeyVaultResourcePanel implements AzureFormJPanel<Resource<KeyVault>
public Resource<KeyVault> getValue() {
final KeyVault cache = this.vaultComboBox.getValue();
final AzureValidationInfo info = this.getValidationInfo(true);
if (!info.isValid()) {
if (info.getType() == AzureValidationInfo.Type.ERROR) {
return null;
}
return KeyVaultResourceDefinition.INSTANCE.define(cache);

Просмотреть файл

@ -0,0 +1,27 @@
<idea-plugin>
<extensions defaultExtensionNs="com.microsoft.tooling.msservices.intellij.azure">
<connectorResourceType implementation="com.microsoft.azure.toolkit.intellij.keyvault.connection.KeyVaultResourceDefinition"/>
<actions implementation="com.microsoft.azure.toolkit.intellij.keyvault.IntellijJavaKeyVaultActionsContributor"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">
<completion.confidence id="azKeyVaultValueAnnotation" language="JAVA"
implementationClass="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarConfidence"
order="before javaSkipAutopopupInStrings"/>
<completion.contributor language="JAVA" id="azKeyVaultAnnotationCompletion" order="before azStorageStringLiteral, first"
implementationClass="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarCompletionContributor"/>
<completion.contributor language="Properties" id="azKeyVaultPropertiesCompletion" order="before azPropertiesCompletion, first"
implementationClass="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarCompletionContributor"/>
<completion.contributor language="yaml" id="azKeyVaultYamlCompletion" order="first, before azYamlCompletion"
implementationClass="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarCompletionContributor"/>
<psi.referenceContributor language="JAVA" implementation="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarReferenceContributor" order="first"/>
<psi.referenceContributor language="Properties" implementation="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarReferenceContributor" order="first"/>
<psi.referenceContributor language="yaml" implementation="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarReferenceContributor" order="first"/>
<codeInsight.lineMarkerProvider language="JAVA" implementationClass="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarLineMarkerProvider"/>
<codeInsight.lineMarkerProvider language="Properties" implementationClass="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarLineMarkerProvider"/>
<codeInsight.lineMarkerProvider language="yaml" implementationClass="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarLineMarkerProvider"/>
<annotator language="Properties" implementationClass="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.PlainTextSecretAnnotator"/>
<annotator language="yaml" implementationClass="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.PlainTextSecretAnnotator"/>
<typedHandler implementation="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarTypeHandler"/>
<lookup.charFilter order="first, before azProperties" implementation="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarCharFilter"/>
</extensions>
</idea-plugin>

Просмотреть файл

@ -3,14 +3,12 @@ dependencies {
// runtimeOnly project(path: ":azure-intellij-plugin-lib", configuration: "instrumentedJar")
implementation(project(":azure-intellij-resource-connector-lib"))
// runtimeOnly project(path: ":azure-intellij-resource-connector-lib", configuration: "instrumentedJar")
implementation(project(":azure-intellij-resource-connector-lib-java"))
// runtimeOnly project(path: ":azure-intellij-resource-connector-lib-java", configuration: "instrumentedJar")
implementation("com.microsoft.azure:azure-toolkit-keyvault-lib")
implementation("com.microsoft.azure:azure-toolkit-ide-common-lib")
implementation("com.microsoft.azure:azure-toolkit-ide-keyvault-lib")
implementation("com.microsoft.azure:azure-toolkit-identity-lib")
intellijPlatform {
// Plugin Dependencies. Uses `platformBundledPlugins` property from the gradle.properties file for bundled IntelliJ Platform plugins.
bundledPlugin("com.intellij.java")
bundledPlugin("org.jetbrains.plugins.yaml")
bundledPlugin("com.intellij.properties")
}

Просмотреть файл

@ -9,18 +9,12 @@ import com.intellij.openapi.actionSystem.AnActionEvent;
import com.microsoft.azure.toolkit.ide.common.IActionsContributor;
import com.microsoft.azure.toolkit.ide.common.action.ResourceCommonActionsContributor;
import com.microsoft.azure.toolkit.ide.keyvault.KeyVaultActionsContributor;
import com.microsoft.azure.toolkit.intellij.connector.AzureServiceResource;
import com.microsoft.azure.toolkit.intellij.connector.ConnectorDialog;
import com.microsoft.azure.toolkit.intellij.keyvault.connection.KeyVaultResourceDefinition;
import com.microsoft.azure.toolkit.intellij.keyvault.creation.certificate.CertificateCreationActions;
import com.microsoft.azure.toolkit.intellij.keyvault.creation.key.KeyCreationActions;
import com.microsoft.azure.toolkit.intellij.keyvault.creation.secret.SecretCreationActions;
import com.microsoft.azure.toolkit.lib.common.action.AzureActionManager;
import com.microsoft.azure.toolkit.lib.common.model.AzResource;
import com.microsoft.azure.toolkit.lib.common.task.AzureTaskManager;
import com.microsoft.azure.toolkit.lib.keyvault.AzureKeyVault;
import com.microsoft.azure.toolkit.lib.keyvault.CredentialVersion;
import com.microsoft.azure.toolkit.lib.keyvault.KeyVault;
import com.microsoft.azure.toolkit.lib.keyvault.certificate.Certificate;
import com.microsoft.azure.toolkit.lib.keyvault.certificate.CertificateModule;
import com.microsoft.azure.toolkit.lib.keyvault.key.Key;
@ -43,13 +37,6 @@ public class IntelliJKeyVaultActionsContributor implements IActionsContributor {
am.registerHandler(KeyVaultActionsContributor.GROUP_CREATE_KEY_VAULT, (r, e) -> true,
(ResourceGroup group, AnActionEvent e) -> createNewKeyVault(getDefaultConfig(group), e.getProject()));
am.<AzResource, AnActionEvent>registerHandler(ResourceCommonActionsContributor.CONNECT, (r, e) -> r instanceof KeyVault,
(r, e) -> AzureTaskManager.getInstance().runLater(() -> {
final ConnectorDialog dialog = new ConnectorDialog(e.getProject());
dialog.setResource(new AzureServiceResource<>(((KeyVault) r), KeyVaultResourceDefinition.INSTANCE));
dialog.show();
}));
final BiPredicate<CredentialVersion, AnActionEvent> certificateCondition = (r, e) -> r instanceof CredentialVersion;
am.registerHandler(KeyVaultActionsContributor.DOWNLOAD_CREDENTIAL_VERSION, certificateCondition,
(CredentialVersion r, AnActionEvent e) -> KeyVaultCredentialActions.downloadCredential(r, e.getProject()));

Просмотреть файл

@ -0,0 +1,53 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
package com.microsoft.azure.toolkit.intellij.keyvault.connection;
import com.intellij.openapi.project.Project;
import com.microsoft.azure.toolkit.ide.common.icon.AzureIcons;
import com.microsoft.azure.toolkit.intellij.connector.AzureServiceResource;
import com.microsoft.azure.toolkit.intellij.connector.Connection;
import com.microsoft.azure.toolkit.intellij.connector.Resource;
import com.microsoft.azure.toolkit.lib.Azure;
import com.microsoft.azure.toolkit.lib.keyvault.AzureKeyVault;
import com.microsoft.azure.toolkit.lib.keyvault.KeyVault;
import lombok.Getter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Getter
public abstract class BaseKeyVaultResourceDefinition extends AzureServiceResource.Definition<KeyVault> {
public BaseKeyVaultResourceDefinition() {
super("Microsoft.KeyVault", "Azure Key Vault", AzureIcons.KeyVault.MODULE.getIconPath());
}
@Override
public String getDefaultEnvPrefix() {
return "KEY_VAULT";
}
@Override
public Map<String, String> initEnv(AzureServiceResource<KeyVault> vaultDef, Project project) {
final KeyVault vault = vaultDef.getData();
final HashMap<String, String> env = new HashMap<>();
env.put(String.format("%s_ENDPOINT", Connection.ENV_PREFIX), vault.getVaultUri());
return env;
}
@Override
public KeyVault getResource(String dataId, final String id) {
return Azure.az(AzureKeyVault.class).getById(dataId);
}
@Override
public List<Resource<KeyVault>> getResources(Project project) {
return Azure.az(AzureKeyVault.class).list().stream()
.flatMap(m -> m.getKeyVaultModule().list().stream())
.map(this::define).toList();
}
}

Просмотреть файл

@ -1,6 +1,5 @@
<idea-plugin>
<extensions defaultExtensionNs="com.microsoft.tooling.msservices.intellij.azure">
<connectorResourceType implementation="com.microsoft.azure.toolkit.intellij.keyvault.connection.KeyVaultResourceDefinition"/>
<explorerNodeProvider implementation="com.microsoft.azure.toolkit.ide.keyvault.KeyVaultNodeProvider"/>
<actions implementation="com.microsoft.azure.toolkit.ide.keyvault.KeyVaultActionsContributor"/>
<actions implementation="com.microsoft.azure.toolkit.intellij.keyvault.IntelliJKeyVaultActionsContributor"/>
@ -13,25 +12,4 @@
<fileEditorProvider implementation="com.microsoft.azure.toolkit.intellij.keyvault.property.key.KeyPropertiesEditorProvider"/>
<fileEditorProvider implementation="com.microsoft.azure.toolkit.intellij.keyvault.property.key.KeyVersionPropertiesEditorProvider"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">
<completion.confidence id="azKeyVaultValueAnnotation" language="JAVA"
implementationClass="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarConfidence"
order="before javaSkipAutopopupInStrings"/>
<completion.contributor language="JAVA" id="azKeyVaultAnnotationCompletion" order="before azStorageStringLiteral, first"
implementationClass="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarCompletionContributor"/>
<completion.contributor language="Properties" id="azKeyVaultPropertiesCompletion" order="before azPropertiesCompletion, first"
implementationClass="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarCompletionContributor"/>
<completion.contributor language="yaml" id="azKeyVaultYamlCompletion" order="first, before azYamlCompletion"
implementationClass="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarCompletionContributor"/>
<psi.referenceContributor language="JAVA" implementation="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarReferenceContributor" order="first"/>
<psi.referenceContributor language="Properties" implementation="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarReferenceContributor" order="first"/>
<psi.referenceContributor language="yaml" implementation="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarReferenceContributor" order="first"/>
<codeInsight.lineMarkerProvider language="JAVA" implementationClass="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarLineMarkerProvider"/>
<codeInsight.lineMarkerProvider language="Properties" implementationClass="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarLineMarkerProvider"/>
<codeInsight.lineMarkerProvider language="yaml" implementationClass="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarLineMarkerProvider"/>
<annotator language="Properties" implementationClass="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.PlainTextSecretAnnotator"/>
<annotator language="yaml" implementationClass="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.PlainTextSecretAnnotator"/>
<typedHandler implementation="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarTypeHandler"/>
<lookup.charFilter order="first, before azProperties" implementation="com.microsoft.azure.toolkit.intellij.keyvault.code.spring.EnvVarCharFilter"/>
</extensions>
</idea-plugin>

Просмотреть файл

@ -0,0 +1,13 @@
dependencies {
implementation(project(":azure-intellij-plugin-lib"))
// runtimeOnly project(path: ":azure-intellij-plugin-lib", configuration: "instrumentedJar")
implementation(project(":azure-intellij-resource-connector-lib"))
// runtimeOnly project(path: ":azure-intellij-resource-connector-lib", configuration: "instrumentedJar")
implementation(project(":azure-intellij-resource-connector-lib-java"))
// runtimeOnly project(path: ":azure-intellij-resource-connector-lib-java", configuration: "instrumentedJar")
implementation(project(":azure-intellij-plugin-redis"))
// runtimeOnly project(path: ":azure-intellij-plugin-redis", configuration: "instrumentedJar")
implementation("com.microsoft.azure:azure-toolkit-redis-lib")
implementation("com.microsoft.azure:azure-toolkit-ide-common-lib")
implementation("com.microsoft.azure:azure-toolkit-ide-redis-lib")
}

Просмотреть файл

@ -0,0 +1,29 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
package com.microsoft.azure.toolkit.intellij.redis;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.microsoft.azure.toolkit.ide.common.IActionsContributor;
import com.microsoft.azure.toolkit.ide.common.action.ResourceCommonActionsContributor;
import com.microsoft.azure.toolkit.intellij.connector.AzureServiceResource;
import com.microsoft.azure.toolkit.intellij.connector.ConnectorDialog;
import com.microsoft.azure.toolkit.intellij.redis.connection.RedisResourceDefinition;
import com.microsoft.azure.toolkit.lib.common.action.AzureActionManager;
import com.microsoft.azure.toolkit.lib.common.model.AzResource;
import com.microsoft.azure.toolkit.lib.common.task.AzureTaskManager;
import com.microsoft.azure.toolkit.redis.RedisCache;
public class IntellijJavaRedisActionsContributor implements IActionsContributor {
@Override
public void registerHandlers(AzureActionManager am) {
am.<AzResource, AnActionEvent>registerHandler(ResourceCommonActionsContributor.CONNECT, (r, e) -> r instanceof RedisCache,
(r, e) -> AzureTaskManager.getInstance().runLater(() -> {
final ConnectorDialog dialog = new ConnectorDialog(e.getProject());
dialog.setResource(new AzureServiceResource<>(((RedisCache) r), RedisResourceDefinition.INSTANCE));
dialog.show();
}));
}
}

Просмотреть файл

@ -0,0 +1,41 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
package com.microsoft.azure.toolkit.intellij.redis.connection;
import com.intellij.openapi.project.Project;
import com.microsoft.azure.toolkit.intellij.common.AzureFormJPanel;
import com.microsoft.azure.toolkit.intellij.connector.Connection;
import com.microsoft.azure.toolkit.intellij.connector.Resource;
import com.microsoft.azure.toolkit.intellij.connector.spring.SpringSupported;
import com.microsoft.azure.toolkit.lib.Azure;
import com.microsoft.azure.toolkit.lib.auth.AzureCloud;
import com.microsoft.azure.toolkit.redis.RedisCache;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class RedisResourceDefinition extends BaseRedisResourceDefinition implements SpringSupported<RedisCache> {
public static final RedisResourceDefinition INSTANCE = new RedisResourceDefinition();
@Override
public List<Pair<String, String>> getSpringProperties(@Nullable final String key) {
final List<Pair<String, String>> properties = new ArrayList<>();
final String suffix = Azure.az(AzureCloud.class).get().getStorageEndpointSuffix();
properties.add(Pair.of("spring.data.redis.host", String.format("${%s_HOST}", Connection.ENV_PREFIX)));
properties.add(Pair.of("spring.data.redis.port", String.format("${%s_PORT}", Connection.ENV_PREFIX)));
properties.add(Pair.of("spring.data.redis.password", String.format("${%s_KEY}", Connection.ENV_PREFIX)));
properties.add(Pair.of("spring.data.redis.ssl.enabled", String.format("${%s_SSL}", Connection.ENV_PREFIX)));
return properties;
}
@Override
public AzureFormJPanel<Resource<RedisCache>> getResourcePanel(Project project) {
return new RedisResourcePanel();
}
}

Просмотреть файл

@ -0,0 +1,6 @@
<idea-plugin>
<extensions defaultExtensionNs="com.microsoft.tooling.msservices.intellij.azure">
<connectorResourceType implementation="com.microsoft.azure.toolkit.intellij.redis.connection.RedisResourceDefinition"/>
<actions implementation="com.microsoft.azure.toolkit.intellij.redis.IntellijJavaRedisActionsContributor"/>
</extensions>
</idea-plugin>

Просмотреть файл

@ -3,8 +3,6 @@ dependencies {
// runtimeOnly project(path: ":azure-intellij-plugin-lib", configuration: "instrumentedJar")
implementation(project(":azure-intellij-resource-connector-lib"))
// runtimeOnly project(path: ":azure-intellij-resource-connector-lib", configuration: "instrumentedJar")
implementation(project(":azure-intellij-resource-connector-lib-java"))
// runtimeOnly project(path: ":azure-intellij-resource-connector-lib-java", configuration: "instrumentedJar")
implementation("com.microsoft.azure:azure-toolkit-redis-lib")
implementation("com.microsoft.azure:azure-toolkit-ide-common-lib")
implementation("com.microsoft.azure:azure-toolkit-ide-redis-lib")

Просмотреть файл

@ -13,14 +13,10 @@ import com.microsoft.azure.toolkit.ide.redis.RedisActionsContributor;
import com.microsoft.azure.toolkit.intellij.common.IntelliJAzureIcons;
import com.microsoft.azure.toolkit.intellij.common.properties.AzureResourceEditorViewManager;
import com.microsoft.azure.toolkit.intellij.common.properties.AzureResourceEditorViewManager.AzureResourceFileType;
import com.microsoft.azure.toolkit.intellij.connector.AzureServiceResource;
import com.microsoft.azure.toolkit.intellij.connector.ConnectorDialog;
import com.microsoft.azure.toolkit.intellij.redis.connection.RedisResourceDefinition;
import com.microsoft.azure.toolkit.intellij.redis.creation.CreateRedisCacheAction;
import com.microsoft.azure.toolkit.intellij.redis.explorer.RedisCacheExplorerProvider;
import com.microsoft.azure.toolkit.lib.common.action.AzureActionManager;
import com.microsoft.azure.toolkit.lib.common.model.AzResource;
import com.microsoft.azure.toolkit.lib.common.task.AzureTaskManager;
import com.microsoft.azure.toolkit.lib.resource.ResourceGroup;
import com.microsoft.azure.toolkit.redis.AzureRedis;
import com.microsoft.azure.toolkit.redis.RedisCache;
@ -38,12 +34,6 @@ public class IntellijRedisActionsContributor implements IActionsContributor {
final BiConsumer<Object, AnActionEvent> handler = (c, e) -> CreateRedisCacheAction.create(e.getProject(), null);
am.registerHandler(ResourceCommonActionsContributor.CREATE, condition, handler);
am.<AzResource, AnActionEvent>registerHandler(ResourceCommonActionsContributor.CONNECT, (r, e) -> r instanceof RedisCache,
(r, e) -> AzureTaskManager.getInstance().runLater(() -> {
final ConnectorDialog dialog = new ConnectorDialog(e.getProject());
dialog.setResource(new AzureServiceResource<>(((RedisCache) r), RedisResourceDefinition.INSTANCE));
dialog.show();
}));
final Icon icon = IntelliJAzureIcons.getIcon(AzureIcons.RedisCache.MODULE);
final String name = RedisCacheExplorerProvider.TYPE;
final AzureResourceFileType type = new AzureResourceFileType(name, icon);

Просмотреть файл

@ -7,29 +7,21 @@ package com.microsoft.azure.toolkit.intellij.redis.connection;
import com.intellij.openapi.project.Project;
import com.microsoft.azure.toolkit.ide.common.icon.AzureIcons;
import com.microsoft.azure.toolkit.intellij.common.AzureFormJPanel;
import com.microsoft.azure.toolkit.intellij.connector.AzureServiceResource;
import com.microsoft.azure.toolkit.intellij.connector.Connection;
import com.microsoft.azure.toolkit.intellij.connector.Resource;
import com.microsoft.azure.toolkit.intellij.connector.spring.SpringSupported;
import com.microsoft.azure.toolkit.lib.Azure;
import com.microsoft.azure.toolkit.lib.auth.AzureCloud;
import com.microsoft.azure.toolkit.redis.AzureRedis;
import com.microsoft.azure.toolkit.redis.RedisCache;
import lombok.Getter;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Getter
public class RedisResourceDefinition extends AzureServiceResource.Definition<RedisCache> implements SpringSupported<RedisCache> {
public static final RedisResourceDefinition INSTANCE = new RedisResourceDefinition();
public RedisResourceDefinition() {
public abstract class BaseRedisResourceDefinition extends AzureServiceResource.Definition<RedisCache> {
public BaseRedisResourceDefinition() {
super("Azure.Redis", "Azure Redis Cache", AzureIcons.RedisCache.MODULE.getIconPath());
}
@ -44,17 +36,6 @@ public class RedisResourceDefinition extends AzureServiceResource.Definition<Red
return env;
}
@Override
public List<Pair<String, String>> getSpringProperties(@Nullable final String key) {
final List<Pair<String, String>> properties = new ArrayList<>();
final String suffix = Azure.az(AzureCloud.class).get().getStorageEndpointSuffix();
properties.add(Pair.of("spring.data.redis.host", String.format("${%s_HOST}", Connection.ENV_PREFIX)));
properties.add(Pair.of("spring.data.redis.port", String.format("${%s_PORT}", Connection.ENV_PREFIX)));
properties.add(Pair.of("spring.data.redis.password", String.format("${%s_KEY}", Connection.ENV_PREFIX)));
properties.add(Pair.of("spring.data.redis.ssl.enabled", String.format("${%s_SSL}", Connection.ENV_PREFIX)));
return properties;
}
@Override
public RedisCache getResource(String dataId, final String id) {
return Azure.az(AzureRedis.class).getById(dataId);
@ -66,9 +47,4 @@ public class RedisResourceDefinition extends AzureServiceResource.Definition<Red
.flatMap(m -> m.caches().list().stream())
.map(this::define).toList();
}
@Override
public AzureFormJPanel<Resource<RedisCache>> getResourcePanel(Project project) {
return new RedisResourcePanel();
}
}

Просмотреть файл

@ -1,6 +1,5 @@
<idea-plugin>
<extensions defaultExtensionNs="com.microsoft.tooling.msservices.intellij.azure">
<connectorResourceType implementation="com.microsoft.azure.toolkit.intellij.redis.connection.RedisResourceDefinition"/>
<explorerNodeProvider implementation="com.microsoft.azure.toolkit.ide.redis.RedisNodeProvider"/>
<actions implementation="com.microsoft.azure.toolkit.ide.redis.RedisActionsContributor"/>
<actions implementation="com.microsoft.azure.toolkit.intellij.redis.IntellijRedisActionsContributor"/>

Просмотреть файл

@ -0,0 +1,19 @@
dependencies {
implementation(project(":azure-intellij-plugin-lib"))
// runtimeOnly project(path: ":azure-intellij-plugin-lib", configuration: "instrumentedJar")
implementation(project(":azure-intellij-resource-connector-lib"))
// runtimeOnly project(path: ":azure-intellij-resource-connector-lib", configuration: "instrumentedJar")
implementation(project(":azure-intellij-resource-connector-lib-java"))
// runtimeOnly project(path: ":azure-intellij-resource-connector-lib-java", configuration: "instrumentedJar")
implementation(project(":azure-intellij-plugin-storage"))
// runtimeOnly project(path: ":azure-intellij-plugin-storage", configuration: "instrumentedJar")
implementation("com.microsoft.azure:azure-toolkit-storage-lib")
implementation("com.microsoft.azure:azure-toolkit-ide-common-lib")
implementation("com.microsoft.azure:azure-toolkit-ide-storage-lib")
implementation("com.microsoft.azure:azure-toolkit-identity-lib")
intellijPlatform {
// Plugin Dependencies. Uses `platformBundledPlugins` property from the gradle.properties file for bundled IntelliJ Platform plugins.
bundledPlugin("com.intellij.java")
}
}

Просмотреть файл

@ -0,0 +1,29 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
package com.microsoft.azure.toolkit.intellij.storage;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.microsoft.azure.toolkit.ide.common.IActionsContributor;
import com.microsoft.azure.toolkit.ide.common.action.ResourceCommonActionsContributor;
import com.microsoft.azure.toolkit.intellij.connector.AzureServiceResource;
import com.microsoft.azure.toolkit.intellij.connector.ConnectorDialog;
import com.microsoft.azure.toolkit.intellij.storage.connection.StorageAccountResourceDefinition;
import com.microsoft.azure.toolkit.lib.common.action.AzureActionManager;
import com.microsoft.azure.toolkit.lib.common.model.AzResource;
import com.microsoft.azure.toolkit.lib.common.task.AzureTaskManager;
import com.microsoft.azure.toolkit.lib.storage.StorageAccount;
public class IntellijJavaStorageActionsContributor implements IActionsContributor {
@Override
public void registerHandlers(AzureActionManager am) {
am.<AzResource, AnActionEvent>registerHandler(ResourceCommonActionsContributor.CONNECT, (r, e) -> r instanceof StorageAccount,
(r, e) -> AzureTaskManager.getInstance().runLater(() -> {
final ConnectorDialog dialog = new ConnectorDialog(e.getProject());
dialog.setResource(new AzureServiceResource<>(((StorageAccount) r), StorageAccountResourceDefinition.INSTANCE));
dialog.show();
}));
}
}

Просмотреть файл

@ -8,7 +8,7 @@ import com.microsoft.azure.toolkit.intellij.connector.Connection;
import com.microsoft.azure.toolkit.intellij.connector.code.function.FunctionUtils;
import com.microsoft.azure.toolkit.intellij.connector.dotazure.AzureModule;
import com.microsoft.azure.toolkit.intellij.connector.dotazure.Profile;
import com.microsoft.azure.toolkit.intellij.storage.connection.StorageAccountResourceDefinition;
import com.microsoft.azure.toolkit.intellij.storage.connection.BaseStorageAccountResourceDefinition;
import com.microsoft.azure.toolkit.lib.storage.IStorageAccount;
import org.apache.commons.lang3.StringUtils;
@ -25,7 +25,7 @@ class Utils {
return Optional.of(module).map(AzureModule::from)
.map(AzureModule::getDefaultProfile).map(Profile::getConnectionManager).stream()
.flatMap(m -> m.getConnections().stream())
.filter(c -> c.getDefinition().getResourceDefinition() instanceof StorageAccountResourceDefinition)
.filter(c -> c.getDefinition().getResourceDefinition() instanceof BaseStorageAccountResourceDefinition)
.filter(c -> Objects.equals(c.getResource().getData(), account))
.toList();
}

Просмотреть файл

@ -25,11 +25,11 @@ import com.microsoft.azure.toolkit.intellij.connector.ConnectorDialog;
import com.microsoft.azure.toolkit.intellij.connector.ModuleResource;
import com.microsoft.azure.toolkit.intellij.connector.code.AnnotationFixes;
import com.microsoft.azure.toolkit.intellij.connector.dotazure.AzureModule;
import com.microsoft.azure.toolkit.intellij.storage.connection.BaseStorageAccountResourceDefinition;
import com.microsoft.azure.toolkit.intellij.storage.connection.StorageAccountResourceDefinition;
import com.microsoft.azure.toolkit.intellij.storage.connection.StorageAccountResourceDefinition.TempData;
import com.microsoft.azure.toolkit.lib.common.operation.AzureOperation;
import com.microsoft.azure.toolkit.lib.storage.ConnectionStringStorageAccount;
import com.microsoft.azure.toolkit.lib.storage.IStorageAccount;
import javax.annotation.Nonnull;
import java.util.Objects;
@ -64,7 +64,7 @@ public class ConnectionStringStorageClientAnnotator implements Annotator {
.anyMatch(s -> s instanceof ConnectionStringStorageAccount);
if (!hasConnectionStringConnection) {
final PsiElement parent = element.getParent();
final TempData tempData = new TempData(StorageAccountResourceDefinition.METHOD_STRING, null);
final TempData tempData = new TempData(BaseStorageAccountResourceDefinition.METHOD_STRING, null);
if (parent instanceof PsiLiteralExpression) {
final PsiLiteralExpression literal = ((PsiLiteralExpression) parent);
final String connectionString = literal.getValue() instanceof String ? (String) literal.getValue() : element.getText();

Просмотреть файл

@ -28,6 +28,7 @@ import com.microsoft.azure.toolkit.intellij.connector.code.Utils;
import com.microsoft.azure.toolkit.intellij.connector.dotazure.AzureModule;
import com.microsoft.azure.toolkit.intellij.connector.dotazure.Profile;
import com.microsoft.azure.toolkit.intellij.connector.projectexplorer.AbstractAzureFacetNode;
import com.microsoft.azure.toolkit.intellij.storage.connection.BaseStorageAccountResourceDefinition;
import com.microsoft.azure.toolkit.intellij.storage.connection.StorageAccountResourceDefinition;
import com.microsoft.azure.toolkit.lib.Azure;
import com.microsoft.azure.toolkit.lib.auth.AzureAccount;
@ -131,7 +132,7 @@ public class StoragePathCompletionProvider extends CompletionProvider<Completion
return Optional.of(module).map(AzureModule::from)
.map(AzureModule::getDefaultProfile).map(Profile::getConnectionManager).stream()
.flatMap(m -> m.getConnections().stream())
.filter(c -> c.getDefinition().getResourceDefinition() instanceof StorageAccountResourceDefinition)
.filter(c -> c.getDefinition().getResourceDefinition() instanceof BaseStorageAccountResourceDefinition)
.filter(c -> c.getResource().isValidResource())
.toList();
}

Просмотреть файл

@ -5,67 +5,54 @@
package com.microsoft.azure.toolkit.intellij.storage.connection;
import com.azure.resourcemanager.resources.fluentcore.arm.ResourceId;
import com.azure.resourcemanager.authorization.models.BuiltInRole;
import com.intellij.openapi.project.Project;
import com.microsoft.azure.toolkit.ide.common.icon.AzureIcons;
import com.microsoft.azure.toolkit.intellij.common.AzureFormJPanel;
import com.microsoft.azure.toolkit.intellij.common.auth.IntelliJSecureStore;
import com.microsoft.azure.toolkit.intellij.connector.AzureServiceResource;
import com.microsoft.azure.toolkit.intellij.connector.AuthenticationType;
import com.microsoft.azure.toolkit.intellij.connector.Connection;
import com.microsoft.azure.toolkit.intellij.connector.Resource;
import com.microsoft.azure.toolkit.intellij.connector.function.FunctionSupported;
import com.microsoft.azure.toolkit.intellij.connector.spring.SpringSupported;
import com.microsoft.azure.toolkit.intellij.connector.spring.SpringManagedIdentitySupported;
import com.microsoft.azure.toolkit.lib.Azure;
import com.microsoft.azure.toolkit.lib.auth.AzureCloud;
import com.microsoft.azure.toolkit.lib.identities.Identity;
import com.microsoft.azure.toolkit.lib.storage.AzureStorageAccount;
import com.microsoft.azure.toolkit.lib.storage.AzuriteStorageAccount;
import com.microsoft.azure.toolkit.lib.storage.ConnectionStringStorageAccount;
import com.microsoft.azure.toolkit.lib.storage.IStorageAccount;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import static com.microsoft.azure.toolkit.lib.common.model.AbstractConnectionStringAzResourceModule.CONNECTION_STRING_SUBSCRIPTION_ID;
@Getter
public class StorageAccountResourceDefinition extends AzureServiceResource.Definition<IStorageAccount>
implements SpringSupported<IStorageAccount>, FunctionSupported<IStorageAccount> {
public static final int METHOD_AZURE = 0;
public static final int METHOD_AZURITE = 1;
public static final int METHOD_STRING = 2;
public class StorageAccountResourceDefinition extends BaseStorageAccountResourceDefinition
implements SpringManagedIdentitySupported<IStorageAccount> {
public static final String CLIENT_ID_KEY = String.format("%s_CLIENT_ID", Connection.ENV_PREFIX);
public static final StorageAccountResourceDefinition INSTANCE = new StorageAccountResourceDefinition();
public static final String LOCAL_STORAGE_CONNECTION_STRING = "UseDevelopmentStorage=true";
public static final String CONNECTION_STRING_KEY = String.format("%s_CONNECTION_STRING", Connection.ENV_PREFIX);
public static final String ACCOUNT_NAME_KEY = String.format("%s_ACCOUNT_NAME", Connection.ENV_PREFIX);
public static final String ACCOUNT_KEY = String.format("%s_ACCOUNT_KEY", Connection.ENV_PREFIX);
@Setter
private TempData tempData;
public StorageAccountResourceDefinition() {
super("Azure.Storage", "Azure Storage Account", AzureIcons.StorageAccount.MODULE.getIconPath());
}
@Override
public Map<String, String> initEnv(AzureServiceResource<IStorageAccount> accountDef, Project project) {
final HashMap<String, String> env = new HashMap<>();
final IStorageAccount account = accountDef.getData();
if (Objects.nonNull(account)) {
final String conString = account.getConnectionString();
env.put(CONNECTION_STRING_KEY, conString);
env.put(ACCOUNT_NAME_KEY, account.getName());
env.put(ACCOUNT_KEY, account.getKey());
public AzureFormJPanel<Resource<IStorageAccount>> getResourcePanel(Project project) {
final StorageAccountResourcePanel panel = new StorageAccountResourcePanel();
if (Objects.nonNull(this.tempData)) {
panel.setMethod(this.tempData.getType());
if (StringUtils.isNotBlank(this.tempData.getConnectionString())) {
final ConnectionStringStorageAccount account = Azure.az(AzureStorageAccount.class).getOrInitByConnectionString(this.tempData.getConnectionString());
if (Objects.nonNull(account)) {
panel.setValue(StorageAccountResourceDefinition.INSTANCE.define(account));
}
}
this.tempData = null;
}
return env;
return panel;
}
@Override
@ -103,59 +90,64 @@ public class StorageAccountResourceDefinition extends AzureServiceResource.Defin
return fields;
}
@Override
public IStorageAccount getResource(String dataId, final String id) {
if (StringUtils.equalsIgnoreCase(dataId, AzuriteStorageAccount.AZURITE_RESOURCE_ID)) {
return AzuriteStorageAccount.AZURITE_STORAGE_ACCOUNT;
} else if (CONNECTION_STRING_SUBSCRIPTION_ID.equalsIgnoreCase(ResourceId.fromString(dataId).subscriptionId())) {
final String connectionString = IntelliJSecureStore.getInstance().loadPassword(StorageAccountResourceDefinition.class.getName(), id.toLowerCase(), null);
if (StringUtils.isNotBlank(connectionString)) {
return Azure.az(AzureStorageAccount.class).getOrInitByConnectionString(connectionString);
}
return null;
} else {
return Azure.az(AzureStorageAccount.class).getById(dataId);
public Map<String, String> initIdentityEnv(Connection<IStorageAccount, ?> connection, Project project) {
final HashMap<String, String> env = new HashMap<>();
final Resource<IStorageAccount> accountDef = connection.getResource();
final IStorageAccount account = accountDef.getData();
if (Objects.nonNull(account)) {
env.put(ACCOUNT_NAME_KEY, account.getName());
}
}
@Override
public List<Resource<IStorageAccount>> getResources(Project project) {
return Azure.az(AzureStorageAccount.class).list().stream()
.flatMap(m -> m.storageAccounts().list().stream())
.map(this::define).toList();
}
@Override
public AzureFormJPanel<Resource<IStorageAccount>> getResourcePanel(Project project) {
final StorageAccountResourcePanel panel = new StorageAccountResourcePanel();
if (Objects.nonNull(this.tempData)) {
panel.setMethod(this.tempData.getType());
if (StringUtils.isNotBlank(this.tempData.getConnectionString())) {
final ConnectionStringStorageAccount account = Azure.az(AzureStorageAccount.class).getOrInitByConnectionString(this.tempData.getConnectionString());
if (Objects.nonNull(account)) {
panel.setValue(StorageAccountResourceDefinition.INSTANCE.define(account));
}
}
this.tempData = null;
if (connection.getAuthenticationType() == AuthenticationType.USER_ASSIGNED_MANAGED_IDENTITY) {
env.put(CLIENT_ID_KEY, Objects.requireNonNull(connection.getUserAssignedManagedIdentity()).getDataId());
}
return panel;
}
@Nonnull
@Override
public String getResourceType() {
return "Storage";
}
@Override
public List<String> getEnvironmentVariablesKey() {
return ListUtils.union(Arrays.asList(CONNECTION_STRING_KEY, ACCOUNT_NAME_KEY, ACCOUNT_KEY), super.getEnvironmentVariablesKey());
return env;
}
@Nullable
@Override
public String getResourceConnectionString(@Nonnull IStorageAccount resource) {
return resource instanceof AzuriteStorageAccount ? LOCAL_STORAGE_CONNECTION_STRING : resource.getConnectionString();
public Map<String, BuiltInRole> getBuiltInRoles() {
return Map.of("ba92f5b4-2d11-453d-a403-e96b0029c9fe", BuiltInRole.STORAGE_BLOB_DATA_CONTRIBUTOR,
"974c5e8b-45b9-4653-ba55-5f855dd0fb88", BuiltInRole.STORAGE_QUEUE_DATA_CONTRIBUTOR,
"0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb", BuiltInRole.STORAGE_FILE_DATA_SMB_SHARE_CONTRIBUTOR);
}
@Override
public List<String> getRequiredPermissions() {
return Arrays.asList(
"Microsoft.Storage/storageAccounts/blobServices/containers/delete",
"Microsoft.Storage/storageAccounts/blobServices/containers/read",
"Microsoft.Storage/storageAccounts/blobServices/containers/write",
"Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey/action",
"Microsoft.Storage/storageAccounts/queueServices/queues/delete",
"Microsoft.Storage/storageAccounts/queueServices/queues/read",
"Microsoft.Storage/storageAccounts/queueServices/queues/write"
);
}
@Override
public List<Pair<String, String>> getSpringPropertiesForManagedIdentity(String key, Connection<?,?> connection) {
final List<Pair<String, String>> properties = new ArrayList<>();
final String suffix = Azure.az(AzureCloud.class).get().getStorageEndpointSuffix();
if (StringUtils.containsIgnoreCase(key, "blob")) {
properties.add(Pair.of("spring.cloud.azure.storage.blob.account-name", String.format("${%s_ACCOUNT_NAME}", Connection.ENV_PREFIX)));
properties.add(Pair.of("spring.cloud.azure.storage.blob.endpoint", String.format("https://${%s_ACCOUNT_NAME}.blob%s", Connection.ENV_PREFIX, suffix)));
} else if (StringUtils.containsIgnoreCase(key, "share")) {
properties.add(Pair.of("spring.cloud.azure.storage.fileshare.account-name", String.format("${%s_ACCOUNT_NAME}", Connection.ENV_PREFIX)));
properties.add(Pair.of("spring.cloud.azure.storage.fileshare.endpoint", String.format("https://${%s_ACCOUNT_NAME}.file%s", Connection.ENV_PREFIX, suffix)));
} else {
properties.add(Pair.of("spring.cloud.azure.storage.fileshare.account-name", String.format("${%s_ACCOUNT_NAME}", Connection.ENV_PREFIX)));
properties.add(Pair.of("spring.cloud.azure.storage.fileshare.endpoint", String.format("https://${%s_ACCOUNT_NAME}.file%s", Connection.ENV_PREFIX, suffix)));
properties.add(Pair.of("spring.cloud.azure.storage.blob.account-name", String.format("${%s_ACCOUNT_NAME}", Connection.ENV_PREFIX)));
properties.add(Pair.of("spring.cloud.azure.storage.blob.endpoint", String.format("https://${%s_ACCOUNT_NAME}.blob%s", Connection.ENV_PREFIX, suffix)));
}
// properties.add(Pair.of("spring.cloud.azure.storage.blob.credential.managed-identity-enabled", String.valueOf(Boolean.TRUE)));
// for user assigned managed identity
if (connection.getAuthenticationType() == AuthenticationType.USER_ASSIGNED_MANAGED_IDENTITY) {
properties.add(Pair.of("spring.cloud.azure.storage.blob.credential.client-id", String.format("${%s_CLIENT_ID}", Connection.ENV_PREFIX)));
}
return properties;
}
@Data

Просмотреть файл

@ -78,6 +78,8 @@ public class StorageAccountResourcePanel implements AzureFormJPanel<Resource<ISt
lblAccount.setLabelFor(accountComboBox);
lblConnectionString.setLabelFor(txtConnectionString);
txtConnectionString.setLabel("Connection string");
this.accountComboBox.addValueChangedListener(ignore -> Optional.ofNullable(getValue()).ifPresent(this::fireValueChangedEvent));
}
private void onSelectEnvironment() {
@ -133,7 +135,7 @@ public class StorageAccountResourcePanel implements AzureFormJPanel<Resource<ISt
@Override
public Resource<IStorageAccount> getValue() {
final AzureValidationInfo info = this.getValidationInfo(true);
if (!info.isValid()) {
if (info.getType() == AzureValidationInfo.Type.ERROR) {
return null;
}
final String connectionString = this.txtConnectionString.getValue();

Просмотреть файл

@ -0,0 +1,20 @@
<idea-plugin>
<extensions defaultExtensionNs="com.microsoft.tooling.msservices.intellij.azure">
<connectorResourceType implementation="com.microsoft.azure.toolkit.intellij.storage.connection.StorageAccountResourceDefinition"/>
<actions implementation="com.microsoft.azure.toolkit.intellij.storage.IntellijJavaStorageActionsContributor"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">
<annotator language="JAVA" implementationClass="com.microsoft.azure.toolkit.intellij.storage.code.java.ConnectionStringStorageClientAnnotator"/>
<annotator language="JAVA" implementationClass="com.microsoft.azure.toolkit.intellij.storage.code.spring.StoragePathAnnotator"/>
<psi.referenceContributor language="JAVA" implementation="com.microsoft.azure.toolkit.intellij.storage.code.spring.StoragePathReferenceContributor" order="first"/>
<psi.referenceContributor language="JAVA" implementation="com.microsoft.azure.toolkit.intellij.storage.code.function.FunctionStorageAccountResourceReferenceContributor"/>
<codeInsight.lineMarkerProvider language="JAVA" implementationClass="com.microsoft.azure.toolkit.intellij.storage.code.spring.StoragePathLineMarkerProvider"/>
<completion.confidence id="azStorageStringLiteral" language="JAVA" implementationClass="com.microsoft.azure.toolkit.intellij.storage.code.spring.StoragePathCompletionConfidence" order="before javaSkipAutopopupInStrings"/>
<completion.contributor id="azStorageFunctionAnnotation" language="JAVA" order="first" implementationClass="com.microsoft.azure.toolkit.intellij.storage.code.function.FunctionAnnotationCompletionContributor"/>
<completion.contributor id="azStorageStringLiteralQuick" language="JAVA" order="first, before azStorageStringLiteral" implementationClass="com.microsoft.azure.toolkit.intellij.storage.code.spring.StoragePathPreCompletionContributor"/>
<completion.contributor id="azStorageStringLiteral" language="JAVA" order="first" implementationClass="com.microsoft.azure.toolkit.intellij.storage.code.spring.StoragePathCompletionContributor"/>
<annotator language="JAVA" implementationClass="com.microsoft.azure.toolkit.intellij.storage.code.function.FunctionAnnotationResourcePathAnnotator"/>
<typedHandler id="azStorageSpringValueAnnotation" implementation="com.microsoft.azure.toolkit.intellij.storage.code.spring.StoragePathTypeHandler"/>
<lookup.charFilter id="azStorageSpringValueAnnotation" implementation="com.microsoft.azure.toolkit.intellij.storage.code.spring.StoragePathCharFilter"/>
</extensions>
</idea-plugin>

Просмотреть файл

@ -3,14 +3,7 @@ dependencies {
// runtimeOnly project(path: ":azure-intellij-plugin-lib", configuration: "instrumentedJar")
implementation(project(":azure-intellij-resource-connector-lib"))
// runtimeOnly project(path: ":azure-intellij-resource-connector-lib", configuration: "instrumentedJar")
implementation(project(":azure-intellij-resource-connector-lib-java"))
// runtimeOnly project(path: ":azure-intellij-resource-connector-lib-java", configuration: "instrumentedJar")
implementation("com.microsoft.azure:azure-toolkit-storage-lib")
implementation("com.microsoft.azure:azure-toolkit-ide-common-lib")
implementation("com.microsoft.azure:azure-toolkit-ide-storage-lib")
intellijPlatform {
// Plugin Dependencies. Uses `platformBundledPlugins` property from the gradle.properties file for bundled IntelliJ Platform plugins.
bundledPlugin("com.intellij.java")
}
}

Просмотреть файл

@ -10,21 +10,16 @@ import com.intellij.openapi.project.Project;
import com.microsoft.azure.toolkit.ide.common.IActionsContributor;
import com.microsoft.azure.toolkit.ide.common.action.ResourceCommonActionsContributor;
import com.microsoft.azure.toolkit.ide.storage.StorageActionsContributor;
import com.microsoft.azure.toolkit.intellij.connector.AzureServiceResource;
import com.microsoft.azure.toolkit.intellij.connector.ConnectorDialog;
import com.microsoft.azure.toolkit.intellij.storage.azurite.AzuriteService;
import com.microsoft.azure.toolkit.intellij.storage.component.StorageCreationDialog;
import com.microsoft.azure.toolkit.intellij.storage.connection.StorageAccountResourceDefinition;
import com.microsoft.azure.toolkit.intellij.storage.creation.CreateStorageAccountAction;
import com.microsoft.azure.toolkit.lib.common.action.Action;
import com.microsoft.azure.toolkit.lib.common.action.AzureActionManager;
import com.microsoft.azure.toolkit.lib.common.model.AbstractAzResourceModule;
import com.microsoft.azure.toolkit.lib.common.model.AzResource;
import com.microsoft.azure.toolkit.lib.common.task.AzureTaskManager;
import com.microsoft.azure.toolkit.lib.resource.ResourceGroup;
import com.microsoft.azure.toolkit.lib.storage.AzureStorageAccount;
import com.microsoft.azure.toolkit.lib.storage.IStorageAccount;
import com.microsoft.azure.toolkit.lib.storage.StorageAccount;
import com.microsoft.azure.toolkit.lib.storage.blob.BlobContainerModule;
import com.microsoft.azure.toolkit.lib.storage.model.StorageAccountConfig;
import com.microsoft.azure.toolkit.lib.storage.queue.QueueModule;
@ -43,13 +38,6 @@ public class IntellijStorageActionsContributor implements IActionsContributor {
final BiConsumer<Object, AnActionEvent> handler = (c, e) -> CreateStorageAccountAction.create(e.getProject(), null);
am.registerHandler(ResourceCommonActionsContributor.CREATE, condition, handler);
am.<AzResource, AnActionEvent>registerHandler(ResourceCommonActionsContributor.CONNECT, (r, e) -> r instanceof StorageAccount,
(r, e) -> AzureTaskManager.getInstance().runLater(() -> {
final ConnectorDialog dialog = new ConnectorDialog(e.getProject());
dialog.setResource(new AzureServiceResource<>(((StorageAccount) r), StorageAccountResourceDefinition.INSTANCE));
dialog.show();
}));
am.registerHandler(ResourceCommonActionsContributor.CREATE, (m, e) -> m instanceof BlobContainerModule, this::createStorage);
am.registerHandler(ResourceCommonActionsContributor.CREATE, (m, e) -> m instanceof ShareModule, this::createStorage);
am.registerHandler(ResourceCommonActionsContributor.CREATE, (m, e) -> m instanceof QueueModule, this::createStorage);

Просмотреть файл

@ -18,7 +18,7 @@ import com.microsoft.azure.toolkit.intellij.connector.ConnectionTopics;
import com.microsoft.azure.toolkit.intellij.connector.dotazure.AzureModule;
import com.microsoft.azure.toolkit.intellij.connector.dotazure.ConnectionManager;
import com.microsoft.azure.toolkit.intellij.connector.dotazure.Profile;
import com.microsoft.azure.toolkit.intellij.storage.connection.StorageAccountResourceDefinition;
import com.microsoft.azure.toolkit.intellij.storage.connection.BaseStorageAccountResourceDefinition;
import com.microsoft.azure.toolkit.lib.common.messager.ExceptionNotification;
import com.microsoft.azure.toolkit.lib.storage.AzuriteStorageAccount;
import lombok.SneakyThrows;
@ -104,7 +104,7 @@ public class AzuriteTaskAdder implements RunManagerListener, ConnectionTopics.Co
}
public static boolean isAzuriteResourceConnection(@Nonnull final Connection<?, ?> connection) {
return connection.getDefinition().getResourceDefinition() instanceof StorageAccountResourceDefinition &&
return connection.getDefinition().getResourceDefinition() instanceof BaseStorageAccountResourceDefinition &&
StringUtils.equalsIgnoreCase(connection.getResource().getDataId(), AzuriteStorageAccount.AZURITE_RESOURCE_ID);
}

Просмотреть файл

@ -0,0 +1,97 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
package com.microsoft.azure.toolkit.intellij.storage.connection;
import com.azure.resourcemanager.resources.fluentcore.arm.ResourceId;
import com.intellij.openapi.project.Project;
import com.microsoft.azure.toolkit.ide.common.icon.AzureIcons;
import com.microsoft.azure.toolkit.intellij.common.auth.IntelliJSecureStore;
import com.microsoft.azure.toolkit.intellij.connector.AzureServiceResource;
import com.microsoft.azure.toolkit.intellij.connector.Connection;
import com.microsoft.azure.toolkit.intellij.connector.Resource;
import com.microsoft.azure.toolkit.intellij.connector.function.FunctionSupported;
import com.microsoft.azure.toolkit.lib.Azure;
import com.microsoft.azure.toolkit.lib.storage.AzureStorageAccount;
import com.microsoft.azure.toolkit.lib.storage.AzuriteStorageAccount;
import com.microsoft.azure.toolkit.lib.storage.IStorageAccount;
import lombok.Getter;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import static com.microsoft.azure.toolkit.lib.common.model.AbstractConnectionStringAzResourceModule.CONNECTION_STRING_SUBSCRIPTION_ID;
@Getter
public abstract class BaseStorageAccountResourceDefinition extends AzureServiceResource.Definition<IStorageAccount> implements FunctionSupported<IStorageAccount> {
public static final int METHOD_AZURE = 0;
public static final int METHOD_AZURITE = 1;
public static final int METHOD_STRING = 2;
public static final String LOCAL_STORAGE_CONNECTION_STRING = "UseDevelopmentStorage=true";
public static final String CONNECTION_STRING_KEY = String.format("%s_CONNECTION_STRING", Connection.ENV_PREFIX);
public static final String ACCOUNT_NAME_KEY = String.format("%s_ACCOUNT_NAME", Connection.ENV_PREFIX);
public static final String ACCOUNT_KEY = String.format("%s_ACCOUNT_KEY", Connection.ENV_PREFIX);
public BaseStorageAccountResourceDefinition() {
super("Azure.Storage", "Azure Storage Account", AzureIcons.StorageAccount.MODULE.getIconPath());
}
@Override
public Map<String, String> initEnv(AzureServiceResource<IStorageAccount> accountDef, Project project) {
final HashMap<String, String> env = new HashMap<>();
final IStorageAccount account = accountDef.getData();
if (Objects.nonNull(account)) {
final String conString = account.getConnectionString();
env.put(CONNECTION_STRING_KEY, conString);
env.put(ACCOUNT_NAME_KEY, account.getName());
env.put(ACCOUNT_KEY, account.getKey());
}
return env;
}
@Override
public IStorageAccount getResource(String dataId, final String id) {
if (StringUtils.equalsIgnoreCase(dataId, AzuriteStorageAccount.AZURITE_RESOURCE_ID)) {
return AzuriteStorageAccount.AZURITE_STORAGE_ACCOUNT;
} else if (CONNECTION_STRING_SUBSCRIPTION_ID.equalsIgnoreCase(ResourceId.fromString(dataId).subscriptionId())) {
final String connectionString = IntelliJSecureStore.getInstance().loadPassword(BaseStorageAccountResourceDefinition.class.getName(), id.toLowerCase(), null);
if (StringUtils.isNotBlank(connectionString)) {
return Azure.az(AzureStorageAccount.class).getOrInitByConnectionString(connectionString);
}
return null;
} else {
return Azure.az(AzureStorageAccount.class).getById(dataId);
}
}
@Override
public List<Resource<IStorageAccount>> getResources(Project project) {
return Azure.az(AzureStorageAccount.class).list().stream()
.flatMap(m -> m.storageAccounts().list().stream())
.map(this::define).toList();
}
@Nonnull
@Override
public String getResourceType() {
return "Storage";
}
@Override
public List<String> getEnvironmentVariablesKey() {
return ListUtils.union(Arrays.asList(CONNECTION_STRING_KEY, ACCOUNT_NAME_KEY, ACCOUNT_KEY), super.getEnvironmentVariablesKey());
}
@Nullable
@Override
public String getResourceConnectionString(@Nonnull IStorageAccount resource) {
return resource instanceof AzuriteStorageAccount ? LOCAL_STORAGE_CONNECTION_STRING : resource.getConnectionString();
}
}

Просмотреть файл

@ -1,23 +1,10 @@
<idea-plugin>
<extensions defaultExtensionNs="com.microsoft.tooling.msservices.intellij.azure">
<connectorResourceType implementation="com.microsoft.azure.toolkit.intellij.storage.connection.StorageAccountResourceDefinition"/>
<explorerNodeProvider implementation="com.microsoft.azure.toolkit.ide.storage.StorageNodeProvider"/>
<actions implementation="com.microsoft.azure.toolkit.ide.storage.StorageActionsContributor"/>
<actions implementation="com.microsoft.azure.toolkit.intellij.storage.IntellijStorageActionsContributor"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">
<annotator language="JAVA" implementationClass="com.microsoft.azure.toolkit.intellij.storage.code.java.ConnectionStringStorageClientAnnotator"/>
<annotator language="JAVA" implementationClass="com.microsoft.azure.toolkit.intellij.storage.code.spring.StoragePathAnnotator"/>
<psi.referenceContributor language="JAVA" implementation="com.microsoft.azure.toolkit.intellij.storage.code.spring.StoragePathReferenceContributor" order="first"/>
<psi.referenceContributor language="JAVA" implementation="com.microsoft.azure.toolkit.intellij.storage.code.function.FunctionStorageAccountResourceReferenceContributor"/>
<codeInsight.lineMarkerProvider language="JAVA" implementationClass="com.microsoft.azure.toolkit.intellij.storage.code.spring.StoragePathLineMarkerProvider"/>
<completion.confidence id="azStorageStringLiteral" language="JAVA" implementationClass="com.microsoft.azure.toolkit.intellij.storage.code.spring.StoragePathCompletionConfidence" order="before javaSkipAutopopupInStrings"/>
<completion.contributor id="azStorageFunctionAnnotation" language="JAVA" order="first" implementationClass="com.microsoft.azure.toolkit.intellij.storage.code.function.FunctionAnnotationCompletionContributor"/>
<completion.contributor id="azStorageStringLiteralQuick" language="JAVA" order="first, before azStorageStringLiteral" implementationClass="com.microsoft.azure.toolkit.intellij.storage.code.spring.StoragePathPreCompletionContributor"/>
<completion.contributor id="azStorageStringLiteral" language="JAVA" order="first" implementationClass="com.microsoft.azure.toolkit.intellij.storage.code.spring.StoragePathCompletionContributor"/>
<annotator language="JAVA" implementationClass="com.microsoft.azure.toolkit.intellij.storage.code.function.FunctionAnnotationResourcePathAnnotator"/>
<typedHandler id="azStorageSpringValueAnnotation" implementation="com.microsoft.azure.toolkit.intellij.storage.code.spring.StoragePathTypeHandler"/>
<lookup.charFilter id="azStorageSpringValueAnnotation" implementation="com.microsoft.azure.toolkit.intellij.storage.code.spring.StoragePathCharFilter"/>
<stepsBeforeRunProvider id="AzuriteTaskProviderId" implementation="com.microsoft.azure.toolkit.intellij.storage.azurite.AzuriteTaskProvider"/>
</extensions>
<projectListeners>

Просмотреть файл

@ -6,6 +6,7 @@ dependencies {
implementation(project(":azure-intellij-resource-connector-lib"))
// runtimeOnly project(path: ":azure-intellij-resource-connector-lib", configuration: "instrumentedJar")
implementation("com.microsoft.azure:azure-toolkit-ide-common-lib")
implementation("com.microsoft.azure:azure-toolkit-identity-lib")
intellijPlatform {
// Plugin Dependencies. Uses `platformBundledPlugins` property from the gradle.properties file for bundled IntelliJ Platform plugins.

Просмотреть файл

@ -0,0 +1,14 @@
package com.microsoft.azure.toolkit.intellij.connector.spring;
import com.microsoft.azure.toolkit.intellij.connector.Connection;
import com.microsoft.azure.toolkit.intellij.connector.IManagedIdentitySupported;
import com.microsoft.azure.toolkit.intellij.connector.Resource;
import com.microsoft.azure.toolkit.lib.common.model.AzResource;
import com.microsoft.azure.toolkit.lib.identities.Identity;
import org.apache.commons.lang3.tuple.Pair;
import java.util.List;
public interface SpringManagedIdentitySupported<T extends AzResource> extends SpringSupported<T>, IManagedIdentitySupported<T> {
List<Pair<String, String>> getSpringPropertiesForManagedIdentity(String key, Connection<?,?> connection);
}

Просмотреть файл

@ -17,8 +17,11 @@ import java.util.stream.Collectors;
public interface SpringSupported<T> extends ResourceDefinition<T> {
static List<Pair<String, String>> getProperties(Connection<?, ?> c, final String propKey) {
final ResourceDefinition<?> rd = c.getResource().getDefinition();
if (rd instanceof SpringSupported) {
return ((SpringSupported<?>) rd).getSpringProperties(propKey).stream()
if (rd instanceof SpringSupported<?> springSupported) {
final List<Pair<String, String>> springProperties =
c.isManagedIdentityConnection() && rd instanceof SpringManagedIdentitySupported<?> si ?
si.getSpringPropertiesForManagedIdentity(propKey, c) : springSupported.getSpringProperties(propKey);
return springProperties.stream()
.map(p -> Pair.of(p.getKey(), p.getValue().replaceAll(Connection.ENV_PREFIX, c.getEnvPrefix())))
.collect(Collectors.toList());
}

Просмотреть файл

@ -5,6 +5,7 @@ dependencies {
// runtimeOnly project(path: ":azure-intellij-plugin-service-explorer", configuration: "instrumentedJar")
implementation("com.microsoft.azure:azure-toolkit-ide-common-lib")
implementation("io.github.cdimascio:dotenv-java:3.0.0")
implementation("com.microsoft.azure:azure-toolkit-identity-lib")
intellijPlatform {
// Plugin Dependencies. Uses `platformBundledPlugins` property from the gradle.properties file for bundled IntelliJ Platform plugins.
bundledPlugin("com.intellij.properties")

Просмотреть файл

@ -0,0 +1,19 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
package com.microsoft.azure.toolkit.intellij.connector;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum AuthenticationType {
SYSTEM_ASSIGNED_MANAGED_IDENTITY("Managed Identity (System Assigned)"),
USER_ASSIGNED_MANAGED_IDENTITY("Managed Identity (User Assigned)"),
CONNECTION_STRING("Connection String");
private String displayName;
}

Просмотреть файл

@ -81,12 +81,14 @@ public class AzureServiceResource<T extends AzResource> implements Resource<T> {
}
@Override
public Map<String, String> initEnv(Project project) {
public Map<String, String> initEnv(Project project, Connection<?,?> connection) {
final T resource = this.getData();
if (resource == null || !resource.exists()) {
throw new AzureToolkitRuntimeException(String.format("%s '%s' does not exist.", this.getResourceType(), this.getName()));
}
final Map<String, String> result = new HashMap<>(this.definition.initEnv(this, project));
final Map<String, String> properties = connection.isManagedIdentityConnection() && definition instanceof IManagedIdentitySupported identitySupported ?
identitySupported.initIdentityEnv(connection, project) : this.definition.initEnv(this, project);
final Map<String, String> result = new HashMap<>(properties);
if (!(resource instanceof AbstractConnectionStringAzResource<?>)) {
result.put(SUBSCRIPTION_ID_KEY, resource.getSubscriptionId());
result.put(RESOURCE_GROUP_KEY, resource.getResourceGroupName());

Просмотреть файл

@ -12,12 +12,14 @@ import com.microsoft.azure.toolkit.intellij.connector.dotazure.Profile;
import com.microsoft.azure.toolkit.intellij.connector.function.FunctionSupported;
import com.microsoft.azure.toolkit.lib.common.messager.AzureMessager;
import com.microsoft.azure.toolkit.lib.common.operation.AzureOperation;
import com.microsoft.azure.toolkit.lib.identities.Identity;
import lombok.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.jdom.Element;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import java.util.stream.Collectors;
@ -52,6 +54,15 @@ public class Connection<R, C> {
@Setter
protected ConnectionDefinition<R, C> definition;
@Nullable
@Setter
protected AuthenticationType authenticationType;
// todo: change authentication properties to different child class, rather than put them all in connection
@Nullable
@Setter
protected Resource<Identity> userAssignedManagedIdentity;
@Setter
@Getter(AccessLevel.NONE)
private String envPrefix;
@ -77,7 +88,7 @@ public class Connection<R, C> {
}
public Map<String, String> getEnvironmentVariables(final Project project) {
final Map<String, String> result = this.resource.initEnv(project).entrySet().stream()
final Map<String, String> result = this.resource.initEnv(project, this).entrySet().stream()
.collect(Collectors.toMap(e -> e.getKey().replaceAll(Connection.ENV_PREFIX, this.getEnvPrefix()), Map.Entry::getValue));
if (this.getResource().getDefinition() instanceof FunctionSupported<R>) {
result.putAll(((FunctionSupported<R>) this.getResource().getDefinition()).getPropertiesForFunction(this.getResource().getData(), this));
@ -134,4 +145,9 @@ public class Connection<R, C> {
public List<Pair<String, String>> getGeneratedEnvironmentVariables() {
return Optional.ofNullable(this.profile).map(p -> p.getGeneratedEnvironmentVariables(this)).orElse(Collections.emptyList());
}
public boolean isManagedIdentityConnection() {
return this.authenticationType == AuthenticationType.USER_ASSIGNED_MANAGED_IDENTITY ||
this.authenticationType == AuthenticationType.SYSTEM_ASSIGNED_MANAGED_IDENTITY;
}
}

Просмотреть файл

@ -13,6 +13,7 @@ import com.microsoft.azure.toolkit.intellij.common.AzureDialog;
import com.microsoft.azure.toolkit.intellij.connector.dotazure.AzureModule;
import com.microsoft.azure.toolkit.intellij.connector.dotazure.Profile;
import com.microsoft.azure.toolkit.lib.common.messager.AzureMessager;
import com.microsoft.azure.toolkit.lib.identities.Identity;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.apache.commons.collections4.CollectionUtils;
@ -75,13 +76,19 @@ public class ConnectionDefinition<R, C> {
@SuppressWarnings("unchecked")
public Connection<R, C> read(@Nonnull final com.microsoft.azure.toolkit.intellij.connector.dotazure.ResourceManager manager, Element connectionEle) {
final String id = connectionEle.getAttributeValue(FIELD_ID);
final String envPrefix = connectionEle.getAttributeValue(ENV_PREFIX);
final Resource<R> resource = Optional.ofNullable(readResourceFromElement(connectionEle, manager))
.orElseGet(() -> new InvalidResource<>(this.getResourceDefinition()));
final Resource<C> consumer = Optional.ofNullable(readConsumerFromElement(connectionEle, manager))
.orElseGet(() -> new InvalidResource<>(this.getConsumerDefinition()));
final Connection<R, C> connection = this.define(id, resource, consumer);
connection.setEnvPrefix(envPrefix);
Optional.ofNullable(connectionEle.getChild("identity"))
.map(ele -> (Resource<Identity>) manager.getResourceById(ele.getTextTrim()))
.ifPresent(connection::setUserAssignedManagedIdentity);
connection.setEnvPrefix(connectionEle.getAttributeValue(ENV_PREFIX));
final AuthenticationType authentication = Optional.ofNullable(connectionEle.getAttributeValue("authentication"))
.filter(StringUtils::isNotBlank).map(AuthenticationType::valueOf).orElse(AuthenticationType.CONNECTION_STRING);
connection.setAuthenticationType(authentication);
return connection;
}
@ -129,7 +136,14 @@ public class ConnectionDefinition<R, C> {
connectionEle.addContent(new Element("consumer")
.setAttribute("type", consumer.getDefinition().getName())
.setText(consumer.getId()));
final Resource<Identity> userAssignedManagedIdentity = connection.getUserAssignedManagedIdentity();
if (Objects.nonNull(userAssignedManagedIdentity)) {
connectionEle.addContent(new Element("identity")
.setAttribute("type", userAssignedManagedIdentity.getDefinition().getName())
.setText(userAssignedManagedIdentity.getId()));
}
connectionEle.setAttribute("envPrefix", connection.getEnvPrefix());
connectionEle.setAttribute("authentication", String.valueOf(connection.getAuthenticationType()));
return true;
}

Просмотреть файл

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.microsoft.azure.toolkit.intellij.connector.ConnectorDialog">
<grid id="cbd77" binding="contentPane" layout-manager="GridLayoutManager" row-count="8" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="cbd77" binding="contentPane" layout-manager="GridLayoutManager" row-count="9" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="48" y="54" width="580" height="256"/>
<xy x="48" y="54" width="721" height="389"/>
</constraints>
<properties/>
<border type="none"/>
@ -139,9 +139,80 @@
</grid>
<vspacer id="1a16a">
<constraints>
<grid row="7" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
<grid row="8" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
<grid id="8493c" binding="pnlAuthentication" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="7" column="0" row-span="1" col-span="3" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<visible value="true"/>
</properties>
<border type="none"/>
<children>
<component id="b9b63" class="com.intellij.ui.TitledSeparator" binding="titleAuthentication">
<constraints>
<grid row="0" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="3" anchor="1" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Authentication"/>
<titleFont style="1"/>
</properties>
</component>
<component id="ed670" class="com.intellij.ui.components.JBLabel">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false">
<minimum-size width="100" height="24"/>
<preferred-size width="100" height="24"/>
<maximum-size width="100" height="24"/>
</grid>
</constraints>
<properties>
<text value="Type:"/>
</properties>
</component>
<component id="5710d" class="com.microsoft.azure.toolkit.intellij.common.AzureComboBox" binding="cbAuthenticationType" custom-create="true">
<constraints>
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<editable value="true"/>
</properties>
</component>
<grid id="6a0f1" binding="pnlUserAssignedManagedIdentity" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="2" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<visible value="false"/>
</properties>
<border type="none"/>
<children>
<component id="7799a" class="com.intellij.ui.components.JBLabel">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false">
<minimum-size width="100" height="24"/>
<preferred-size width="100" height="24"/>
<maximum-size width="100" height="24"/>
</grid>
</constraints>
<properties>
<text value="Identity:"/>
</properties>
</component>
<component id="2b748" class="com.microsoft.azure.toolkit.intellij.connector.UserAssignedManagedIdentityComboBox" binding="cbIdentity" custom-create="true">
<constraints>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
</component>
</children>
</grid>
</children>
</grid>
</children>
</grid>
</form>

Просмотреть файл

@ -25,8 +25,10 @@ import com.microsoft.azure.toolkit.lib.common.action.Action;
import com.microsoft.azure.toolkit.lib.common.action.AzureActionManager;
import com.microsoft.azure.toolkit.lib.common.form.AzureForm;
import com.microsoft.azure.toolkit.lib.common.form.AzureFormInput;
import com.microsoft.azure.toolkit.lib.common.model.AzResource;
import com.microsoft.azure.toolkit.lib.common.task.AzureTaskManager;
import lombok.Getter;
import org.apache.commons.lang3.ObjectUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@ -61,6 +63,11 @@ public class ConnectorDialog extends AzureDialog<Connection<?, ?>> implements Az
private JTextPane descriptionPane;
private JPanel pnlEnvPrefix;
private JLabel lblEnvPrefix;
private TitledSeparator titleAuthentication;
private JPanel pnlAuthentication;
private JPanel pnlUserAssignedManagedIdentity;
private AzureComboBox<AuthenticationType> cbAuthenticationType;
private UserAssignedManagedIdentityComboBox cbIdentity;
private SignInHyperLinkLabel signInHyperLinkLabel1;
private ResourceDefinition<?> resourceDefinition;
private ResourceDefinition<?> consumerDefinition;
@ -99,6 +106,7 @@ public class ConnectorDialog extends AzureDialog<Connection<?, ?>> implements Az
}));
this.consumerTypeSelector.addItemListener(this::onResourceOrConsumerTypeChanged);
this.resourceTypeSelector.addItemListener(this::onResourceOrConsumerTypeChanged);
this.cbAuthenticationType.addItemListener(this::onAuthenticationTypeChanged);
final Font font = UIManager.getFont("Label.font");
final Color foregroundColor = UIManager.getColor("Label.foreground");
final Color backgroundColor = UIManager.getColor("Label.backgroundColor");
@ -119,6 +127,26 @@ public class ConnectorDialog extends AzureDialog<Connection<?, ?>> implements Az
}
}
private void onSelectResource(Object o) {
final AzureServiceResource<?> value = o instanceof AzureServiceResource ? (AzureServiceResource<?>) this.resourcePanel.getValue() : null;
if (Objects.nonNull(value)) {
cbIdentity.setResource(value);
}
}
private void onAuthenticationTypeChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
final AuthenticationType authenticationType = this.cbAuthenticationType.getValue();
this.pnlUserAssignedManagedIdentity.setVisible(authenticationType == AuthenticationType.USER_ASSIGNED_MANAGED_IDENTITY);
if (authenticationType == AuthenticationType.USER_ASSIGNED_MANAGED_IDENTITY) {
final Resource<?> value = (Resource<?>) this.resourcePanel.getValue();
if (value instanceof AzResource azResource) {
cbIdentity.setSubscription(azResource.getSubscription());
}
}
}
}
protected void onResourceOrConsumerTypeChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED && !tryOpenCustomDialog()) {
if (Objects.equals(e.getSource(), this.consumerTypeSelector)) {
@ -197,6 +225,10 @@ public class ConnectorDialog extends AzureDialog<Connection<?, ?>> implements Az
if (resource.getDefinition().isEnvPrefixSupported()) {
connection.setEnvPrefix(this.envPrefixTextField.getText().trim());
}
connection.setAuthenticationType(cbAuthenticationType.getValue());
if (cbAuthenticationType.getValue() == AuthenticationType.USER_ASSIGNED_MANAGED_IDENTITY) {
Optional.ofNullable(cbIdentity.getValue()).map(IdentityResource.Definition.INSTANCE::define).ifPresent(connection::setUserAssignedManagedIdentity);
}
return connection;
}
@ -206,6 +238,9 @@ public class ConnectorDialog extends AzureDialog<Connection<?, ?>> implements Az
this.setResource(connection.getResource());
this.envPrefixTextField.setText(connection.getEnvPrefix());
this.connection = connection;
// authentication
this.cbAuthenticationType.setValue(ObjectUtils.firstNonNull(connection.getAuthenticationType(), AuthenticationType.CONNECTION_STRING));
Optional.ofNullable(connection.getUserAssignedManagedIdentity()).map(Resource::getData).ifPresent(cbIdentity::setValue);
}
@Override
@ -246,8 +281,16 @@ public class ConnectorDialog extends AzureDialog<Connection<?, ?>> implements Az
this.envPrefixTextField.setText(definition.getDefaultEnvPrefix());
this.resourceTypeSelector.setValue(new ItemReference<>(definition.getName(), ResourceDefinition::getName));
this.resourcePanel = this.updatePanel(definition, this.resourcePanelContainer);
Optional.ofNullable(this.resourcePanel).ifPresent(panel -> panel.addValueChangedListener(this::onSelectResource));
this.lblEnvPrefix.setVisible(resourceDefinition.isEnvPrefixSupported());
this.envPrefixTextField.setVisible(resourceDefinition.isEnvPrefixSupported());
final List<AuthenticationType> supportedAuthenticationTypes = definition.getSupportedAuthenticationTypes();
this.pnlAuthentication.setVisible(supportedAuthenticationTypes.size() > 1);
this.cbAuthenticationType.clear();
this.cbAuthenticationType.setItemsLoader(() -> supportedAuthenticationTypes);
this.cbAuthenticationType.reloadItems();
}
}
@ -297,6 +340,25 @@ public class ConnectorDialog extends AzureDialog<Connection<?, ?>> implements Az
return Collections.emptyList();
}
};
this.cbIdentity = new UserAssignedManagedIdentityComboBox();
this.cbAuthenticationType = new AzureComboBox<>() {
@Nullable
@Override
protected AuthenticationType doGetDefaultValue() {
return AuthenticationType.SYSTEM_ASSIGNED_MANAGED_IDENTITY;
}
@Nonnull
@Override
protected List<ExtendableTextComponent.Extension> getExtensions() {
return Collections.emptyList();
}
@Override
protected String getItemText(Object item) {
return item instanceof AuthenticationType type ? type.getDisplayName() : super.getItemText(item);
}
};
}
public void setDescription(@Nonnull final String description) {

Просмотреть файл

@ -0,0 +1,109 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
package com.microsoft.azure.toolkit.intellij.connector;
import com.azure.resourcemanager.authorization.models.BuiltInRole;
import com.azure.resourcemanager.authorization.models.RoleAssignment;
import com.intellij.openapi.project.Project;
import com.microsoft.azure.toolkit.ide.common.action.ResourceCommonActionsContributor;
import com.microsoft.azure.toolkit.lib.common.action.Action;
import com.microsoft.azure.toolkit.lib.common.action.AzureActionManager;
import com.microsoft.azure.toolkit.lib.common.messager.AzureMessager;
import com.microsoft.azure.toolkit.lib.common.model.AbstractAzResource;
import com.microsoft.azure.toolkit.lib.common.model.AzResource;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* Interfaced to indicate that the resource supports managed identity
* <p>
*/
public interface IManagedIdentitySupported<T extends AzResource> {
String FAILED_TO_ASSIGN_MESSAGE = "Failed to grant permission to identity <a href=\"%s\">%s</a>, %s, please try assign correct role to it in portal";
Map<String, String> initIdentityEnv(Connection<T, ?> data, Project project);
/**
* Get required permissions to access the target resource
*
* @return List of required permissions
*/
List<String> getRequiredPermissions();
/**
* Get built-in roles that could be assigned to the identity to get access to target resource
*
* @return Map (role id, BuildInRole), refers https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles
*/
@Nullable Map<String, BuiltInRole> getBuiltInRoles();
/**
* Check whether identity has required permissions to access resource
*/
public static boolean checkPermission(@Nonnull AzureServiceResource<?> data, @Nonnull String identity) {
final AzureServiceResource.Definition<?> d = data.getDefinition();
final AzResource r = data.getData();
if (d instanceof IManagedIdentitySupported<?> definition && r instanceof AbstractAzResource<?, ?, ?> resource) {
final List<String> permissions = resource.getPermissions(identity);
final List<String> requiredPermissions = definition.getRequiredPermissions();
return CollectionUtils.containsAll(permissions, requiredPermissions);
}
return true;
}
@Nonnull
public static Action<?> getOpenIdentityConfigurationAction(@Nonnull AzureServiceResource<?> data) {
final String url = Objects.requireNonNull(data.getData()).getPortalUrl() + "/iamAccessControl";
return AzureActionManager.getInstance().getAction(ResourceCommonActionsContributor.OPEN_URL).bind(url).withLabel("Open IAM Configuration");
}
public static boolean grantPermission(@Nonnull AzureServiceResource<?> data, @Nonnull String identity) {
final AzureServiceResource.Definition<?> d = data.getDefinition();
final AzResource r = data.getData();
if (d instanceof IManagedIdentitySupported<?> definition && MapUtils.isNotEmpty(definition.getBuiltInRoles()) && r instanceof AbstractAzResource<?, ?, ?> resource) {
final Map<String, BuiltInRole> builtInRoles = definition.getBuiltInRoles();
final List<String> roles = resource.getRoleAssignments(identity).stream().map(RoleAssignment::roleDefinitionId).toList();
final String rolesStr = builtInRoles.values().stream().map(BuiltInRole::toString).collect(Collectors.joining(","));
final boolean assignRole = AzureMessager.getDefaultMessager().confirm(String.format("Do you want to assign roles (%s) to identity (%s)?", rolesStr, identity), "Assign Required Roles");
if (assignRole) {
try {
Objects.requireNonNull(definition.getBuiltInRoles()).forEach((id, role) -> {
if (roles.stream().noneMatch(ro -> ro.endsWith(id))) {
AzureMessager.getMessager().info(String.format("Assigning role (%s) to identity (%s)...", role, identity));
resource.grantPermissionToIdentity(identity, role);
}
});
AzureMessager.getMessager().info(String.format("Roles (%s) have been assigned to identity (%s)?", rolesStr, identity));
return true;
} catch (final RuntimeException e) {
final String errorMessage = String.format(FAILED_TO_ASSIGN_MESSAGE, resource.getPortalUrl(), identity, e.getMessage());
AzureMessager.getMessager().warning(errorMessage, getOpenIdentityConfigurationAction(data));
}
}
}
return false;
}
@Nullable
public static Action<?> getGrantPermissionAction(@Nonnull AzureServiceResource<?> data, @Nonnull String identity) {
final AzureServiceResource.Definition<?> d = data.getDefinition();
final AzResource r = data.getData();
if (d instanceof IManagedIdentitySupported<?> definition && MapUtils.isNotEmpty(definition.getBuiltInRoles()) && r instanceof AbstractAzResource<?, ?, ?> resource) {
return new Action<>(Action.Id.of("user/common.assign_role.identity"))
.withLabel("Assign Required Roles")
.withIdParam(identity)
.withHandler(ignore -> grantPermission(data, identity));
}
return null;
}
}

Просмотреть файл

@ -0,0 +1,68 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
package com.microsoft.azure.toolkit.intellij.connector;
import com.intellij.openapi.project.Project;
import com.microsoft.azure.toolkit.ide.common.icon.AzureIcons;
import com.microsoft.azure.toolkit.intellij.common.AzureFormJPanel;
import com.microsoft.azure.toolkit.lib.Azure;
import com.microsoft.azure.toolkit.lib.common.exception.AzureToolkitRuntimeException;
import com.microsoft.azure.toolkit.lib.identities.AzureManagedIdentity;
import com.microsoft.azure.toolkit.lib.identities.Identity;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@Getter
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class IdentityResource extends AzureServiceResource<Identity> {
public IdentityResource(@Nonnull Identity data, @Nonnull AzureServiceResource.Definition<Identity> definition) {
super(data, definition);
}
@Getter
public static class Definition extends AzureServiceResource.Definition<Identity> {
public static final Definition INSTANCE = new Definition();
public Definition() {
super("Managed Identity", "Managed Identity", AzureIcons.Common.AZURE.getIconPath());
}
@Override
public Resource<Identity> define(Identity resource) {
return super.define(resource, null);
}
@Override
public Identity getResource(String dataId, final String id) {
return Azure.az(AzureManagedIdentity.class).getById(dataId);
}
@Override
public Map<String, String> initEnv(AzureServiceResource<Identity> data, Project project) {
return Collections.emptyMap();
}
@Override
public int getRole() {
return IDENTITY;
}
@Override
public AzureFormJPanel<Resource<Identity>> getResourcePanel(Project project) {
throw new AzureToolkitRuntimeException("not supported");
}
@Override
public List<Resource<Identity>> getResources(Project project) {
throw new AzureToolkitRuntimeException("not supported");
}
}
}

Просмотреть файл

@ -43,6 +43,10 @@ public interface Resource<T> {
default void navigate(AnActionEvent event) {
}
default Map<String, String> initEnv(Project project, Connection<?,?> connection) {
return Collections.emptyMap();
}
default Map<String, String> initEnv(Project project) {
return Collections.emptyMap();
}

Просмотреть файл

@ -11,11 +11,13 @@ import org.jdom.Element;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public interface ResourceDefinition<T> {
int RESOURCE = 1;
int CONSUMER = 2;
int IDENTITY = 4;
int BOTH = RESOURCE | CONSUMER;
/**
@ -77,4 +79,14 @@ public interface ResourceDefinition<T> {
default String getDefaultEnvPrefix() {
return this.getName().toUpperCase().replaceAll("[^a-zA-Z0-9]", "_");
}
default List<AuthenticationType> getSupportedAuthenticationTypes() {
final List<AuthenticationType> result = new ArrayList<>();
result.add(AuthenticationType.CONNECTION_STRING);
if (this instanceof IManagedIdentitySupported) {
result.add(AuthenticationType.SYSTEM_ASSIGNED_MANAGED_IDENTITY);
result.add(AuthenticationType.USER_ASSIGNED_MANAGED_IDENTITY);
}
return result;
}
}

Просмотреть файл

@ -0,0 +1,79 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
package com.microsoft.azure.toolkit.intellij.connector;
import com.microsoft.azure.toolkit.intellij.common.AzureComboBox;
import com.microsoft.azure.toolkit.lib.Azure;
import com.microsoft.azure.toolkit.lib.common.model.AzResource;
import com.microsoft.azure.toolkit.lib.common.model.Subscription;
import com.microsoft.azure.toolkit.lib.identities.AzureManagedIdentity;
import com.microsoft.azure.toolkit.lib.identities.Identity;
import lombok.Getter;
import org.apache.commons.collections4.ComparatorUtils;
import org.apache.commons.lang3.BooleanUtils;
import javax.annotation.Nonnull;
import java.util.*;
import static com.microsoft.azure.toolkit.intellij.connector.IManagedIdentitySupported.checkPermission;
public class UserAssignedManagedIdentityComboBox extends AzureComboBox<Identity> {
@Getter
private AzureServiceResource<?> resource;
@Getter
private Subscription subscription;
private final Map<Identity, Boolean> permissions = new HashMap<>();
public UserAssignedManagedIdentityComboBox() {
super();
}
public void setSubscription(Subscription subscription) {
if (Objects.equals(subscription, this.subscription)) {
return;
}
this.subscription = subscription;
if (subscription == null) {
this.clear();
return;
}
this.reloadItems();
}
public void setResource(AzureServiceResource<?> azResource) {
if (Objects.equals(azResource, this.resource)) {
return;
}
this.clear();
this.resource = azResource;
this.subscription = Optional.ofNullable(azResource.getData()).map(AzResource::getSubscription).orElse(null);
this.reloadItems();
}
@Override
protected String getItemText(Object item) {
if (item instanceof Identity identity) {
return Objects.isNull(resource) || BooleanUtils.isTrue(permissions.get(identity)) ?
identity.getName() : String.format("%s (No permission)", identity.getName());
}
return super.getItemText(item);
}
@Nonnull
@Override
protected List<Identity> loadItems() throws Exception {
final List<Identity> identities = Objects.isNull(subscription) ?
Azure.az(AzureManagedIdentity.class).identities() :
Azure.az(AzureManagedIdentity.class).forSubscription(this.subscription.getId()).identity().list();
if (Objects.isNull(resource)) {
return identities;
}
permissions.clear();
identities.forEach(identity -> permissions.put(identity, checkPermission(resource, identity.getPrincipalId())));
identities.sort(Comparator.comparing(permissions::get).reversed());
return identities;
}
}

Просмотреть файл

@ -9,16 +9,17 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.microsoft.azure.toolkit.intellij.connector.Connection;
import com.microsoft.azure.toolkit.intellij.connector.ConnectionTopics;
import com.microsoft.azure.toolkit.intellij.connector.DeploymentTargetTopics;
import com.microsoft.azure.toolkit.intellij.connector.*;
import com.microsoft.azure.toolkit.intellij.facet.AzureFacet;
import com.microsoft.azure.toolkit.lib.common.action.Action;
import com.microsoft.azure.toolkit.lib.common.bundle.AzureString;
import com.microsoft.azure.toolkit.lib.common.exception.AzureToolkitRuntimeException;
import com.microsoft.azure.toolkit.lib.common.messager.AzureMessager;
import com.microsoft.azure.toolkit.lib.common.model.AbstractAzResource;
import com.microsoft.azure.toolkit.lib.common.operation.AzureOperation;
import com.microsoft.azure.toolkit.lib.common.operation.OperationBundle;
import com.microsoft.azure.toolkit.lib.common.task.AzureTaskManager;
import com.microsoft.azure.toolkit.lib.identities.Identity;
import io.github.cdimascio.dotenv.internal.DotenvParser;
import io.github.cdimascio.dotenv.internal.DotenvReader;
import lombok.Getter;
@ -33,20 +34,17 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.*;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import static com.microsoft.azure.toolkit.intellij.connector.ConnectionTopics.CONNECTION_CHANGED;
import static com.microsoft.azure.toolkit.intellij.connector.IManagedIdentitySupported.*;
import static com.microsoft.azure.toolkit.intellij.connector.dotazure.AzureModule.DOT_ENV;
@Getter
public class Profile {
public static final String NO_PERMISSION_MESSAGE = "The managed identity <a href=\"%s\">%s</a> (%s) doesn't have enough permission to access resource %s.";
@Nonnull
private final String name;
@Nonnull
@ -98,8 +96,23 @@ public class Profile {
public synchronized Future<?> addConnection(@Nonnull Connection<?, ?> connection) {
AzureFacet.addTo(this.module.getModule());
this.resourceManager.addResource(connection.getResource());
final Resource<?> resource = connection.getResource();
this.resourceManager.addResource(resource);
this.connectionManager.addConnection(connection);
// handle user assigned managed identity
final Resource<Identity> identityResource = connection.getUserAssignedManagedIdentity();
if (Objects.nonNull(identityResource)) {
this.resourceManager.addResource(identityResource);
AzureTaskManager.getInstance().runInBackground("Validating connection", () -> {
final String identity = identityResource.getData().getPrincipalId();
if (resource instanceof AzureServiceResource<?> serviceResource && !checkPermission(serviceResource, identity)) {
final String message = String.format(NO_PERMISSION_MESSAGE, identityResource.getData().getPortalUrl(), identityResource.getName(),identityResource.getData().getPrincipalId(), resource.getName());
final Action<?> openIdentityConfigurationAction = getOpenIdentityConfigurationAction(serviceResource);
final Action<?> grantPermissionAction = getGrantPermissionAction(serviceResource, identity);
AzureMessager.getMessager().warning(message, grantPermissionAction, openIdentityConfigurationAction);
}
});
}
return this.addConnectionToDotEnv(connection);
}

Просмотреть файл

@ -53,7 +53,7 @@ public class KeyValueResource implements Resource<KeyValueData> {
}
@Override
public Map<String, String> initEnv(Project project) {
public Map<String, String> initEnv(Project project, Connection<?,?> ignore) {
final KeyValueData connection = getData();
return Collections.singletonMap(connection.getKey(), connection.getValue());
}

Просмотреть файл

@ -66,15 +66,15 @@ allprojects {
// jetbrainsRuntime()
}
implementation(platform("com.microsoft.azure:azure-toolkit-libs:0.47.0-SNAPSHOT"))
implementation(platform("com.microsoft.azure:azure-toolkit-ide-libs:0.47.0-SNAPSHOT"))
implementation(platform("com.microsoft.azure:azure-toolkit-libs:0.47.0"))
implementation(platform("com.microsoft.azure:azure-toolkit-ide-libs:0.47.0"))
implementation(platform("com.microsoft.hdinsight:azure-toolkit-ide-hdinsight-libs:0.1.1"))
compileOnly("org.projectlombok:lombok:1.18.24")
compileOnly("org.jetbrains:annotations:24.0.0")
annotationProcessor("org.projectlombok:lombok:1.18.24")
implementation("com.microsoft.azure:azure-toolkit-common-lib:0.47.0-SNAPSHOT")
aspect("com.microsoft.azure:azure-toolkit-common-lib:0.47.0-SNAPSHOT")
implementation("com.microsoft.azure:azure-toolkit-common-lib:0.47.0")
aspect("com.microsoft.azure:azure-toolkit-common-lib:0.47.0")
}
configurations {
@ -176,6 +176,7 @@ dependencies {
implementation(project(":azure-sdk-reference-book"))
implementation(project(":azure-intellij-plugin-springcloud"))
implementation(project(":azure-intellij-plugin-storage"))
implementation(project(":azure-intellij-plugin-storage-java"))
implementation(project(":azure-intellij-plugin-appservice"))
implementation(project(":azure-intellij-plugin-appservice-java"))
implementation(project(":azure-intellij-plugin-arm"))
@ -190,11 +191,13 @@ dependencies {
implementation(project(":azure-intellij-plugin-database-java"))
implementation(project(":azure-intellij-plugin-vm"))
implementation(project(":azure-intellij-plugin-redis"))
implementation(project(":azure-intellij-plugin-redis-java"))
implementation(project(":azure-intellij-plugin-samples"))
implementation(project(":azure-intellij-plugin-bicep"))
implementation(project(":azure-intellij-plugin-eventhubs"))
implementation(project(":azure-intellij-plugin-servicebus"))
implementation(project(":azure-intellij-plugin-keyvault"))
implementation(project(":azure-intellij-plugin-keyvault-java"))
implementation(project(":azure-intellij-resource-connector-aad"))
implementation(project(":azure-intellij-plugin-hdinsight-lib"))
implementation(project(":azure-intellij-plugin-sqlserverbigdata"))

Просмотреть файл

@ -1,4 +1,4 @@
pluginVersion=3.91.0-SNAPSHOT
pluginVersion=3.91.0
intellijDisplayVersion=2024.2
intellij_version=IU-242-EAP-SNAPSHOT
platformVersion=242-EAP-SNAPSHOT

Просмотреть файл

@ -18,6 +18,7 @@ include("azure-intellij-plugin-guidance-java")
include("azure-sdk-reference-book")
include("azure-intellij-plugin-springcloud")
include("azure-intellij-plugin-storage")
include("azure-intellij-plugin-storage-java")
include("azure-intellij-plugin-appservice")
include("azure-intellij-plugin-appservice-java")
include("azure-intellij-plugin-arm")
@ -32,6 +33,7 @@ include("azure-intellij-plugin-database")
include("azure-intellij-plugin-database-java")
include("azure-intellij-plugin-vm")
include("azure-intellij-plugin-redis")
include("azure-intellij-plugin-redis-java")
include("azure-intellij-plugin-samples")
include("azure-intellij-plugin-bicep")
include("azure-intellij-plugin-eventhubs")
@ -44,4 +46,5 @@ include("azure-intellij-plugin-synapse")
include("azure-intellij-plugin-sparkoncosmos")
include("azure-intellij-plugin-sqlserverbigdata")
include("azure-intellij-plugin-keyvault")
include("azure-intellij-plugin-keyvault-java")
include("azure-intellij-plugin-integration-services")

Просмотреть файл

@ -2,7 +2,7 @@
xmlns:xi="http://www.w3.org/2001/XInclude">
<id>com.microsoft.tooling.msservices.intellij.azure</id>
<name>Azure Toolkit for IntelliJ</name>
<version>3.91.0-SNAPSHOT</version>
<version>3.91.0</version>
<vendor email="java@microsoft.com" url="http://www.microsoft.com">Microsoft</vendor>
<description><![CDATA[
@ -54,6 +54,7 @@
<xi:include href="/META-INF/azure-sdk-reference-book.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/azure-intellij-plugin-springcloud.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/azure-intellij-plugin-storage.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/azure-intellij-plugin-storage-java.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/azure-intellij-plugin-appservice.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/azure-intellij-plugin-appservice-java.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/azure-intellij-plugin-arm.xml" xpointer="xpointer(/idea-plugin/*)"/>
@ -68,11 +69,13 @@
<xi:include href="/META-INF/azure-intellij-plugin-database-java.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/azure-intellij-plugin-vm.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/azure-intellij-plugin-redis.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/azure-intellij-plugin-redis-java.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/azure-intellij-plugin-samples.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/azure-intellij-plugin-bicep.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/azure-intellij-plugin-eventhubs.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/azure-intellij-plugin-servicebus.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/azure-intellij-plugin-keyvault.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/azure-intellij-plugin-keyvault-java.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/azure-intellij-resource-connector-aad.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/azure-intellij-plugin-hdinsight.xml" xpointer="xpointer(/idea-plugin/*)"/>
<xi:include href="/META-INF/azure-intellij-plugin-sqlserverbigdata.xml" xpointer="xpointer(/idea-plugin/*)"/>

Просмотреть файл

@ -13,8 +13,8 @@
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<azure.toolkit-lib.version>0.47.0-SNAPSHOT</azure.toolkit-lib.version>
<azure.toolkit-ide-lib.version>0.47.0-SNAPSHOT</azure.toolkit-ide-lib.version>
<azure.toolkit-lib.version>0.47.0</azure.toolkit-lib.version>
<azure.toolkit-ide-lib.version>0.47.0</azure.toolkit-ide-lib.version>
<hdinsight.toolkit-ide-lib.version>0.1.1</hdinsight.toolkit-ide-lib.version>
<gson.version>2.9.0</gson.version>
<kotlin.version>1.9.10</kotlin.version>

Просмотреть файл

@ -5,7 +5,7 @@
<parent>
<artifactId>azure-toolkit-ide-libs</artifactId>
<groupId>com.microsoft.azure</groupId>
<version>0.47.0-SNAPSHOT</version>
<version>0.47.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Просмотреть файл

@ -5,7 +5,7 @@
<parent>
<artifactId>azure-toolkit-ide-libs</artifactId>
<groupId>com.microsoft.azure</groupId>
<version>0.47.0-SNAPSHOT</version>
<version>0.47.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Просмотреть файл

@ -5,7 +5,7 @@
<parent>
<artifactId>azure-toolkit-ide-libs</artifactId>
<groupId>com.microsoft.azure</groupId>
<version>0.47.0-SNAPSHOT</version>
<version>0.47.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Просмотреть файл

@ -6,7 +6,7 @@
<parent>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-toolkit-ide-libs</artifactId>
<version>0.47.0-SNAPSHOT</version>
<version>0.47.0</version>
</parent>
<artifactId>azure-toolkit-ide-cognitiveservices-lib</artifactId>

Просмотреть файл

@ -5,7 +5,7 @@
<parent>
<artifactId>azure-toolkit-ide-libs</artifactId>
<groupId>com.microsoft.azure</groupId>
<version>0.47.0-SNAPSHOT</version>
<version>0.47.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше