npm package: @pubgcorp/kubectl-node
Description: Limited and partial implementation of kubectl.
Author: PUBG DevOps
Latest version: 1.5.0

# kubectl-node

Limited and partial implementation of kubectl.

### ⚠️ Caution ⚠️

"kubectl-node" uses server-side-apply to modify resources.
Modification by "kubectl-node" may cause conflict.

## Install

```bash
# NPM
npm install @pubgcorp/kubectl-node

# YARN
yarn add @pubgcorp/kubectl-node
```

## Basic Usage

### Create kubectl instance

Javascript

```javascript
const fs = require("fs");
const os = require("os");
const yaml = require("js-yaml"); // if you use js-yaml, need to install

const { NewKubectl } = require("@pubgcorp/kubectl-node");
// kubeconfig sample

const kubeconfig = yaml.load(fs.readFileSync(`${os.homedir()}/.kube/config`, "utf8"));
const kubectl = NewKubectl(kubeconfig)
```

Typescript

```typescript
import * as fs from "fs"
import * as os from "os"
import * as yaml from "js-yaml" // if you use js-yaml, need to install

import { NewKubectl, KubeConfig } from "@pubgcorp/kubectl-node";
// kubeconfig sample

const kubeconfig = yaml.load(fs.readFileSync(`${os.homedir()}/.kube/config`, "utf8")) as KubeConfig;
const kubectl = NewKubectl(kubeconfig)
```

### kubectl api-resources, api-versions, version

Get api-resources, api-versions and version from cluster

```typescript
const apiResources = await kubectl.apiResources();
const apiVersions = await kubectl.apiVersions();
const version = await kubectl.version();
```

### kubectl get

Get single resource

```typescript
// get without namespace (search `default` namespace by default);
//  => equivalant to `kubectl.get('deployment', 'nginx', { namespace: "default" })`;
const result = await kubectl.get('deployment', 'nginx');
```

```typescript
// get with namespace
const result = await kubectl.get('deployment', 'nginx', { namespace: 'my-namespace' });
```

### kubectl list

Get collection of resources

```typescript
// list without namespace (search `default` namespace by default);
const result = await kubectl.list('deployment');
```

```typescript
// list with namespace
const namespace = "my-namespace";
const result = await kubectl.list('deployment', { namespace });
```

```typescript
// list all resources in all namespaces
const result = await kubectl.list('deployment', { allNamespaces: true });
```

```typescript
// list with labelSelector
const result1 = await kubectl.list('deployment', { allNamespaces: true, labelSelector: { app: 'nginx' }});
const result2 = await kubectl.list('deployment', { allNamespaces: true, labelSelector: { app: { op: 'In', values: ['nginx'] } }});
```

```typescript
// list with fieldSelector
const result1 = await kubectl.list('pod', { allNamespaces: true, fieldSelector: [{ path: 'spec.nodeName', op: 'Equal', value: 'docker-desktop' }] })
const result2 = await kubectl.list('pod', { allNamespaces: true, fieldSelector: [{ path: 'status.podIP', op: 'NotEqual', value: '10.1.0.8' }] })
const result3 = await kubectl.list('pod', { allNamespaces: true, labelSelector: { tier: 'control-plane' }, fieldSelector: [{ path: 'status.podIP', op: 'NotEqual', value: '10.1.0.8' }] })
```

### kubectl scale

Scale single resource if resource"s spec.replicas exists and spec.replicas is number

```typescript
// scale without namespace
const result = await kubectl.scale('deployment', 'nginx', 2);
```

```typescript
// scale with namespace
const namespace = "my-namespace";
const result = await kubectl.scale('deployment', 'nginx', 2, { namespace });
```

### kubectl patch

Patch single resource

Sequence
1. Get resource from remort
2. Apply json-patch locally
3. Apply the modification through server-side-apply patch.

See [json-patch](https://datatracker.ietf.org/doc/html/rfc6902) for additional information.

```typescript
// patch without namespace
const result = await kubectl.patch('deployment', 'nginx', [{ op: "add", path: "/metadata/annotations", value: { key1: "value1" } }]);
```

```typescript
// patch with namespace
const namespace = "my-namespace";
const result = await kubectl.scale('deployment', 'nginx', [{ op: "add", path: "/metadata/annotations", value: { key1: "value1" } }], { namespace });
```

### kubectl delete

Delete single resource

```typescript
// delete without namespace
const result = await kubectl.delete('deployment', 'nginx');
```

```typescript
// delete with namespace
const namespace = "my-namespace";
const result = await kubectl.delete('deployment', 'nginx', { namespace });
```

### kubectl apply

```typescript
const objects = [
    {
        "apiVersion": "apps/v1",
        "kind": "Deployment",
        "metadata": {
            "labels": {
                "app": "nginx"
            },
            "name": "nginx",
            "namespace": "default"
        },
        "spec": {
            "selector": {
                "matchLabels": {
                    "app": "nginx"
                }
            },
            "template": {
                "metadata": {
                    "labels": {
                        "app": "nginx"
                    }
                },
                "spec": {
                    "containers": [
                        {
                            "image": "nginx",
                            "name": "nginx"
                        }
                    ]
                }
            }
        }
    },
    {
        "apiVersion": "apps/v1",
        "kind": "Deployment",
        "metadata": {
            "labels": {
                "app": "nginx"
            },
            "name": "nginx",
            "namespace": "my-namespace",
        },
        "spec": {
            "selector": {
                "matchLabels": {
                    "k8s-app": "nginx"
                }
            },
            "template": {
                "metadata": {
                    "labels": {
                        "k8s-app": "nginx"
                    }
                },
                "spec": {
                    "containers": [
                        {
                            "image": "nginx",
                            "name": "nginx"
                        }
                    ]
                }
            }
        }
    }
]
const result = await kubectl.apply(objects);
```

## To-Dos

- [ ] (Not sure) Support list resources using get (= conbine list and get)
- [ ] (Not sure) Support delete with labelSelect
- [ ] (Not sure) Support other methods (create, label, annotate, taint, drain, cordon, uncordon, etc.)