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

Create Fleet: Full Cycle Completed #1179

Merged
merged 3 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 14 additions & 25 deletions src/commands/aksFleet/aksFleetManager.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { IActionContext } from "@microsoft/vscode-azext-utils";
import * as vscode from "vscode";
import * as k8s from "vscode-kubernetes-tools-api";
import { getCredential, getReadySessionProvider } from "../../auth/azureAuth";
import { getReadySessionProvider } from "../../auth/azureAuth";
import { getAksClusterSubscriptionNode } from "../utils/clusters";
import { failed } from "../utils/errorable";
import { getResourceGroups } from "../utils/resourceGroups";
import { createFleet } from "../../panels/CreateFleetPanel";
import { ContainerServiceFleetClient } from "@azure/arm-containerservicefleet";
import { CreateFleetDataProvider, CreateFleetPanel } from "../../panels/CreateFleetPanel";
import { getExtension } from "../utils/host";

export default async function aksCreateFleet(_context: IActionContext, target: unknown): Promise<void> {
const cloudExplorer = await k8s.extension.cloudExplorer.v1;
Expand Down Expand Up @@ -38,26 +38,15 @@ export default async function aksCreateFleet(_context: IActionContext, target: u
return;
}

// Temporary code for incremental check-in.
// TODO: Replace hardcoded values with dynamic parameters or configuration settings.

// Initialize the ContainerServiceFleetClient with session credentials and subscription ID.
// Hardcoded 'subscriptionId' should be parameterized in future updates.
const client = new ContainerServiceFleetClient(
getCredential(sessionProvider.result), // Retrieve credentials from session provider.
subscriptionId, // TODO: Ensure subscriptionId is dynamically passed or configured.
);

// Create a fleet using hardcoded parameters.
// TODO: Replace hardcoded 'Fleet-Resource-Name', 'Fleet-Name', and 'Australia East' with configurable inputs.
createFleet(
client,
"Fleet-Resource-Name", // Fleet resource group name (hardcoded).
"Fleet-Name", // Fleet name (hardcoded).
{ location: "Australia East" }, // Location (hardcoded).
);

// NOTE: This temporary implementation assumes static context for testing purposes.
// Ensure these hardcoded values are replaced with appropriate dynamic configurations
// before finalizing this code for production level work which will be user focused.
const extension = getExtension();
if (failed(extension)) {
vscode.window.showErrorMessage(extension.error);
return;
}

const panel = new CreateFleetPanel(extension.result.extensionUri);

const dataProvider = new CreateFleetDataProvider(sessionProvider.result, subscriptionId, subscriptionName);

panel.show(dataProvider);
}
2 changes: 2 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import { getPlugins } from "./plugins/getPlugins";
import { aksCreateClusterFromCopilot } from "./commands/aksCreateCluster/aksCreateClusterFromCopilot";
import { aksDeployManifest } from "./commands/aksDeployManifest/aksDeployManifest";
import { aksOpenKubectlPanel } from "./commands/aksOpenKubectlPanel/aksOpenKubectlPanel";
import aksCreateFleet from "./commands/aksFleet/aksFleetManager";

export async function activate(context: vscode.ExtensionContext) {
const cloudExplorer = await k8s.extension.cloudExplorer.v1;
Expand Down Expand Up @@ -118,6 +119,7 @@ export async function activate(context: vscode.ExtensionContext) {
registerCommandWithTelemetry("aks.aksOpenKubectlPanel", aksOpenKubectlPanel);
registerCommandWithTelemetry("aks.getAzureKubernetesServicePlugins", getPlugins);
registerCommandWithTelemetry("aks.aksDraftValidate", draftValidate);
registerCommandWithTelemetry("aks.aksCreateFleet", aksCreateFleet);

await registerAzureServiceNodes(context);

Expand Down
42 changes: 36 additions & 6 deletions src/panels/CreateFleetPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export class CreateFleetDataProvider implements PanelDataProvider<"createFleet">
getLocationsRequest: () => this.handleGetLocationsRequest(webview),
getResourceGroupsRequest: () => this.handleGetResourceGroupsRequest(webview),
createFleetRequest: (args) =>
this.handleCreateFleetRequest(args.resourceGroupName, args.location, args.name),
this.handleCreateFleetRequest(args.resourceGroupName, args.location, args.name, webview),
};
}

Expand Down Expand Up @@ -109,25 +109,55 @@ export class CreateFleetDataProvider implements PanelDataProvider<"createFleet">
webview.postGetResourceGroupsResponse({ groups: usableGroups });
}

private async handleCreateFleetRequest(resourceGroupName: string, location: string, name: string) {
private async handleCreateFleetRequest(
resourceGroupName: string,
location: string,
name: string,
webview: MessageSink<ToWebViewMsgDef>,
) {
const resource = {
location: location,
};

await createFleet(this.fleetClient, resourceGroupName, name, resource);
await createFleet(this.fleetClient, resourceGroupName, name, resource, webview);
}
}

export async function createFleet(
async function createFleet(
client: ContainerServiceFleetClient,
resourceGroupName: string,
name: string,
resource: Fleet,
webview: MessageSink<ToWebViewMsgDef>,
) {
const operationDescription = `Creating fleet ${name}`;
webview.postProgressUpdate({
event: ProgressEventType.InProgress,
operationDescription,
errorMessage: null,
deploymentPortalUrl: null,
createdFleet: null,
});

try {
const result = await client.fleets.beginCreateOrUpdateAndWait(resourceGroupName, name, resource);
return { succeeded: true, result: result.name! };
const deploymentPortalUrl = `https://portal.azure.com/#resource${result.id}`;
webview.postProgressUpdate({
event: ProgressEventType.Success,
operationDescription,
errorMessage: null,
deploymentPortalUrl,
createdFleet: {
portalUrl: deploymentPortalUrl,
},
});
} catch (error) {
return { succeeded: false, error: (error as Error).message };
webview.postProgressUpdate({
event: ProgressEventType.Failed,
operationDescription,
errorMessage: (error as Error).message,
deploymentPortalUrl: null,
createdFleet: null,
});
}
}
83 changes: 83 additions & 0 deletions webview-ui/src/CreateFleet/CreateFleet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { useEffect } from "react";
import { InitialState } from "../../../src/webview-contract/webviewDefinitions/createFleet";
import { CreateFleetInput } from "./CreateFleetInput";
import { useStateManagement } from "../utilities/state";
import { Stage, stateUpdater, vscode } from "./helpers/state";
import { VSCodeLink, VSCodeProgressRing } from "@vscode/webview-ui-toolkit/react";

export function CreateFleet(initialState: InitialState) {
const { state, eventHandlers } = useStateManagement(stateUpdater, initialState, vscode);

useEffect(() => {
if (state.stage === Stage.Uninitialized) {
vscode.postGetLocationsRequest();
vscode.postGetResourceGroupsRequest();
eventHandlers.onSetInitializing(); // Set stage to Stage.Loading
}
});

useEffect(() => {
if (state.stage === Stage.Loading && state.locations !== null && state.resourceGroups !== null) {
eventHandlers.onSetInitialized(); // Set stage to Stage.CollectingInput
}
}, [state.stage, state.locations, state.resourceGroups, eventHandlers]);

function getBody() {
// Returns JSX based on the current stage
switch (state.stage) {
case Stage.Uninitialized:
case Stage.Loading:
return <p>Loading...</p>;
case Stage.CollectingInput:
return (
<CreateFleetInput
locations={state.locations!}
resourceGroups={state.resourceGroups!}
eventHandlers={eventHandlers}
vscode={vscode}
/>
);
case Stage.Creating:
return (
<>
<h3>
Creating Fleet {state.createParams!.name} in {state.createParams!.location}
</h3>
{state.deploymentPortalUrl && (
<p>
Click <VSCodeLink href={state.deploymentPortalUrl}>here</VSCodeLink> to view the
deployment in the Azure Portal.
</p>
)}

<VSCodeProgressRing />
</>
);
case Stage.Failed:
return (
<>
<h3>Error Creating Fleet</h3>
<p>{state.message}</p>
</>
);
case Stage.Succeeded:
return (
<>
<h3>Fleet {state.createParams!.name} was created successfully</h3>
<p>
Click <VSCodeLink href={state.deploymentPortalUrl!}>here</VSCodeLink> to view your fleet in
the Azure Portal.
</p>
</>
);
}
}

return (
<>
<h1>Create AKS Fleet Manager</h1>
<label>Subscription: {state.subscriptionName}</label>
{getBody()}
</>
);
}
Loading
Loading