Skip to content

Commit bfeb23b

Browse files
authored
Added documentation (#3)
1 parent 4f63fd5 commit bfeb23b

File tree

6 files changed

+234
-2
lines changed

6 files changed

+234
-2
lines changed

README.md

+122
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,128 @@
33
A NPM package containing utility functions for parsing output from the Kubernetes `kubectl` command
44
line tool.
55

6+
# Reference
7+
8+
## Table format functions
9+
10+
These functions are for use with `kubectl` commands that return data in tabular format -
11+
that is, of the form:
12+
13+
```
14+
TITLE1 TITLE2 TITLE3
15+
value11 value12 value13
16+
value21 value22 value23
17+
```
18+
19+
where no column header or value contains a space, and columns are separated by one or more spaces.
20+
Examples include the default behaviour of `kubectl get`, for example `kubectl get pods` or
21+
`kubectl get pods -o wide` to get a list of pods.
22+
23+
In all cases:
24+
25+
* The function takes a `KubectlOutput`: that is, either a `ShellResult` (an object with numeric `code`,
26+
`stdout` string and `stderr` string properties), or `undefined`. `code` and `stderr` are used
27+
for error handling; on the happy path, the function will operate on the `stdout` string.
28+
* The function returns an `Errorable`: that is, an object with a boolean `succeeded` property. If
29+
`succeeded` is true, the object also has a `result` property containing the result of the function;
30+
if `succeeded` is false, the object has `reason` and `error` properties describing the failure.
31+
* If the input is `undefined`, or has a non-zero `code`, the function returns a _failed_ Errorable.
32+
* The function does not check the format of the provided `stdout`. You should use it **only** on the output
33+
of `kubectl` commands that return tabular data without spaces or missing values.
34+
35+
### parseTabular
36+
37+
**JavaScript:** `parseTabular(output)`
38+
39+
**TypeScript:** `parseTabular(output: KubectlOutput): Errorable<Dictionary<string>[]>`
40+
41+
Parses tabular `kubectl` output into an array of key-value objects, one per line.
42+
43+
The result is an array of the form:
44+
45+
```javascript
46+
[
47+
{
48+
title1: "value11",
49+
title2: "value12",
50+
title3: "value13"
51+
},
52+
{
53+
title1: "value21",
54+
title2: "value22",
55+
title3: "value23"
56+
}
57+
]
58+
```
59+
60+
Each non-header row is parsed as an object within the array. Each object's keys are the lowercased
61+
column headers, and the value of each key is the string under that header in the object's row.
62+
63+
If `output.stdout` is empty then the function returns success with an empty array.
64+
65+
**TypeScript:** `Dictionary<T>` is an alias for `{ [key: string]: T }`.
66+
67+
### asTableLines
68+
69+
**JavaScript:** `asTableLines(output)`
70+
71+
**TypeScript:** `asTableLines(output: KubectlOutput): Errorable<TableLines>`
72+
73+
Splits tabular `kubectl` output into a header line and an array of body lines. The result is
74+
an object of the form:
75+
76+
```javascript
77+
{
78+
header: "TITLE1 TITLE2 TITLE3",
79+
body: [
80+
"value11 value12 value13".
81+
"value21 value22 value23"
82+
]
83+
}
84+
```
85+
86+
If `output.stdout` is empty then the function returns success with an empty string `header` and
87+
an empty `body` array.
88+
89+
## JSON format functions
90+
91+
These functions are for use with `kubectl` commands that return data in JSON format.
92+
This is typically triggered by the `-o json` option and may be used for lists or for single
93+
resources, e.g. `kubectl get pods -o json` or `kubectl get deploy/nginx -o json`.
94+
95+
In all cases:
96+
97+
* The function takes a `KubectlOutput`: that is, either a `ShellResult` (an object with numeric `code`,
98+
`stdout` string and `stderr` string properties), or `undefined`. `code` and `stderr` are used
99+
for error handling; on the happy path, the function will operate on the `stdout` string.
100+
* The function returns an `Errorable`: that is, an object with a boolean `succeeded` property. If
101+
`succeeded` is true, the object also has a `result` property containing the result of the function;
102+
if `succeeded` is false, the object has `reason` and `error` properties describing the failure.
103+
* If the input is `undefined`, or has a non-zero `code`, or if `stdout` is empty, the function
104+
returns a _failed_ Errorable.
105+
* The function does not check the format of the provided `stdout`. You should use it **only** on the output
106+
of `kubectl` commands that return JSON data.
107+
108+
### parseJSON
109+
110+
**JavaScript:** `parseJSON(output)`
111+
112+
**TypeScript:** `parseJSON<T>(output: KubectlOutput): Errorable<T>`
113+
114+
Checks for `kubectl` failure and then returns the deserialised object corresponding to the
115+
`stdout` JSON.
116+
117+
### parseJSONCollection
118+
119+
**TypeScript:** `parseJSONCollection<T>(output: KubectlOutput): Errorable<KubernetesList<T>>`
120+
121+
Checks for `kubectl` failure and then returns the deserialised object corresponding to the
122+
`stdout` JSON, where this is a Kubernetes item list object.
123+
124+
This is equivalent to writing `parseJSON<KubernetesList<T>>`; it is provided for TypeScript
125+
users to reduce generics clutter in their code. (In untyped JavaScript, there's no difference
126+
between this and the `parseJSON` function.)
127+
6128
# Contributing
7129

8130
This project welcomes contributions and suggestions. Most contributions require you to agree to a

ts/src/dictionary.ts

+8
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
1+
/**
2+
* Represents objects which can have arbitrary property names but whose
3+
* properties must all be of the specified type. This is equivalent
4+
* to the TypeScript `{ [key: string]: T }` type.
5+
*/
16
export type Dictionary<T> = {
27
[key: string]: T
38
};
49

510
export module Dictionary {
11+
/**
12+
* Returns a new, empty Dictionary<T>.
13+
*/
614
export function of<T>(): Dictionary<T> {
715
return {};
816
}

ts/src/errorable.ts

+44
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,64 @@
1+
/**
2+
* Represents a successful result of a function on kubectl output - that is, the function
3+
* successfully computed a value.
4+
*/
15
export interface Succeeded<T> {
6+
/**
7+
* Identifies this as a successful result.
8+
*/
29
readonly succeeded: true;
10+
/**
11+
* The result value of the function.
12+
*/
313
readonly result: T;
414
}
515

16+
/**
17+
* Represents a failed result of a function on kubectl output - that is, the function was
18+
* unable to compute a value, and this object describes why.
19+
*/
620
export interface Failed {
21+
/**
22+
* Identifies this as a failed result.
23+
*/
724
readonly succeeded: false;
25+
/**
26+
* The reason for the failure. This is a programmatic identifier which you
27+
* can use to create a meaningful error message. Values are:
28+
*
29+
* 'failed-to-run': failed because the kubectl process was not created
30+
* 'kubectl-error': failed because kubectl encountered an error (returned a non-zero exit code)
31+
* 'failed-to-parse': failed because it could not parse kubectl's standard output
32+
*/
833
readonly reason: 'failed-to-run' | 'kubectl-error' | 'failed-to-parse';
34+
/**
35+
* If reason is 'kubectl-error', contains the stderr from kubectl. Otherwise,
36+
* contains a default message for the reason.
37+
*/
938
readonly error: string;
1039
}
1140

41+
/**
42+
* Represents the result of trying to parse kubectl output - success or failure.
43+
*/
1244
export type Errorable<T> = Succeeded<T> | Failed;
1345

46+
/**
47+
* Checks if an Errorable represents a successful parse. In TypeScript, this is
48+
* a type guard, and you may access the .result property after calling this.
49+
* @param e The Errorable to be checked.
50+
* @returns Whether the Errorable represents a successful parse.
51+
*/
1452
export function succeeded<T>(e: Errorable<T>): e is Succeeded<T> {
1553
return e.succeeded;
1654
}
1755

56+
/**
57+
* Checks if an Errorable represents a fauked parse. In TypeScript, this is
58+
* a type guard, and you may access the .reason and .error properties after calling this.
59+
* @param e The Errorable to be checked.
60+
* @returns Whether the Errorable represents a failed parse.
61+
*/
1862
export function failed<T>(e: Errorable<T>): e is Failed {
1963
return !e.succeeded;
2064
}

ts/src/index.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1+
/**
2+
* The result of invoking an external program via the shell.
3+
*/
14
export interface ShellResult {
25
readonly code: number;
36
readonly stdout: string;
47
readonly stderr: string;
58
}
69

10+
/**
11+
* The result of invoking the kubectl program via the shell.
12+
* This is undefined if creating the kubectl process failed.
13+
*/
714
export type KubectlOutput = ShellResult | undefined;
815

916
export * from './dictionary';
1017
export * from './errorable';
11-
export { asTableLines, parseTabular, parseTableLines, TableLines } from './table';
18+
export { asTableLines, parseTabular, TableLines } from './table';
1219
export { parseJSON, parseJSONCollection, KubernetesList } from './json';

ts/src/json.ts

+30
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,35 @@
11
import { KubectlOutput, Errorable } from ".";
22
import { Dictionary } from "./dictionary";
33

4+
/**
5+
* Represents how kubectl -o json formats lists of resources.
6+
*/
47
export interface KubernetesList<T> {
8+
/**
9+
* The Kubernetes API version.
10+
*/
511
readonly apiVersion: string;
12+
/**
13+
* The contents of the list.
14+
*/
615
readonly items: T[];
16+
/**
17+
* Identifies this object to the Kubernetes API as a list.
18+
*/
719
readonly kind: "List";
20+
/**
21+
* Contains additional data about the list.
22+
*/
823
readonly metadata: Dictionary<string>;
924
}
1025

26+
/**
27+
* Parses JSON kubectl output into an object.
28+
* @param output The result of invoking kubectl via the shell.
29+
* @returns If kubectl ran successfully and produced JSON output, a success value
30+
* containing the deserialised object. If kubectl did not run
31+
* successfully, a failure value.
32+
*/
1133
export function parseJSON<T>(output: KubectlOutput): Errorable<T> {
1234
if (!output) {
1335
return { succeeded: false, reason: 'failed-to-run', error: 'Unable to run kubectl' };
@@ -24,6 +46,14 @@ export function parseJSON<T>(output: KubectlOutput): Errorable<T> {
2446
return { succeeded: false, reason: 'kubectl-error', error: output.stderr };
2547
}
2648

49+
/**
50+
* Parses JSON kubectl output into a Kubernetes list object. You may use this if your
51+
* kubectl command requested a list of resources rather than a single resource.
52+
* @param output The result of invoking kubectl via the shell.
53+
* @returns If kubectl ran successfully and produced JSON output, a success value
54+
* containing the deserialised object. If kubectl did not run
55+
* successfully, a failure value.
56+
*/
2757
export function parseJSONCollection<T>(output: KubectlOutput): Errorable<KubernetesList<T>> {
2858
return parseJSON<KubernetesList<T>>(output);
2959
}

ts/src/table.ts

+22-1
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,23 @@ import { Errorable, failed } from "./errorable";
44

55
const KUBECTL_OUTPUT_COLUMN_SEPARATOR = /\s+/g;
66

7+
/**
8+
* Provides a line-oriented view of tabular kubectl output.
9+
*/
710
export interface TableLines {
811
readonly header: string;
912
readonly body: string[];
1013
}
1114

15+
/**
16+
* Parses tabular kubectl output into an array of objects. Each non-header row
17+
* is mapped to an object in the output, and each object has a property per column,
18+
* named as the lower-cased column header.
19+
* @param output The result of invoking kubectl via the shell.
20+
* @returns If kubectl ran successfully and produced tabular output, a success value
21+
* containing an array of objects for the non-header rows. If kubectl did not run
22+
* successfully, a failure value.
23+
*/
1224
export function parseTabular(output: KubectlOutput): Errorable<Dictionary<string>[]> {
1325
const table = asTableLines(output);
1426
if (failed(table)) {
@@ -19,6 +31,15 @@ export function parseTabular(output: KubectlOutput): Errorable<Dictionary<string
1931
return { succeeded: true, result: parsed };
2032
}
2133

34+
/**
35+
* Parses tabular kubectl output into an array of lines. The first row is mapped
36+
* as a header, and the remaining rows as a body array.
37+
* @param output The result of invoking kubectl via the shell.
38+
* @returns If kubectl ran successfully and produced tabular output, a success value
39+
* containing an object with header (string) and body (array of string) properties.
40+
* If kubectl ran successfully but produced no output, header is the empty string and
41+
* body the empty array. If kubectl did not run successfully, a failure value.
42+
*/
2243
export function asTableLines(output: KubectlOutput): Errorable<TableLines> {
2344
if (!output) {
2445
return { succeeded: false, reason: 'failed-to-run', error: 'Unable to run kubectl' };
@@ -37,7 +58,7 @@ export function asTableLines(output: KubectlOutput): Errorable<TableLines> {
3758
return { succeeded: false, reason: 'kubectl-error', error: output.stderr };
3859
}
3960

40-
export function parseTableLines(table: TableLines, columnSeparator: RegExp): Dictionary<string>[] {
61+
function parseTableLines(table: TableLines, columnSeparator: RegExp): Dictionary<string>[] {
4162
if (table.header.length === 0 || table.body.length === 0) {
4263
return [];
4364
}

0 commit comments

Comments
 (0)