{"_id":"@burna-org/ansible-client","name":"@burna-org/ansible-client","dist-tags":{"latest":"0.0.1"},"versions":{"0.0.1":{"name":"@burna-org/ansible-client","version":"0.0.1","description":"Ansible client library","main":"index.js","types":"dist/types/index.d.ts","scripts":{"test":"jest --runInBand","test:coverage":"jest --runInBand --coverage","typecheck":"tsc -p tsconfig.json --noEmit","build:types":"tsc -p tsconfig.types.json","clean:types":"rm -rf dist/types","prepack":"npm run clean:types && npm run build:types"},"keywords":["ansible","client","nodejs"],"author":{"name":"Burna Team"},"license":"MIT","dependencies":{"@burna-org/awx-client":"^0.0.2","consola":"^3.4.2"},"publishConfig":{"access":"public"},"devDependencies":{"jest":"^29.7.0","typescript":"^5.6.3"},"gitHead":"1ca17a7c80dc7969f7e86ec8a5a9eed2e9dd766a","_id":"@burna-org/ansible-client@0.0.1","_nodeVersion":"24.11.1","_npmVersion":"11.6.2","dist":{"integrity":"sha512-ZbehijT9WxEsnow7eT4nVKgSXd0iGS3aI3ee/PCGRAFgjDH9MESSjyag3Bj1tJyGhpTvTHXRX6njm+bOyzXbsQ==","shasum":"7ca92221e5d6bd0750a7cd85c1018cbbb06e7def","tarball":"https://registry.npmjs.org/@burna-org/ansible-client/-/ansible-client-0.0.1.tgz","fileCount":20,"unpackedSize":57545,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIEo0urmftzUBmcwwc+wQDYe0vsxkkSgaB5Rm1jAtQq7HAiEA5E0968hCnms6hifGfCSf4rMmGmV54LdGNZAjzPp0dgY="}]},"_npmUser":{"name":"radiumgh","email":"mail.rezaghanbari@gmail.com"},"directories":{},"maintainers":[{"name":"radiumgh","email":"mail.rezaghanbari@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ansible-client_0.0.1_1771751296949_0.7874702439068193"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-22T09:08:16.870Z","0.0.1":"2026-02-22T09:08:17.096Z","modified":"2026-02-22T09:08:17.280Z"},"maintainers":[{"name":"radiumgh","email":"mail.rezaghanbari@gmail.com"}],"description":"Ansible client library","keywords":["ansible","client","nodejs"],"author":{"name":"Burna Team"},"license":"MIT","readme":"# @burna-org/ansible-client\n\nAnsible workflow helpers built on top of `@burna-org/awx-client`.\n\nThis library composes:\n\n- Full AWX client API pass-through\n- Higher-level helpers for pagination, job polling, cached job reuse, and template auto-provisioning\n\n## Install\n\n```bash\nnpm install @burna-org/ansible-client @burna-org/awx-client\n```\n\n## Quick start (server)\n\n```js\nconst AWXClient = require('@burna-org/awx-client');\nconst {createAnsibleWorkflows} = require('@burna-org/ansible-client');\n\nconst awxClient = new AWXClient({\n  host: process.env.AWX_HOST,\n  username: process.env.AWX_USERNAME,\n  password: process.env.AWX_PASSWORD,\n});\n\nconst ansible = createAnsibleWorkflows({\n  awxClient,\n  config: {\n    jobResultExpirySeconds: 3600,\n    pollInitialDelay: 5000,\n    pollInterval: 2000,\n  },\n});\n```\n\n## Factory\n\n`createAnsibleWorkflows({ awxClient, config })`\n\n- `awxClient` (required): an initialized `AWXClient` instance\n- `config.jobResultExpirySeconds` (default `3600`)\n- `config.pollInitialDelay` (default `5000` ms)\n- `config.pollInterval` (default `2000` ms)\n- `config.runtimeMock` (default `false`): when `true`, use built-in mock AWX responses and avoid real HTTP calls.\n\nIf `awxClient` is missing, it throws `awxClient is required` unless `config.runtimeMock` is enabled.\nIf required AWX methods are missing, it throws `awxClient method \"<name>\" is required`.\n\n## Returned API\n\nThe returned object includes:\n\n1. All AWX methods from `@burna-org/awx-client`\n2. Workflow helper methods below\n\n### AWX pass-through methods\n\nAll of these are directly delegated to `awxClient`:\n\n- `getAccessToken`\n- `listInventories`, `listInventoryHosts`, `createInventory`, `manageInventoryHost`\n- `listJobs`, `retrieveJob`, `retrieveJobStdout`, `listJobEvents`\n- `listJobTemplates`, `createJobTemplate`, `updateJobTemplate`, `launchJobTemplate`, `listJobsForTemplate`, `manageJobTemplateCredential`\n- `listAdhocCommands`, `retrieveAdhocCommand`, `retrieveAdhocCommandStdout`, `createAdhocCommand`\n- `listProjects`, `createProject`\n- `listCredentials`, `createCredential`\n- `listOrganizations`, `createOrganization`\n- `updateHost`, `listHosts`, `listHostGroups`\n- `createGroup`, `updateGroup`, `listGroups`, `listGroupHosts`, `manageGroupHost`\n- `listExecutionEnvironments`\n- `listSettingCategories`, `listSettings`, `updateSettings`\n\n## Helper API reference\n\n### `getGroups({ inventoryName })`\n\nReturns all groups for inventory name, handling pagination.\n\nResponse:\n\n```js\n{ groups: Array, error: '' }\n```\n\n### `getHosts({ inventoryName })`\n\nFinds inventory by name, then returns all hosts with pagination.\n\nResponse:\n\n```js\n{ hosts: Array, error: '' }\n```\n\nIf inventory is not found:\n\n```js\n{ hosts: [], error: 'Failed to found inventory \"<name>\"' }\n```\n\n### `findJobTemplateId({ jobTemplateName })`\n\nResponse:\n\n```js\n{ jobTemplateId: number | null, error: string }\n```\n\n### `getLastJobResult({ jobTemplateName, limit })`\n\nReturns latest non-failed job result if not expired.\n\nUses configured `jobResultExpirySeconds`.\n\nResponse:\n\n```js\n{ job: Object | null, error: string }\n```\n\n### `handleJob({ jobTemplateName, limit, options, useLastJobResult })`\n\nFlow:\n\n1. Optionally reuse valid previous job\n2. Else launch new job template run\n3. Poll until finished\n\n`useLastJobResult` defaults to `true`.\n\nResponse:\n\n```js\n{ job: Object | null, error: string }\n```\n\n### `handleJobEvents({ jobTemplateName, limit, options, urlParams, useLastJobResult })`\n\nRuns/reuses job via `handleJob`, then fetches all events with pagination.\n\nResponse:\n\n```js\n{ jobEvents: Array, error: string }\n```\n\n### `getJobEventsByJobId({ jobId, urlParams })`\n\nPolls job by ID until completion, then returns all events.\n\nResponse:\n\n```js\n{ jobEvents: Array, error: '' }\n// or\n{ job: null, error: string }\n```\n\n### `waitForJobToFinish({ jobId })`\n\nPolls AWX until job finishes.\n\nResponse:\n\n```js\n{ job: Object | null, error: string }\n```\n\n### `ensureJobTemplate({ ... })`\n\nEnsures template exists and returns template ID. If missing, it creates template and attaches credentials.\n\nParams:\n\n- `slug` (required): logical template key (for example `deploy_app`)\n- `templateNamePrefix` (optional): prefix for generated name\n- `projectName` (required)\n- `inventoryName` (required)\n- `executionEnvironmentName` (required)\n- `credentialNames` (required): comma-separated string or array\n- `playbook` (required)\n- `extraVars` (optional object)\n- `options` (optional AWX template options)\n\nNotes:\n\n- Template display name is generated from prefix+slug and title-cased\n- Uses in-memory cache for template IDs\n- Throws on resolution/create failures\n\n### `clearTemplateCache(slug, templateNamePrefix)`\n\n- With `slug`, clears one cached entry\n- With no args, clears all cache\n\n### `getTemplateCacheStats()`\n\nReturns:\n\n```js\n{ size: number, keys: string[] }\n```\n\n## Practical examples\n\n### 1) Use helper APIs\n\n```js\nconst {groups, error} = await ansible.getGroups({inventoryName: 'production'});\nif (error) throw new Error(error);\n\nconst hostsResult = await ansible.getHosts({inventoryName: 'production'});\n```\n\n### 2) Run job with cache fallback\n\n```js\nconst result = await ansible.handleJob({\n  jobTemplateName: 'Deploy App',\n  limit: 'web-01',\n  options: {\n    extra_vars: {release: '2026.02'},\n  },\n  useLastJobResult: true,\n});\n\nif (result.error) {\n  throw new Error(result.error);\n}\n\nconsole.log('Job ID:', result.job.id);\n```\n\n### 3) Run and collect all events\n\n```js\nconst events = await ansible.handleJobEvents({\n  jobTemplateName: 'Deploy App',\n  urlParams: {\n    event: 'runner_on_ok',\n    page_size: 200,\n  },\n});\n\nif (events.error) {\n  throw new Error(events.error);\n}\n\nconsole.log(events.jobEvents.length);\n```\n\n### 4) Ensure template exists (auto-create)\n\n```js\nconst templateId = await ansible.ensureJobTemplate({\n  slug: 'deploy_app',\n  templateNamePrefix: 'kolla-',\n  projectName: 'infra-project',\n  inventoryName: 'prod-inventory',\n  executionEnvironmentName: 'default-ee',\n  credentialNames: ['machine-cred', 'vault-cred'],\n  playbook: 'site.yml',\n  extraVars: {kolla_action: 'deploy'},\n  options: {verbosity: 2},\n});\n\nconsole.log('Template ID:', templateId);\n```\n\n### 5) Cache inspection/cleanup\n\n```js\nconsole.log(ansible.getTemplateCacheStats());\nansible.clearTemplateCache('deploy_app', 'kolla-');\nansible.clearTemplateCache();\n```\n\n## Example server wrapper (Express)\n\n```js\nconst express = require('express');\nconst app = express();\n\napp.use(express.json());\n\napp.post('/api/ansible/job', async (req, res) => {\n  const {jobTemplateName, limit, options} = req.body;\n\n  const result = await ansible.handleJob({\n    jobTemplateName,\n    limit,\n    options,\n    useLastJobResult: true,\n  });\n\n  if (result.error) {\n    return res.status(400).json(result);\n  }\n\n  return res.json(result);\n});\n\napp.get('/api/ansible/job/:id/events', async (req, res) => {\n  const result = await ansible.getJobEventsByJobId({\n    jobId: Number(req.params.id),\n    urlParams: req.query,\n  });\n\n  if (result.error) {\n    return res.status(400).json(result);\n  }\n\n  return res.json(result);\n});\n```\n\n## Error handling model\n\n- Most helpers return `{..., error: ''}` on success and a non-empty `error` string on failures\n- `ensureJobTemplate` throws when required dependencies/resources cannot be resolved\n\n## Development\n\n```bash\nnpm test\nnpm run typecheck\nnpm run build:types\n```\n","readmeFilename":"README.md","_rev":"1-13b1ae8289cd830a04fda66a7cb32912"}