feat: add provider profile removal
This commit is contained in:
@@ -75,6 +75,37 @@ export async function getProviderProfileConfig(profileValue: string, options: Pr
|
||||
};
|
||||
}
|
||||
|
||||
export async function removeProviderProfile(profileValue: string, options: ProviderProfileOptions = {}): Promise<JsonRecord> {
|
||||
const profile = validateBackendProfile(profileValue);
|
||||
const spec = requiredSpec(profile);
|
||||
const namespace = profileNamespace(options);
|
||||
const secret = await kubectlGetSecret(spec.defaultSecretName, namespace, options.kubectlCommand ?? "kubectl");
|
||||
const data = asOptionalRecord(secret?.data);
|
||||
const annotations = asOptionalRecord(asOptionalRecord(secret?.metadata)?.annotations);
|
||||
if (secret) await kubectlDeleteSecret(spec.defaultSecretName, namespace, options.kubectlCommand ?? "kubectl");
|
||||
return {
|
||||
action: "provider-profile-removed",
|
||||
mutation: true,
|
||||
profile,
|
||||
configured: false,
|
||||
removed: Boolean(secret),
|
||||
...(secret ? {} : { alreadyAbsent: true }),
|
||||
...(isBuiltinProviderProfile(profile) ? { builtinCapabilityRetained: true } : {}),
|
||||
secretRef: secretRefSummary(profile, namespace),
|
||||
deletedResourceVersion: stringPath(secret, ["metadata", "resourceVersion"]),
|
||||
credentialHashSuffix: hashDataKey(data, "auth.json") ?? stringPath(annotations, [`${credentialAnnotationPrefix}-credential-hash-suffix`]),
|
||||
configHashSuffix: hashDataKey(data, "config.toml") ?? stringPath(annotations, [`${credentialAnnotationPrefix}-config-hash-suffix`]),
|
||||
updatedAt: new Date().toISOString(),
|
||||
valuesPrinted: false,
|
||||
pollCommands: {
|
||||
list: "./scripts/agentrun provider-profiles list",
|
||||
show: `./scripts/agentrun provider-profiles show ${profile}`,
|
||||
setKey: `./scripts/agentrun provider-profiles set-key ${profile} --key-stdin`,
|
||||
setConfig: `./scripts/agentrun provider-profiles set-config ${profile} --config-stdin`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export async function setProviderProfileConfig(profileValue: string, body: unknown, options: ProviderProfileOptions = {}): Promise<JsonRecord> {
|
||||
const profile = validateBackendProfile(profileValue);
|
||||
const spec = requiredSpec(profile);
|
||||
@@ -304,6 +335,10 @@ function compareProviderProfiles(left: string, right: string): number {
|
||||
return left.localeCompare(right);
|
||||
}
|
||||
|
||||
function isBuiltinProviderProfile(profile: BackendProfile): boolean {
|
||||
return backendProfileSpecs.some((item) => item.profile === profile);
|
||||
}
|
||||
|
||||
function providerProfileFromSecret(secret: JsonRecord): BackendProfile | null {
|
||||
const metadata = asOptionalRecord(secret.metadata);
|
||||
const labels = asOptionalRecord(metadata?.labels);
|
||||
@@ -615,6 +650,13 @@ async function kubectlUpsertSecret(manifest: JsonRecord, kubectlCommand: string)
|
||||
throw new AgentRunError("infra-failed", `kubectl replace provider profile secret ${namespace}/${name} failed with code ${replace.code}`, { httpStatus: 502, details: redactJson({ stderr: redactText(replace.stderr.slice(-2000)), stdout: redactText(replace.stdout.slice(-1000)) }) });
|
||||
}
|
||||
|
||||
async function kubectlDeleteSecret(name: string, namespace: string, kubectlCommand: string): Promise<void> {
|
||||
const result = await runKubectl(kubectlCommand, ["delete", "secret", name, "-n", namespace, "--ignore-not-found=true"]);
|
||||
if (result.code !== 0) {
|
||||
throw new AgentRunError("infra-failed", `kubectl delete provider profile secret ${namespace}/${name} failed with code ${result.code}`, { httpStatus: 502, details: redactJson({ stderr: redactText(result.stderr.slice(-2000)), stdout: redactText(result.stdout.slice(-1000)) }) });
|
||||
}
|
||||
}
|
||||
|
||||
function isKubectlNotFoundFailure(result: { stdout: string; stderr: string }): boolean {
|
||||
return /notfound|not found|not-found/iu.test(`${result.stderr}\n${result.stdout}`);
|
||||
}
|
||||
|
||||
+2
-1
@@ -14,7 +14,7 @@ import { runnerJobStatusSummary } from "./runner-job-status.js";
|
||||
import { createSessionPvc, deleteSessionPvc, getSessionPvcSummary, refreshSessionPvcSummary, runSessionStorageGc } from "./session-pvc.js";
|
||||
import type { SessionPvcSummary } from "./session-pvc.js";
|
||||
import type { SessionPvcOptions } from "./session-pvc.js";
|
||||
import { getProviderProfileConfig, getProviderProfileValidation, listProviderProfiles, setProviderProfileConfig, setProviderProfileCredential, showProviderProfile, validateProviderProfile } from "./provider-profiles.js";
|
||||
import { getProviderProfileConfig, getProviderProfileValidation, listProviderProfiles, removeProviderProfile, setProviderProfileConfig, setProviderProfileCredential, showProviderProfile, validateProviderProfile } from "./provider-profiles.js";
|
||||
|
||||
function pvcOptions(defaults: { kubectlCommand?: string } | undefined): SessionPvcOptions {
|
||||
return defaults?.kubectlCommand ? { kubectlCommand: defaults.kubectlCommand } : {};
|
||||
@@ -96,6 +96,7 @@ async function route({ method, url, body, store, sourceCommit, runnerJobDefaults
|
||||
if (method === "GET" && path === "/api/v1/provider-profiles") return await listProviderProfiles(providerProfileDefaults) as JsonValue;
|
||||
const providerProfileMatch = path.match(/^\/api\/v1\/provider-profiles\/([^/]+)$/u);
|
||||
if (method === "GET" && providerProfileMatch) return await showProviderProfile(providerProfileMatch[1] ?? "", providerProfileDefaults) as JsonValue;
|
||||
if (method === "DELETE" && providerProfileMatch) return await removeProviderProfile(providerProfileMatch[1] ?? "", providerProfileDefaults) as JsonValue;
|
||||
const providerConfigMatch = path.match(/^\/api\/v1\/provider-profiles\/([^/]+)\/config$/u);
|
||||
if (method === "GET" && providerConfigMatch) return await getProviderProfileConfig(providerConfigMatch[1] ?? "", providerProfileDefaults) as JsonValue;
|
||||
if (method === "PUT" && providerConfigMatch) return await setProviderProfileConfig(providerConfigMatch[1] ?? "", body, providerProfileDefaults) as JsonValue;
|
||||
|
||||
Reference in New Issue
Block a user