Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

serviceconnector: Add Service Connector 🔗 #1476

Merged
merged 13 commits into from
Jun 23, 2023
Merged

Conversation

motm32
Copy link
Contributor

@motm32 motm32 commented May 25, 2023

Part of #1419.

This will currently be used with the Container Apps and App Service extensions. The current implementation has picks for only storage connections.

Still to do: (these will go in seperate PR's)

  • Add UI
  • Add database connections

serviceconnector/package.json Outdated Show resolved Hide resolved
serviceconnector/constants.ts Outdated Show resolved Hide resolved
@motm32 motm32 marked this pull request as ready for review June 2, 2023 20:42
@motm32 motm32 requested a review from a team as a code owner June 2, 2023 20:42
import { ISubscriptionActionContext } from "@microsoft/vscode-azext-utils";
import { TargetServiceType } from "../../constants";


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: extra new line

{ label: targetServiceLabels[0], data: { name: "storageBlob", type: TargetServiceTypeName.storage, id: '/blobServices/default' } },
{ label: targetServiceLabels[1], data: { name: "storageQueue", type: TargetServiceTypeName.storage, id: '/queueServices/default' } },
{ label: targetServiceLabels[2], data: { name: "storageTable", type: TargetServiceTypeName.storage, id: '/tableServices/default' } },
{ label: targetServiceLabels[3], data: { name: "storageFile", type: TargetServiceTypeName.storage, id: '/fileServices/default' } },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, but the other enums like StorageAccountKind use properties that start with a capital letter, so I think it would look better to do the same, i.e. TargetServiceTypeName.Storage

@MicroFish91
Copy link
Contributor

Also... would it make sense to add activity log support for createLinker/deleteLinker/validateLinker?

@motm32
Copy link
Contributor Author

motm32 commented Jun 8, 2023

Also... would it make sense to add activity log support for createLinker/deleteLinker/validateLinker?

Yup already planning to add it :). I originally was planning to just do it in the client extensions but ran into some issues with that.

export class ClientTypeStep extends AzureWizardPromptStep<ICreateLinkerContext>{
public async prompt(context: ICreateLinkerContext): Promise<void> {
const placeHolder = vscode.l10n.t('Select Language/Framework');
const picks: IAzureQuickPickItem<KnownClientType>[] = [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this ordering the same as the portal? It feels a little random/arbitrary.

I'd think we should either do it alphabetically or by what we expect to be the most common choices. That being said, I think it'd be cool if client extensions have a way to recommend/organize these picks.

For example, for a Function App, it would be very easy for us to see what runtime their app is running and have it be at the top.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the order the portal does except they exclude PHP and Ruby. I do think that the portal has some smart detection where they will pre fill in a client type for you based on the runtime of your app which would be helpful to add.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd opt for just putting it in alphabetical order so it makes some sense.

Maybe have an optional argument of KnownClientType[] so those types can get put to the top as part of the "recommended" group or something?

import { TargetServiceType, TargetServiceTypeName } from "../../constants";
import { ICreateLinkerContext } from "./ICreateLinkerContext";

export class TargetServiceTypeStep extends AzureWizardPromptStep<ICreateLinkerContext>{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also just following other conventions, but this is generally called a ListStep.

import { createServiceConnectorClient } from "../serviceConnectorClient";
import { ICreateLinkerContext } from "./ICreateLinkerContext";

export class CreateLinkerStep extends AzureWizardExecuteStep<ICreateLinkerContext>{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Generally, we call things <noun>CreateStep. Just makes it easier to organize/read (otherwise they would all start with Create.

export class ClientTypeStep extends AzureWizardPromptStep<ICreateLinkerContext>{
public async prompt(context: ICreateLinkerContext): Promise<void> {
const placeHolder = vscode.l10n.t('Select Language/Framework');
const picks: IAzureQuickPickItem<KnownClientType>[] = [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd opt for just putting it in alphabetical order so it makes some sense.

Maybe have an optional argument of KnownClientType[] so those types can get put to the top as part of the "recommended" group or something?

new AuthenticationTypeStep(),
];

promptSteps.unshift(...nonNullValue(preSteps));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't assume that this is a nonNullValue. It'll cause problems in the event no prompt steps are passed through.

You should could probably just make preSteps default to an empty array:

export async function createLinker(context: IActionContext & ExecuteActivityContext, item: LinkerItem | AzExtTreeItem, preSteps: AzureWizardPromptStep<ICreateLinkerContext>[] = []): Promise<void>

@bwateratmsft
Copy link
Contributor

bwateratmsft commented Jun 16, 2023

This will need to be added here in order to pass the PR validation. Also, can you merge main into your branch and push?

"mocha": "^9.1.3",
"mocha-junit-reporter": "^2.0.2",
"mocha-multi-reporters": "^1.1.7",
"typescript": "^4.9.4"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might as well update to the latest version of TS

export interface ICreateLinkerContext extends ISubscriptionActionContext, IStorageAccountWizardContext {
//Source resource
sourceResourceUri?: string;
scope?: string; // This is only assigned when the source resource is a container app to indicate which container is being connected
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you use a multi-line comment (/** */ kind) then VS Code will pick it up as documentation. I think you should change this to a multi-line comment to leverage this.

image

Comment on lines 14 to 15
runtime?: KnownClientType[];
clientType?: KnownClientType;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these properties specific to app service? If so, add a comment to add some context

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runtime is so I will add a comment about that being specific to app service but clientType will always be set. In the case of container apps it is set to None but is still being set.

}

export async function createLinker(context: IActionContext & ExecuteActivityContext, item: LinkerItem | AzExtTreeItem, preSteps: AzureWizardPromptStep<ICreateLinkerContext>[] = [], runtime?: KnownClientType[]): Promise<void> {
const subscription = item instanceof AzExtTreeItem ? item.subscription : createSubscriptionContext(item.subscription); // For v1.5 compatibility
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be using isAzExtTreeItem() here instead of instanceof. Classes are unique per instance of the utils package.

id: string,
}

export async function createLinker(context: IActionContext & ExecuteActivityContext, item: LinkerItem | AzExtTreeItem, preSteps: AzureWizardPromptStep<ICreateLinkerContext>[] = [], runtime?: KnownClientType[]): Promise<void> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

preSteps isn't optional, but it's not clear to me (just from looking at this method) what the preSteps need to accomplish in order to work properly. Are there specific properties on ICreateLinkerContext the preSteps should define?

If so, a comment would go a long way here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

preSteps is referring to steps that are specific to the client extension that should to be set before any of the general service connector steps. For example in container apps we need to set the container. I had originally had this as an optional parameter but ran into issues with that since I was using nonNullValue which caused an error when testing with app service since there are no pre steps for that service. For more context here is the comment Nathan left:

You shouldn't assume that this is a nonNullValue. It'll cause problems in the event no prompt steps are passed through.

You should could probably just make preSteps default to an empty array:

export async function createLinker(context: IActionContext & ExecuteActivityContext, item: LinkerItem | >AzExtTreeItem, preSteps: AzureWizardPromptStep<ICreateLinkerContext>[] = []): Promise<void>

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I'm sorry, I totally missed that it was defaulting to an empty array. That makes more sense.


export class LinkerListStep extends AzureWizardPromptStep<IPickLinkerContext>{
public async prompt(context: IPickLinkerContext): Promise<void> {
const placeHolder = vscode.l10n.t("Select a service connector");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: create the value inline where it's used below.

import { LinkerListStep } from "./LinkerListStep";

export async function deleteLinker(context: IActionContext & ExecuteActivityContext, item: LinkerItem | AzExtTreeItem, preSteps: AzureWizardPromptStep<IPickLinkerContext>[] = []): Promise<void> {
const subscription = item instanceof AzExtTreeItem ? item.subscription : createSubscriptionContext(item.subscription); // For v1.5 compatibility
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use isAzExtTreeItem() instead of instanceof.

const response = await client.linker.beginValidateAndWait(nonNullValue(context.sourceResourceUri), nonNullValue(context.linkerName));
for (const detail of nonNullValue(response.validationDetail)) {
if (detail.result === "failure") {
throw new Error(detail.description);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something we can deal with later: throwing an error here will tell our telemetry that this wizard actually failed to execute. But in reality the step succeeded in doing it's job, the linker is just invalid.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a UserCancelledError with a good cancellation step would be more accurate?

sourceResourceUri: item?.id,
}

const title: string = vscode.l10n.t('Validate service connector');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: create the value where it's used instead of making a variable up here

"@microsoft/eslint-config-azuretools/test"
],
"rules": {
"no-restricted-imports": "off"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious, where/what are we importing that we needed to turn this rule off?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was mostly basing this off the other packages since they all turn this rule off. Based on some more investigation it seems like the base rule needs to be turned off since it can return incorrect errors. For more info here's the link.

@alexweininger
Copy link
Member

Looking good. Just some final touches and we should be good to move forward and publish 🎸

@MicroFish91
Copy link
Contributor

MicroFish91 commented Jun 20, 2023

Are you planning to add a README for this package?


import { AzExtServiceClientCredentials } from "@microsoft/vscode-azext-utils";

export async function createServiceConnectorClient(credentials: AzExtServiceClientCredentials) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok so if we are going full LINKER then we should rename this file and method

Copy link
Member

@alexweininger alexweininger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔗

@motm32 motm32 changed the title serviceconnector: Add Service Connector serviceconnector: Add Service Connector 🔗 Jun 23, 2023
@motm32 motm32 merged commit 10ece51 into main Jun 23, 2023
@motm32 motm32 deleted the meganmott/serviceConnector branch June 23, 2023 18:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants