@fabric-harness/azure 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -0
- package/dist/aks-sandbox.d.ts +35 -0
- package/dist/aks-sandbox.d.ts.map +1 -0
- package/dist/aks-sandbox.js +64 -0
- package/dist/aks-sandbox.js.map +1 -0
- package/package.json +22 -2
package/README.md
CHANGED
|
@@ -9,11 +9,42 @@ Current surface:
|
|
|
9
9
|
- `createAzureKeyVaultSecretResolver()` — Key Vault secret resolver for scoped commands.
|
|
10
10
|
- `FoundryAgentServiceClient` / `foundryAgentTool()` — invoke Azure AI Foundry Agent Service from Fabric agents.
|
|
11
11
|
- `AzureArmClient` tools for Container Apps jobs, AKS Run Command, and ACI exec-session creation.
|
|
12
|
+
- **`aksSandbox()`** (subpath: `@fabric-harness/azure/aks-sandbox`) — full `SandboxEnv` runtime backed by an AKS pod. Pulls cluster credentials via ARM `listClusterUserCredential` and delegates to `kubernetesSandbox` from `@fabric-harness/connectors/k8s`.
|
|
12
13
|
|
|
13
14
|
## Install
|
|
14
15
|
|
|
15
16
|
```sh
|
|
16
17
|
npm install @fabric-harness/azure @fabric-harness/sdk
|
|
18
|
+
|
|
19
|
+
# Optional: required only when using aksSandbox
|
|
20
|
+
npm install @kubernetes/client-node
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## AKS sandbox (full SandboxEnv)
|
|
24
|
+
|
|
25
|
+
Run an entire agent inside an AKS pod — `exec`/`readFile`/`writeFile`/`mkdir`/`rm` all work over the pod.
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { init } from '@fabric-harness/sdk';
|
|
29
|
+
import { createAzureArmClient } from '@fabric-harness/azure';
|
|
30
|
+
import { aksSandbox } from '@fabric-harness/azure/aks-sandbox';
|
|
31
|
+
|
|
32
|
+
const arm = createAzureArmClient({
|
|
33
|
+
subscriptionId: process.env.AZURE_SUBSCRIPTION_ID!,
|
|
34
|
+
token: process.env.AZURE_ACCESS_TOKEN!,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const sandbox = await aksSandbox({
|
|
38
|
+
arm,
|
|
39
|
+
resourceGroup: 'my-rg',
|
|
40
|
+
clusterName: 'my-aks',
|
|
41
|
+
// Either attach to an existing pod:
|
|
42
|
+
podName: 'agent-pod',
|
|
43
|
+
// Or create an ephemeral pod from an image (auto-deleted on cleanup):
|
|
44
|
+
// image: 'alpine:latest',
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const fabric = await init({ sandbox });
|
|
17
48
|
```
|
|
18
49
|
|
|
19
50
|
## Foundry Agent Service as a tool
|
|
@@ -39,6 +70,10 @@ const arm = createAzureArmClient({ subscriptionId: process.env.AZURE_SUBSCRIPTIO
|
|
|
39
70
|
const tools = [azureContainerAppsJobTool(arm), azureAksRunCommandTool(arm)];
|
|
40
71
|
```
|
|
41
72
|
|
|
73
|
+
## Build targets
|
|
74
|
+
|
|
75
|
+
`fh build --target aks` and `fh build --target aca` emit the deployment scaffolding for AKS (k8s manifests with health probes) and Azure Container Apps (azd project + Bicep with scale-to-zero) respectively. See [Azure deployment](https://harness.fabric.pro/docs/deployment/azure).
|
|
76
|
+
|
|
42
77
|
Keep Azure credentials in environment variables, managed identity token providers, or secret stores. Do not put tokens in prompts or payloads.
|
|
43
78
|
|
|
44
79
|
## License
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { SandboxEnv } from '@fabric-harness/sdk';
|
|
2
|
+
import type { AzureArmClient } from './index.js';
|
|
3
|
+
/**
|
|
4
|
+
* AKS-flavored Kubernetes sandbox. Pulls cluster credentials from the AKS
|
|
5
|
+
* `listClusterUserCredentials` endpoint, builds a `@kubernetes/client-node`
|
|
6
|
+
* `KubeConfig`, and delegates to `kubernetesSandbox`.
|
|
7
|
+
*
|
|
8
|
+
* Requires both peer deps:
|
|
9
|
+
* ```sh
|
|
10
|
+
* npm install @kubernetes/client-node
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Pod lifecycle: by default this attaches to an existing pod. To have the
|
|
14
|
+
* sandbox create its own ephemeral pod from an image, supply `image` and the
|
|
15
|
+
* pod will be created on first use and deleted on `cleanup()`.
|
|
16
|
+
*/
|
|
17
|
+
export interface AksSandboxOptions {
|
|
18
|
+
arm: AzureArmClient;
|
|
19
|
+
resourceGroup: string;
|
|
20
|
+
clusterName: string;
|
|
21
|
+
/** Kubernetes namespace. Defaults to `default`. */
|
|
22
|
+
namespace?: string;
|
|
23
|
+
/** Existing pod name to attach to. Mutually exclusive with `image`. */
|
|
24
|
+
podName?: string;
|
|
25
|
+
/** Container image. If set, AKS sandbox creates an ephemeral pod and deletes it on cleanup. */
|
|
26
|
+
image?: string;
|
|
27
|
+
/** Container name inside the pod. */
|
|
28
|
+
container?: string;
|
|
29
|
+
/** AKS API version. */
|
|
30
|
+
apiVersion?: string;
|
|
31
|
+
/** Working directory inside the pod. Defaults to `/workspace`. */
|
|
32
|
+
cwd?: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function aksSandbox(options: AksSandboxOptions): Promise<SandboxEnv>;
|
|
35
|
+
//# sourceMappingURL=aks-sandbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aks-sandbox.d.ts","sourceRoot":"","sources":["../src/aks-sandbox.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAIjD;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,cAAc,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+FAA+F;IAC/F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uBAAuB;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,UAAU,CAAC,CAsDhF"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { kubernetesSandbox, createKubernetesPod } from '@fabric-harness/connectors/k8s';
|
|
3
|
+
const requireFromHere = createRequire(import.meta.url);
|
|
4
|
+
export async function aksSandbox(options) {
|
|
5
|
+
if (!options.podName && !options.image) {
|
|
6
|
+
throw new Error('aksSandbox: provide either `podName` (attach) or `image` (ephemeral pod).');
|
|
7
|
+
}
|
|
8
|
+
const namespace = options.namespace ?? 'default';
|
|
9
|
+
const apiVersion = options.apiVersion ?? '2024-02-01';
|
|
10
|
+
const credResponse = await options.arm.request('POST', options.arm.resourcePath(options.resourceGroup, `Microsoft.ContainerService/managedClusters/${encodeURIComponent(options.clusterName)}/listClusterUserCredential`), undefined, { 'api-version': apiVersion });
|
|
11
|
+
const encoded = credResponse.kubeconfigs?.[0]?.value;
|
|
12
|
+
if (!encoded)
|
|
13
|
+
throw new Error(`aksSandbox: no kubeconfig returned for ${options.resourceGroup}/${options.clusterName}`);
|
|
14
|
+
const kubeconfig = Buffer.from(encoded, 'base64').toString('utf8');
|
|
15
|
+
const { KubeConfig, CoreV1Api } = loadK8sModule();
|
|
16
|
+
const kc = new KubeConfig();
|
|
17
|
+
kc.loadFromString(kubeconfig);
|
|
18
|
+
let podName = options.podName;
|
|
19
|
+
let ownsPod = false;
|
|
20
|
+
if (!podName) {
|
|
21
|
+
podName = `fabric-harness-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
22
|
+
const core = kc.makeApiClient(CoreV1Api);
|
|
23
|
+
await core.createNamespacedPod(namespace, {
|
|
24
|
+
apiVersion: 'v1',
|
|
25
|
+
kind: 'Pod',
|
|
26
|
+
metadata: { name: podName, labels: { 'app.kubernetes.io/managed-by': 'fabric-harness' } },
|
|
27
|
+
spec: {
|
|
28
|
+
restartPolicy: 'Never',
|
|
29
|
+
containers: [{
|
|
30
|
+
name: options.container ?? 'main',
|
|
31
|
+
image: options.image,
|
|
32
|
+
command: ['sh', '-c', 'mkdir -p /workspace && sleep infinity'],
|
|
33
|
+
workingDir: options.cwd ?? '/workspace',
|
|
34
|
+
}],
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
ownsPod = true;
|
|
38
|
+
}
|
|
39
|
+
const pod = createKubernetesPod({
|
|
40
|
+
kubeConfig: kc,
|
|
41
|
+
namespace,
|
|
42
|
+
podName,
|
|
43
|
+
...(options.container ? { container: options.container } : {}),
|
|
44
|
+
ownsPod,
|
|
45
|
+
});
|
|
46
|
+
return kubernetesSandbox(pod, {
|
|
47
|
+
cwd: options.cwd ?? '/workspace',
|
|
48
|
+
cleanup: ownsPod,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
let cachedK8sModule;
|
|
52
|
+
function loadK8sModule() {
|
|
53
|
+
if (cachedK8sModule)
|
|
54
|
+
return cachedK8sModule;
|
|
55
|
+
try {
|
|
56
|
+
const mod = requireFromHere('@kubernetes/client-node');
|
|
57
|
+
cachedK8sModule = mod;
|
|
58
|
+
return mod;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
throw new Error('aksSandbox requires the `@kubernetes/client-node` peer dependency. Install it with: npm install @kubernetes/client-node');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=aks-sandbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aks-sandbox.js","sourceRoot":"","sources":["../src/aks-sandbox.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fabric-harness/azure",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Azure Container Apps / Container Instances / AKS adapter for Fabric Harness.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Fabric",
|
|
@@ -32,15 +32,35 @@
|
|
|
32
32
|
},
|
|
33
33
|
"main": "dist/index.js",
|
|
34
34
|
"types": "dist/index.d.ts",
|
|
35
|
+
"exports": {
|
|
36
|
+
".": {
|
|
37
|
+
"types": "./dist/index.d.ts",
|
|
38
|
+
"import": "./dist/index.js"
|
|
39
|
+
},
|
|
40
|
+
"./aks-sandbox": {
|
|
41
|
+
"types": "./dist/aks-sandbox.d.ts",
|
|
42
|
+
"import": "./dist/aks-sandbox.js"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
35
45
|
"files": [
|
|
36
46
|
"dist",
|
|
37
47
|
"README.md",
|
|
38
48
|
"LICENSE"
|
|
39
49
|
],
|
|
40
50
|
"dependencies": {
|
|
41
|
-
"@fabric-harness/
|
|
51
|
+
"@fabric-harness/connectors": "0.6.0",
|
|
52
|
+
"@fabric-harness/sdk": "0.6.0"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"@kubernetes/client-node": "^0.21.0"
|
|
56
|
+
},
|
|
57
|
+
"peerDependenciesMeta": {
|
|
58
|
+
"@kubernetes/client-node": {
|
|
59
|
+
"optional": true
|
|
60
|
+
}
|
|
42
61
|
},
|
|
43
62
|
"devDependencies": {
|
|
63
|
+
"@kubernetes/client-node": "^0.21.0",
|
|
44
64
|
"@types/node": "^22.15.3",
|
|
45
65
|
"typescript": "^5.8.3",
|
|
46
66
|
"vitest": "^4.1.5"
|