Skip to content

Commit

Permalink
chore: rename EnvironmentState to ApplicationState (#441)
Browse files Browse the repository at this point in the history
* chore: rename EnvironmentState to ApplicationState

* chore: rename getEnvironmentsState to getApplicationsState

* chore: rename requestRemoveEnvironment to requestRemoveApplication

* chore: rename requestRestartEnvironment to requestRestartApplication

* chore: rename to adoptRunningApplications

* chore: rename hasApplicationPod

* chore: rename sendApplicationState

* chore: rename getApplicationPod

* chore: rename updateApplicationState

* chore: rename application in test doc

* chore: Rename Environments -> Applications component

* chore: rename applicationStates

* chore: rename ApplicationActions

* chore: rename able/applications directory

* chore: rename envState to appState

* chore: misc local variables renames
  • Loading branch information
feloy authored Mar 6, 2024
1 parent adda3dd commit bc03f30
Show file tree
Hide file tree
Showing 30 changed files with 255 additions and 255 deletions.
68 changes: 34 additions & 34 deletions packages/backend/src/managers/applicationManager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1113,7 +1113,7 @@ describe('pod detection', async () => {
);
});

test('adoptRunningEnvironments updates the environment state with the found pod', async () => {
test('adoptRunningApplications updates the app state with the found pod', async () => {
mocks.listPodsMock.mockResolvedValue([
{
Labels: {
Expand All @@ -1127,10 +1127,10 @@ describe('pod detection', async () => {
mocks.startupSubscribeMock.mockImplementation((f: startupHandle) => {
f();
});
const updateEnvironmentStateSpy = vi.spyOn(manager, 'updateEnvironmentState');
manager.adoptRunningEnvironments();
const updateApplicationStateSpy = vi.spyOn(manager, 'updateApplicationState');
manager.adoptRunningApplications();
await new Promise(resolve => setTimeout(resolve, 0));
expect(updateEnvironmentStateSpy).toHaveBeenNthCalledWith(1, 'recipe-id-1', 'model-id-1', {
expect(updateApplicationStateSpy).toHaveBeenNthCalledWith(1, 'recipe-id-1', 'model-id-1', {
pod: {
Labels: {
'ai-studio-recipe-id': 'recipe-id-1',
Expand All @@ -1146,28 +1146,28 @@ describe('pod detection', async () => {
});
});

test('adoptRunningEnvironments does not update the environment state with the found pod without label', async () => {
test('adoptRunningApplications does not update the application state with the found pod without label', async () => {
mocks.listPodsMock.mockResolvedValue([{}]);
mocks.startupSubscribeMock.mockImplementation((f: startupHandle) => {
f();
});
const updateEnvironmentStateSpy = vi.spyOn(manager, 'updateEnvironmentState');
manager.adoptRunningEnvironments();
const updateApplicationStateSpy = vi.spyOn(manager, 'updateApplicationState');
manager.adoptRunningApplications();
await new Promise(resolve => setTimeout(resolve, 0));
expect(updateEnvironmentStateSpy).not.toHaveBeenCalled();
expect(updateApplicationStateSpy).not.toHaveBeenCalled();
});

test('onMachineStop updates the environments state with no environment running', async () => {
test('onMachineStop updates the applications state with no application running', async () => {
mocks.listPodsMock.mockResolvedValue([]);
mocks.onMachineStopMock.mockImplementation((f: machineStopHandle) => {
f();
});
const sendEnvironmentStateSpy = vi.spyOn(manager, 'sendEnvironmentState').mockResolvedValue();
manager.adoptRunningEnvironments();
expect(sendEnvironmentStateSpy).toHaveBeenCalledOnce();
const sendApplicationStateSpy = vi.spyOn(manager, 'sendApplicationState').mockResolvedValue();
manager.adoptRunningApplications();
expect(sendApplicationStateSpy).toHaveBeenCalledOnce();
});

test('onPodStart updates the environments state with the started pod', async () => {
test('onPodStart updates the applications state with the started pod', async () => {
mocks.listPodsMock.mockResolvedValue([]);
mocks.onMachineStopMock.mockImplementation((_f: machineStopHandle) => {});
mocks.onPodStartMock.mockImplementation((f: podStartHandle) => {
Expand All @@ -1181,12 +1181,12 @@ describe('pod detection', async () => {
},
} as unknown as PodInfo);
});
const sendEnvironmentStateSpy = vi.spyOn(manager, 'sendEnvironmentState').mockResolvedValue();
manager.adoptRunningEnvironments();
expect(sendEnvironmentStateSpy).toHaveBeenCalledOnce();
const sendApplicationStateSpy = vi.spyOn(manager, 'sendApplicationState').mockResolvedValue();
manager.adoptRunningApplications();
expect(sendApplicationStateSpy).toHaveBeenCalledOnce();
});

test('onPodStart does no update the environments state with the started pod without labels', async () => {
test('onPodStart does no update the applications state with the started pod without labels', async () => {
mocks.listPodsMock.mockResolvedValue([]);
mocks.onMachineStopMock.mockImplementation((_f: machineStopHandle) => {});
mocks.onPodStartMock.mockImplementation((f: podStartHandle) => {
Expand All @@ -1196,12 +1196,12 @@ describe('pod detection', async () => {
kind: 'podman',
} as unknown as PodInfo);
});
const sendEnvironmentStateSpy = vi.spyOn(manager, 'sendEnvironmentState').mockResolvedValue();
manager.adoptRunningEnvironments();
expect(sendEnvironmentStateSpy).not.toHaveBeenCalledOnce();
const sendApplicationStateSpy = vi.spyOn(manager, 'sendApplicationState').mockResolvedValue();
manager.adoptRunningApplications();
expect(sendApplicationStateSpy).not.toHaveBeenCalledOnce();
});

test('onPodStop updates the environments state by removing the stopped pod', async () => {
test('onPodStop updates the applications state by removing the stopped pod', async () => {
mocks.startupSubscribeMock.mockImplementation((f: startupHandle) => {
f();
});
Expand All @@ -1227,13 +1227,13 @@ describe('pod detection', async () => {
} as unknown as PodInfo);
}, 1);
});
const sendEnvironmentStateSpy = vi.spyOn(manager, 'sendEnvironmentState').mockResolvedValue();
manager.adoptRunningEnvironments();
const sendApplicationStateSpy = vi.spyOn(manager, 'sendApplicationState').mockResolvedValue();
manager.adoptRunningApplications();
await new Promise(resolve => setTimeout(resolve, 10));
expect(sendEnvironmentStateSpy).toHaveBeenCalledTimes(2);
expect(sendApplicationStateSpy).toHaveBeenCalledTimes(2);
});

test('onPodRemove updates the environments state by removing the removed pod', async () => {
test('onPodRemove updates the applications state by removing the removed pod', async () => {
mocks.startupSubscribeMock.mockImplementation((f: startupHandle) => {
f();
});
Expand All @@ -1252,13 +1252,13 @@ describe('pod detection', async () => {
f('pod-id-1');
}, 1);
});
const sendEnvironmentStateSpy = vi.spyOn(manager, 'sendEnvironmentState').mockResolvedValue();
manager.adoptRunningEnvironments();
const sendApplicationStateSpy = vi.spyOn(manager, 'sendApplicationState').mockResolvedValue();
manager.adoptRunningApplications();
await new Promise(resolve => setTimeout(resolve, 10));
expect(sendEnvironmentStateSpy).toHaveBeenCalledTimes(2);
expect(sendApplicationStateSpy).toHaveBeenCalledTimes(2);
});

test('getEnvironmentPod', async () => {
test('getApplicationPod', async () => {
mocks.listPodsMock.mockResolvedValue([
{
Labels: {
Expand All @@ -1273,7 +1273,7 @@ describe('pod detection', async () => {
},
},
]);
const result = await manager.getEnvironmentPod('recipe-id-1', 'model-id-1');
const result = await manager.getApplicationPod('recipe-id-1', 'model-id-1');
expect(result).toEqual({
Labels: {
'ai-studio-recipe-id': 'recipe-id-1',
Expand All @@ -1282,7 +1282,7 @@ describe('pod detection', async () => {
});
});

test('deleteEnvironment calls stopPod and removePod', async () => {
test('deleteApplication calls stopPod and removePod', async () => {
mocks.listPodsMock.mockResolvedValue([
{
engineId: 'engine-1',
Expand All @@ -1301,12 +1301,12 @@ describe('pod detection', async () => {
},
},
]);
await manager.deleteEnvironment('recipe-id-1', 'model-id-1');
await manager.deleteApplication('recipe-id-1', 'model-id-1');
expect(mocks.stopPodMock).toHaveBeenCalledWith('engine-1', 'pod-1');
expect(mocks.removePodMock).toHaveBeenCalledWith('engine-1', 'pod-1');
});

test('deleteEnvironment calls stopPod and removePod even if stopPod fails because pod already stopped', async () => {
test('deleteApplication calls stopPod and removePod even if stopPod fails because pod already stopped', async () => {
mocks.listPodsMock.mockResolvedValue([
{
engineId: 'engine-1',
Expand All @@ -1326,7 +1326,7 @@ describe('pod detection', async () => {
},
]);
mocks.stopPodMock.mockRejectedValue('something went wrong, pod already stopped...');
await manager.deleteEnvironment('recipe-id-1', 'model-id-1');
await manager.deleteApplication('recipe-id-1', 'model-id-1');
expect(mocks.stopPodMock).toHaveBeenCalledWith('engine-1', 'pod-1');
expect(mocks.removePodMock).toHaveBeenCalledWith('engine-1', 'pod-1');
});
Expand Down
84 changes: 42 additions & 42 deletions packages/backend/src/managers/applicationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ import { goarch } from '../utils/arch';
import { getDurationSecondsSince, timeout } from '../utils/utils';
import type { LocalRepositoryRegistry } from '../registries/LocalRepositoryRegistry';
import { LABEL_MODEL_ID, LABEL_MODEL_PORTS } from './playground';
import type { EnvironmentState } from '@shared/src/models/IEnvironmentState';
import type { ApplicationState } from '@shared/src/models/IApplicationState';
import type { PodmanConnection } from './podmanConnection';
import { MSG_ENVIRONMENTS_STATE_UPDATE } from '@shared/Messages';
import { MSG_APPLICATIONS_STATE_UPDATE } from '@shared/Messages';
import type { CatalogManager } from './catalogManager';
import { ApplicationRegistry } from '../registries/ApplicationRegistry';
import type { TaskRegistry } from '../registries/TaskRegistry';
Expand Down Expand Up @@ -76,7 +76,7 @@ export interface ImageInfo {
}

export class ApplicationManager {
#applications: ApplicationRegistry<EnvironmentState>;
#applications: ApplicationRegistry<ApplicationState>;
protectTasks: Set<string> = new Set();

constructor(
Expand All @@ -90,7 +90,7 @@ export class ApplicationManager {
private telemetry: TelemetryLogger,
private localRepositories: LocalRepositoryRegistry,
) {
this.#applications = new ApplicationRegistry<EnvironmentState>();
this.#applications = new ApplicationRegistry<ApplicationState>();
}

async pullApplication(recipe: Recipe, model: ModelInfo) {
Expand Down Expand Up @@ -147,8 +147,8 @@ export class ApplicationManager {
);

// first delete any existing pod with matching labels
if (await this.hasEnvironmentPod(recipe.id, model.id)) {
await this.deleteEnvironment(recipe.id, model.id);
if (await this.hasApplicationPod(recipe.id, model.id)) {
await this.deleteApplication(recipe.id, model.id);
}

// create a pod containing all the containers to run the application
Expand Down Expand Up @@ -575,7 +575,7 @@ export class ApplicationManager {
}
}

adoptRunningEnvironments() {
adoptRunningApplications() {
this.podmanConnection.startupSubscribe(() => {
if (!containerEngine.listPods) {
// TODO(feloy) this check can be safely removed when podman desktop 1.8 is released
Expand All @@ -585,8 +585,8 @@ export class ApplicationManager {
containerEngine
.listPods()
.then(pods => {
const envsPods = pods.filter(pod => LABEL_RECIPE_ID in pod.Labels);
for (const podToAdopt of envsPods) {
const appsPods = pods.filter(pod => LABEL_RECIPE_ID in pod.Labels);
for (const podToAdopt of appsPods) {
this.adoptPod(podToAdopt);
}
})
Expand All @@ -605,7 +605,7 @@ export class ApplicationManager {
}

this.#applications.clear();
this.sendEnvironmentState();
this.sendApplicationState();
});

this.podmanConnection.onPodStart((pod: PodInfo) => {
Expand All @@ -630,14 +630,14 @@ export class ApplicationManager {
if (this.#applications.has({ recipeId, modelId })) {
return;
}
const state: EnvironmentState = {
const state: ApplicationState = {
recipeId,
modelId,
pod,
appPorts,
modelPorts,
};
this.updateEnvironmentState(recipeId, modelId, state);
this.updateApplicationState(recipeId, modelId, state);
}

forgetPod(pod: PodInfo) {
Expand All @@ -650,7 +650,7 @@ export class ApplicationManager {
return;
}
this.#applications.delete({ recipeId, modelId });
this.sendEnvironmentState();
this.sendApplicationState();

const protect = this.protectTasks.has(pod.Id);
if (!protect) {
Expand All @@ -664,20 +664,20 @@ export class ApplicationManager {
}

forgetPodById(podId: string) {
const env = Array.from(this.#applications.values()).find(p => p.pod.Id === podId);
if (!env) {
const app = Array.from(this.#applications.values()).find(p => p.pod.Id === podId);
if (!app) {
return;
}
if (!env.pod.Labels) {
if (!app.pod.Labels) {
return;
}
const recipeId = env.pod.Labels[LABEL_RECIPE_ID];
const modelId = env.pod.Labels[LABEL_MODEL_ID];
const recipeId = app.pod.Labels[LABEL_RECIPE_ID];
const modelId = app.pod.Labels[LABEL_MODEL_ID];
if (!this.#applications.has({ recipeId, modelId })) {
return;
}
this.#applications.delete({ recipeId, modelId });
this.sendEnvironmentState();
this.sendApplicationState();

const protect = this.protectTasks.has(podId);
if (!protect) {
Expand All @@ -690,27 +690,27 @@ export class ApplicationManager {
}
}

updateEnvironmentState(recipeId: string, modelId: string, state: EnvironmentState): void {
updateApplicationState(recipeId: string, modelId: string, state: ApplicationState): void {
this.#applications.set({ recipeId, modelId }, state);
this.sendEnvironmentState();
this.sendApplicationState();
}

getEnvironmentsState(): EnvironmentState[] {
getApplicationsState(): ApplicationState[] {
return Array.from(this.#applications.values());
}

sendEnvironmentState() {
sendApplicationState() {
this.webview
.postMessage({
id: MSG_ENVIRONMENTS_STATE_UPDATE,
body: this.getEnvironmentsState(),
id: MSG_APPLICATIONS_STATE_UPDATE,
body: this.getApplicationsState(),
})
.catch((err: unknown) => {
console.error(`Something went wrong while emitting MSG_ENVIRONMENTS_STATE_UPDATE: ${String(err)}`);
console.error(`Something went wrong while emitting MSG_APPLICATIONS_STATE_UPDATE: ${String(err)}`);
});
}

async deleteEnvironment(recipeId: string, modelId: string) {
async deleteApplication(recipeId: string, modelId: string) {
// clear any existing status / tasks related to the pair recipeId-modelId.
this.taskRegistry.deleteByLabels({
'recipe-id': recipeId,
Expand All @@ -722,9 +722,9 @@ export class ApplicationManager {
'model-id': modelId,
});
try {
const envPod = await this.getEnvironmentPod(recipeId, modelId);
const appPod = await this.getApplicationPod(recipeId, modelId);
try {
await containerEngine.stopPod(envPod.engineId, envPod.Id);
await containerEngine.stopPod(appPod.engineId, appPod.Id);
} catch (err: unknown) {
// continue when the pod is already stopped
if (!String(err).includes('pod already stopped')) {
Expand All @@ -734,8 +734,8 @@ export class ApplicationManager {
throw err;
}
}
this.protectTasks.add(envPod.Id);
await containerEngine.removePod(envPod.engineId, envPod.Id);
this.protectTasks.add(appPod.Id);
await containerEngine.removePod(appPod.engineId, appPod.Id);

stoppingTask.state = 'success';
stoppingTask.name = `AI App stopped`;
Expand All @@ -748,25 +748,25 @@ export class ApplicationManager {
}
}

async restartEnvironment(recipeId: string, modelId: string) {
const envPod = await this.getEnvironmentPod(recipeId, modelId);
await this.deleteEnvironment(recipeId, modelId);
async restartApplication(recipeId: string, modelId: string) {
const appPod = await this.getApplicationPod(recipeId, modelId);
await this.deleteApplication(recipeId, modelId);
const recipe = this.catalogManager.getRecipeById(recipeId);
const model = this.catalogManager.getModelById(envPod.Labels[LABEL_MODEL_ID]);
const model = this.catalogManager.getModelById(appPod.Labels[LABEL_MODEL_ID]);
await this.startApplication(recipe, model);
}

async getEnvironmentPod(recipeId: string, modelId: string): Promise<PodInfo> {
const envPod = await this.queryPod(recipeId, modelId);
if (!envPod) {
async getApplicationPod(recipeId: string, modelId: string): Promise<PodInfo> {
const appPod = await this.queryPod(recipeId, modelId);
if (!appPod) {
throw new Error(`no pod found with recipe Id ${recipeId} and model Id ${modelId}`);
}
return envPod;
return appPod;
}

async hasEnvironmentPod(recipeId: string, modelId: string): Promise<boolean> {
const envPod = await this.queryPod(recipeId, modelId);
return !!envPod;
async hasApplicationPod(recipeId: string, modelId: string): Promise<boolean> {
const appPod = await this.queryPod(recipeId, modelId);
return !!appPod;
}

async queryPod(recipeId: string, modelId: string): Promise<PodInfo | undefined> {
Expand Down
Loading

0 comments on commit bc03f30

Please sign in to comment.