{"id":21672157,"url":"https://github.com/cesarvr/okd-client","last_synced_at":"2025-06-20T11:35:17.439Z","repository":{"id":57313999,"uuid":"168842721","full_name":"cesarvr/okd-client","owner":"cesarvr","description":"Node.js client to make calls to Kubernetes/OpenShift","archived":false,"fork":false,"pushed_at":"2019-12-10T13:13:26.000Z","size":137,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-09T07:12:24.948Z","etag":null,"topics":["client-side","kubernetes","okd","openshift","restful"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cesarvr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-02-02T14:57:37.000Z","updated_at":"2022-02-24T15:04:22.000Z","dependencies_parsed_at":"2022-09-20T23:30:41.268Z","dependency_job_id":null,"html_url":"https://github.com/cesarvr/okd-client","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cesarvr/okd-client","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cesarvr%2Fokd-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cesarvr%2Fokd-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cesarvr%2Fokd-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cesarvr%2Fokd-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cesarvr","download_url":"https://codeload.github.com/cesarvr/okd-client/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cesarvr%2Fokd-client/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260937288,"owners_count":23085655,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["client-side","kubernetes","okd","openshift","restful"],"created_at":"2024-11-25T13:18:49.954Z","updated_at":"2025-06-20T11:35:12.422Z","avatar_url":"https://github.com/cesarvr.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## OKD Node.js Client\n\nThis Node.JS RESTful client API for Kubernetes/OpenShift. This library helps you use JavaScript to write simple programs to automate things like deploy images, listen for cluster events, [build/create containers](#binary) (OpenShift only at the moment), watch push/pull images etc. Or more sophisticated things like send me an email/slack message if a particular pod crash.\n\n## Index\n\n* [Installing](#install)\n* [Login](#login)\n* [Initialize With Token](#token)\n* [Select Namespace](#ns)\n* [Components](#res)\n* [CRUD](#common)\n  - [Find All](#all)\n  - [Find By Name](#by_name)\n  - [Remove](#remove)\n  - [Create](#create)\n  - [Template](#template)\n    - [Faster Template](#fii)\n  - [Patch](#patch)\n  - [Update](#update)\n* [Watch](#watch)\n  - [All](#watch_all)\n* [Concrete Implementations](#concrete)\n  - [Build Configuration](#bc)\n    - [Binary Build](#binary)\n  - [Pods](#pods)\n    - [Logs](#logs)\n* [Bot Example](#examples)\n\n\u003ca name=\"install\"/\u003e\n\n### Installing\n\n```sh\n  npm i okd-api\n```\n\n```js\nconst { login, okd } = require('okd-api')\n```\n\n\n\u003ca name=\"login\"/\u003e\n\n### Login into OpenShift\n\nThis API exposes two objects ```login``` which handles the login against a OpenShift cluster.\n\n```js\nlet config = {\n  cluster:'https://okd.address.com/',\n  user: 'user',\n  password: '***',\n  strictSSL: true || false  \n}\n\nlogin(config)\n    .then(okd =\u003e /* do something... */)\n    .catch(err =\u003e /* auth failed... */)\n```\n\nThe login function receive an configuration following object:\n\n - **cluster** Kubernetes server URL.\n - **user, password**  Your user and password.\n - **strictSSL** Some implementations like [Minishfit](https://github.com/minishift/minishift) use a self-signed SSL certificate which trigger a security warning for https clients, is that your case turn this to false.  \n\nThe login functions returns an ``okd`` object after it finish the authentication with the server, the ``okd`` object is the one in charge of to talk against the API server.\n\n\u003ca name=\"token\"/\u003e\n\n#### With Token\n\nIf you already have a token (because you previously acquired one through authentication) you can provide the cluster URL and the token.\n\n```js\n  const cluster = `https://minishfit.vm:8443/`\n  const token = 'v0tDED5vjN7Vv...'\n  let imagestream = okd(cluster, token).namespace('dev-665').is\n\n  imagestream.all().then(/*...*/)\n                   .catch(/*...*/)\n```\n\n\n\n\n\u003ca name=\"ns\"/\u003e\n\n### Namespace\n\n[Namespaces](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/) is a way to partition resources across your Kubernetes/OpenShift cluster. This mean that to access a particular resource such as [BuildConfig](https://docs.openshift.com/container-platform/3.9/dev_guide/builds/index.html) you need first need to specify the namespace.\n\n```js\n  okd.namespace('dev-665')\n\n  /* Now you can use this okd object for resources in the dev-665 namespace*/\n\n  okd.svc.all() /*...*/\n```\n\nIf you need to operate across multiple namespaces you just need to instantiate multiple objects.\n\n```js\nfunction useNS(ns) {\n  const cluster = `https://my-cluster.com/`\n  const token = 'v0tDED5vjN7Vv...'\n  return okd(cluster, token).namespace(ns)\n}\n\nmyScripts.forEach(script =\u003e useNS('A').from_template('app-1',script).post())\nmyScripts.forEach(script =\u003e useNS('B').from_template('app-1',script).post())\nmyScripts.forEach(script =\u003e useNS('C').from_template('app-1',script).post())\n```\n\n\n#### Retrieve Token\n\nOnce the client login with the server you receive an OAuth token to get this token and other information by calling the ``config`` method.\n\n```js\n okd.config( opts =\u003e {\n   console.log(opts)\n   /* {  namespace: '....',\n         cluster: '....',\n         token: '....',\n         strictSSL: true || false\n       } */\n })\n```\n\n\u003ca name=\"res\"/\u003e\n\n### Components\n\nThis are the objects supported at the moment:\n\n- OpenShift  \n  - [ImageStream](https://docs.openshift.com/enterprise/3.0/architecture/core_concepts/builds_and_image_streams.html)\n  - [BuildConfig](https://docs.openshift.com/container-platform/3.9/dev_guide/builds/index.html)\n  - [Build](https://docs.openshift.com/container-platform/3.9/dev_guide/builds/index.html)\n  - [DeploymentConfig](https://docs.openshift.com/enterprise/3.0/dev_guide/deployments.html)\n  - [Router](https://docs.openshift.com/container-platform/3.9/install_config/router/index.html)\n  - [Project](https://docs.openshift.com/container-platform/3.7/dev_guide/projects.html) *Requires Admin*\n\n- Kubernetes\n  - [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)\n  - [Service](https://kubernetes.io/docs/concepts/services-networking/service/)\n  - [Pod](https://kubernetes.io/docs/concepts/workloads/pods/pod/)\n  - [ReplicaSet](https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/)\n  - [Namespace](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/) *Require Admin*\n\n\nTo access those elements like this:\n\n  ```js\n    okd.is         // OpenShift ImageStream\n    okd.bc         // OpenShift BuildConfig\n    okd.build      // OpenShift Build\n    okd.project    // OpenShift Project \n    okd.dc         // OpenShift DeploymentConfig\n    okd.route      // OpenShift Routes\n    okd.svc        // OpenShift/Kubernetes services\n    okd.pod        // OpenShift/Kubernetes pod\n    okd.deploy     // OpenShift/Kubernetes deployment\n    okd.rs         // OpenShift/Kubernetes replica sets\n    okd.namespace     // OpenShift/Kubernetes Namespaces \n  ```\n\n\n\n---\n\n\u003ca name=\"common\"/\u003e\n\n## CRUD\n\nEach of this objects support a common set of functionalities which are related to the basic HTTP REST verbs. Let's talk in more detail about those functions.\n\n\u003ca name=\"all\"/\u003e\n\n### Find All\n\nReturns a promise which resolve in the future with a list of all the objects of a particular type.\n\n\n```js\n  // Returns a promise with all imagestreams in the namespace dev-655.\n  okd.namespace('dev-665')\n     .is\n     .all()      \n\n\n  // All Services\n  okd.namespace('dev-1')\n     .svc\n     .all()\n```\n\n\u003ca name=\"by_name\"/\u003e\n\n### By Name\n\nYou can also find resources by name:\n\n```js\n  okd.namespace('dev-665')\n     .is\n     .by_name('nodejs-image')\n```\nReturns Imagestream called `nodejs-image`.\n\n\n\u003ca name=\"remove\"/\u003e\n\n### Remove\n\nTo remove a resource from the cluster:\n\n```js\nokd.namespace('dev-665')\n   .is\n   .remove('nodejs-image')\n```\n\nIt returns a promise with the response from the server.\n\n\u003ca name=\"create\"/\u003e\n\n### Creating\n\nTo create Kubernetes/OpenShift objects you can use the following:\n\n```js\n  let deploy = okd.namespace('dev-665').deploy\n  deploy.post('name')\n```\n\nUsually you want to describe the configuration of your components and for that reason there is a  template system.\n\n\n\u003ca name=\"template\"/\u003e\n\n### Template\n\nObjects in Kubernetes are defined using a templates like this one:\n\n```yml\napiVersion: apps/v1beta1\nkind: Deployment\nmetadata:\n  name: \u003c%=name%\u003e\n  labels:\n    app: \u003c%=name%\u003e\nspec:\n  replicas: 1\n  selector:\n    matchLabels:\n      app: \u003c%=name%\u003e\n  template:\n    metadata:\n      labels:\n        app: \u003c%=name%\u003e\n    spec:\n      containers:\n      - name: \u003c%=name%\u003e\n        image: \u003c%=image%\u003e\n        command: ['sh', '-c', 'echo Hello Kubernetes! \u0026\u0026 sleep 3600']\n        ports:\n        - containerPort: 8080\n```\n\nThis is what a Deployment looks like, this API support template parameters that helps you create reusable templates, in this example we can replace the ``\u003c%=name%\u003e`` and ``\u003c%=image%\u003e`` placeholders with actual information like this:\n\n```js\n  let deploy = okd.namespace('dev-665')\n                  .deploy\n\n  deploy.load({name: 'my-deployment', image:'nginx'}, 'deploy.yml')\n        .post()\n```\n\nThis code push to the server a Deployment object with the following shape:  \n\n```xml\napiVersion: apps/v1beta1\nkind: Deployment\nmetadata:\n  name: my-deployment\n  labels:\n    app: my-deployment\nspec:\n  replicas: 1\n  ...\n  containers:\n   image: nginx\n  ...\n```\n\n\n### Editing template at Runtime\n\nTo modify the template at run-time you can do the following:\n\n```js\nlet deploy = okd.namespace('dev-665').deploy\nlet object = deploy.load({name: 'my-deployment', image:'nginx'}, 'deploy.yml')._tmpl   //pass by reference\n\n\nobject.metadata.name = 'deploy-y'\ndeploy.post()   // we send the template with the amended field.\n```\n\n\n\u003ca name=\"fii\"/\u003e\n\n### Faster Template\n\nTemplate operations above can be done faster by using this shortcut:\n\n```js\n  okd.namespace('dev-003')\n  okd.from_template(this.appName,'./tmpl/imagestream.yml').post()\n```\n\n**from_template** will auto-detect the type of template you try to use and if its supported you can perform the actions for example:\n\n```js\n  let deploy = okd.from_template(this.appName,'./tmpl/deployment.yml')\n```\n\nIf ``deployment.yml`` is a valid Deployment template it will return an ``okd.deploy`` object, equivalent to something like this:\n\n\n```js\nlet deploy = okd.deploy\n```\n\nThe difference is that the information about the deployment is encapsulated inside the object, allowing you act over the object.\n\n```js\n  //['tmpl0.yml','tmpl1.yml', 'tmpl2.yml'... ]\n  let objs = ['./deploy.yml','pod.yml', 'route.yml' ]\n                .map(tmpl =\u003e okd.from_template(tmpl))\n\n  // create all\n    objs.forEach(obj =\u003e obj.create())\n\n\n  //delete all\n    objs.forEach(obj =\u003e obj.remove())    \n```\n\n\u003ca name=\"update\"/\u003e\n\n### Update\n\nTo update a Kubernetes component such as Deployment you can use the ``put`` or ``update`` method, this method fetch a copy of the actual resource from the server and apply a merge, for example:\n\nLet's assume an imaginary object ``A`` is in the cloud:\n\n```js\n A {\n     a:1,\n     b:2,\n     c:3,\n     d: { e: 5  }\n   }\n```\n\nTo update the ``e``  property to **1** we can do:\n\n```js\n okd.Atype.put( { b: {e: 1 } })\n   .then(ok =\u003e  /* success */ )\n```\n\nAfter we execute this command we should get this:\n\n```js\n A {\n     a:1,\n     b:2,\n     c:3,\n     d: { e: 1  }\n   }\n```\n\n\nIn the following example we are going to update a Deployment controller ``test`` to 3 replicas.\n\n```js\nlogin(store.configuration)\n    .then(okd =\u003e {\n        okd.namespace('hello')\n        okd.config((conf) =\u003e store.save(conf))\n        return okd.deploy.put('test', {spec: { replicas: 3 }})\n    })\n    .then(  ok =\u003e console.log('update-\u003e', ok))\n    .catch(err =\u003e console.log('failing: ', err))\n```\n\n\u003ca name=\"patch\"/\u003e\n\n### Patch\n\nAnother way to update Kubernetes object is to use the ``patch`` method, this method requires the [json-PATCH](http://jsonpatch.com/) protocol, for example:\n\n```js\nlet update = {\n  op:'replace',\n  path:'/spec/template/spec/containers/0/image',\n  value: 'awesome:test-23'\n}\n\nlet deploy = okd.namespace('dev-001').deploy\n\ndeploy.patch('awesome-app', update)\n```\n\nThis will update the deployment object and automatically this change will trigger a re-deployment.\n\n\n---\n\n\u003ca name=\"watch\"/\u003e\n\n### Watch\n\nKubernetes/OpenShift uses an [event](https://kubernetes.io/docs/tasks/debug-application-cluster/events-stackdriver/) system to keep track of changes in the cluster, we can listen to this changes individually using the ``watch`` function.     \n\n```js\n  okd.okd_object.watch(name, event =\u003e {})\n```\n  - **name** The name of the object we want to listen for state change.\n\n  - ``event =\u003e `` A function that receives Kubernetes [events](https://kubernetes.io/docs/reference/federation/v1/definitions/#_v1_event).\n\n\n\nThe *event* have the form of:\n\n```js\n{\n  type: \"MODIFIED\",  /* DELETE, ADDED */\n  object: {\n    kind: \"Service\",\n    apiVersion: \"v1\",\n    /*...*/\n  }\n}\n```\n\nType define the action and object is basically a [Kubernetes/OKD](#res) object definition.\n\n\n\n#### Usage Example\n\n```js\nokd.namespace('hello')\n\n// Watch for new builds\nokd.is.watch('micro-1', (event)=\u003e {\n  if (event.type === 'MODIFIED') {   \n    // Deploy this image to ...\n  }\n})\n\n// Watch for for actions in this pod\nokd.pod.watch('nginx-prod', (event)=\u003e {\n  if (event.type === 'DELETED') {  \n    // Call emergency...\n  }\n})\n\n```\n\n\n\u003ca name=\"watch_all\"/\u003e\n\n### Watching All Objects\n\nOr we can watch them all using the ``watch_all`` function, and listen any events in the ``namespace`` for a particular object type.\n\n```js\n  okd.resource.watch_all( (events) =\u003e {  /* events [ event 1, event 2, ... ]*/  } )\n```\n\nThis function receives array of [events](https://kubernetes.io/docs/reference/federation/v1/definitions/#_v1_event) as parameters. To watch the pods running we can do this:\n\n\n```js\nconst login = require('okd-api').login\n\nlogin(store.configuration) //{cluster: '****', user:'user', ...}\n    .then(okd =\u003e okd.namespace('testing') // watch in testing namespace\n                    .pod\n                    .watch_all(watch_test))\n    .catch(err =\u003e console.log('Authentication error: ', err))\n\n```\n\n\nWe call a ``watch_all`` function a pass a function called ``watch_test`` this function should have the following signature:\n\n```js\n\nfunction watch_test(events) {\n  let type     = events[0].type\n  let phase    = events[0].object.status.phase\n  let pod_name = events[0].object.metadata.name\n\n    // Only show compute pods in OKD ;)\n    if(!( 'openshift.io/build.name' in annotations)  ) {\n      console.log(`event type ${events[0].type} -\u003e ${pod_name}`)\n      console.log(`phase =\u003e `, phase)\n    }\n}\n\n```\n\n\nContrary to the cases above, here should use a callback because we are dealing with a stateful connection which will remain as long as the timeout limit establish by the cluster administrator. The event type is similar to the one we used above.\n\n\n![](https://github.com/cesarvr/hugo-blog/blob/master/static/static/gifs/global-events.gif?raw=true)\n\n\n\u003ca name=\"concrete\"/\u003e\n\n# Concrete Implementations\n\nSome Kubernetes/OKD objects have unique functionalities, in the case of pod for example aside from common functionalities they also implement other functions like logs, exec, etc.\n\n\u003ca name=\"bc\"/\u003e\n\n## Build Configuration\n\n\u003ca name=\"binary\"/\u003e\n\n### Trigger A Binary Build\n\nFor now the only way to trigger a build in using this API is by uploading a binary.\n\nFor example:\n\n```js\nfunction compressWorkSpace(dir, name){\n    let tmp_file = name || './okd.tar.gz'\n    let ret = spawn('tar', ['-Czf', tmp_file, '-C', dir, dir]) // tar the directory, forget parent\n    return tmp_file\n}\n\n/* tar the workspace folder */\nlet file = compressWorkSpace('build.tar.gz', '~/my-nodejs-project')\n\nokd.bc.binary(file, 'micro-1') // micro-1 should be an existing BuildConfig\n.then(ok =\u003e console.log('The build has started...'))\n.catch(noErrors)\n```\n\n\u003ca name=\"pods\"/\u003e\n\n## Pods\n\n[Pods](https://kubernetes.io/docs/concepts/workloads/pods/pod/) are the building blocks for Kubernetes applications, they also expose some functionalities that can be useful:\n\n\n\u003ca name=\"logs\"/\u003e\n\n### Logs\n\nThere is two options to watch pod logs first is getting the whole bulk, by using the ``pod.logs`` method:\n\n```js\nokd.pod.by_name('my-pod')\n       .then(pod  =\u003e pod.metadata.name)\n       .then(name =\u003e okd.pod.logs(name))\n       .then(logs =\u003e console.log(logs))\n```\n\nThis will return the logs for the pod ``my-pod``\n\n```sh\nnpm info using npm@6.4.1\nnpm info using node@v10.12.0\nnpm info lifecycle my-app@1.0.0~prestart: my-app@1.0.0\nnpm info lifecycle my-app@1.0.0~start: my-app@1.0.0\n\u003e my-app@1.0.0 start /opt/app-root/src\n\u003e node app.js\n```\n\nThis method give you a snapshot of the current state but you will miss further updates, to keep streaming logs in real-time you can use the ``pod.stream_logs`` method:\n\n\n```js\nokd.pod.stream_logs(podName, line =\u003e {\n    console.log(line)    // npm info using npm@6.4.1 ...\n                         // npm info using node@v10.12.0\n})\n```\n\nThis method keeps track of the latest logs update in the pod.\n\nIf you are running multiple containers in a single *pod* then you can target that container using function ``container`` like this:\n\n```js\nokd.namespace('dev-0')\n             .pod\n             .container('ftp-server')\n             .logs('static-files-pod')\n             .then(logs =\u003e {\n                /* Read the logs */\n             })\n```\n\n\u003ca name=\"examples\"/\u003e\n\n## Writing A Bot\n\nLet's build a bot that fetch the logs of any container that is being deploying in our cluster, this can be interesting to follow the stages of an applications from building, testing and execution from one place.  \n\n### Login\n\n```js\nconst { login } = require('okd-api')\n\nlogin(store.configuration) // {cluster: '****', user:'user', ...}\n    .then(okd =\u003e okd.namespace('testing')\n                    .pod\n                    .watch_all( pods =\u003e // pods events )\n         )\n    .catch(err =\u003e console.log('Authentication error: ', err))\n```\n\n\nWe have done the login and we setup the watch for the namespace ``testing`` next we need to create a function that watch and capture the transition of pods from ``Pending`` to ``Running``.\n\n\n```js\n\nfunction watch_bot(okd, name) {\n    let pending = {}\n\n    // Closure that will\n    return function(events) {\n        // for more info about event object --\u003e\n        //https://kubernetes.io/docs/reference/federation/v1/definitions/#_v1_event\n        let annotations = events[0].object.metadata.annotations\n        let labels = events[0].object.metadata.labels\n        let phase = events[0].object.status.phase\n        let pod_name = events[0].object.metadata.name\n\n        // Capture pods transitioning from Pending to Running.\n        // This means being deployed...\n        if(phase === 'Pending') {\n            console.log(`event type ${events[0].type} -\u003e ${pod_name}`)\n            console.log(`phase =\u003e `, events[0].object.status.phase)\n\n            pending[pod_name] = true\n        }\n\n        // If the pod goes from Pending to Running...\n        // ... We show the logs.\n        if(phase === 'Running' \u0026\u0026 pending[pod_name]) {\n            console.log('\\033[2J')  // clear screen...\n            console.log('pod: ', pod_name)\n            console.log('================================')\n\n            // Watch the logs for this pod: pod_name\n            okd.pod.stream_logs(pod_name, (logs)=\u003e {\n              // We read the logs and print the logs...\n              process.stdout.write(logs)\n            })\n            pending[pod_name] = false\n        }\n    }\n}\n\n```\n\nThis function does just that it just listen for pods doing the transitions and then we finally use the ``pod.stream_logs`` to retrieve the logs from the targeted pod. If we run this program we are going to get something like this:\n\n![](https://github.com/cesarvr/hugo-blog/blob/master/static/static/gifs/logs.gif?raw=true)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcesarvr%2Fokd-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcesarvr%2Fokd-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcesarvr%2Fokd-client/lists"}