github.com/wmuizelaar/kpt@v0.0.0-20221018115725-bd564717b2ed/site/book/05-developing-functions/03-developing-in-Typescript.md (about)

     1  kpt project provides an opinionated Typescript SDK for implementing functions.
     2  It provides the following features:
     3  
     4  - **General-purpose language:** Similar to Go, Typescript is a general-purpose
     5    programming language that provides:
     6    - Proper abstractions and language features
     7    - An extensive ecosystem of tooling (e.g. IDE support)
     8    - A comprehensive catalog of well-supported libraries
     9    - Robust community support and detailed documentation
    10  - **Idiomatic:** The TS SDK provides a different level of abstraction compared
    11    to the Go library we saw previously. Instead of exposing the low-level YAML
    12    AST, resources are marshalled into native Typescript objects. As a result, you
    13    get a more idiomatic and high-level abstraction. Ideally, you should work with
    14    native data structure/object in each language and not think about YAML which
    15    is just a file format. Even though resources in configuration files are
    16    round-tripped to Typescript objects, the kpt orchestrator ensures that
    17    YAML-specific constructs such as comments are preserved. The obvious
    18    limitation of this high-level abstraction is that you cannot develop functions
    19    for manipulating YAML-specific constructs like comments.
    20  - **Type-safety:** Kubernetes configuration is typed, and its schema is defined
    21    using the OpenAPI spec. Typescript has a sophisticated type system that
    22    accommodates the complexity of Kubernetes resources. The TS SDK enables
    23    generating Typescript classes for core and CRD types.
    24  - **Batteries-included:** The TS SDK provides a simple, powerful API for
    25    querying and manipulating resources inspired by [document-oriented databases].
    26    It provides the scaffolding required to develop, build, test, and publish
    27    functions, allowing you to focus on implementing your business-logic.
    28  
    29  ## Quickstart
    30  
    31  This quickstart will get you started developing a kpt function with the TS SDK.
    32  
    33  ### System Requirements
    34  
    35  Currently supported platforms: amd64 Linux/Mac
    36  
    37  - Install [kpt][download-kpt] and its dependencies
    38  - Install [node][download-node]
    39    - The SDK requires `npm` version 6 or higher.
    40    - If installing node from binaries (i.e. without a package manager), follow
    41      these [installation instructions][install-node].
    42  
    43  ### Explore the Demo Functions Package
    44  
    45  1. Get the `demo-functions` package:
    46  
    47     ```shell
    48     $ git clone --depth 1 https://github.com/GoogleContainerTools/kpt-functions-sdk.git
    49     ```
    50  
    51     All subsequent commands are run from the `demo-functions` directory:
    52  
    53     ```shell
    54     $ cd kpt-functions-sdk/ts/demo-functions
    55     ```
    56  
    57  1. Install all dependencies:
    58  
    59     ```shell
    60     $ npm install
    61     ```
    62  
    63  1. Run the following in a separate terminal to continuously build your function
    64     as you make changes:
    65  
    66     ```shell
    67     $ npm run watch
    68     ```
    69  
    70  1. Explore the [`label_namespace`][label-namespace] transformer function. This
    71     function takes a given `label_name` and `label_value` to add the appropriate
    72     label to `Namespace` objects using the SDK's `addLabel` function.
    73  
    74     ```typescript
    75     import { addLabel, Configs } from "kpt-functions";
    76     import { isNamespace } from "./gen/io.k8s.api.core.v1";
    77  
    78     export const LABEL_NAME = "label_name";
    79     export const LABEL_VALUE = "label_value";
    80  
    81     export async function labelNamespace(configs: Configs) {
    82       const labelName = configs.getFunctionConfigValueOrThrow(LABEL_NAME);
    83       const labelValue = configs.getFunctionConfigValueOrThrow(LABEL_VALUE);
    84       configs
    85         .get(isNamespace)
    86         .forEach((n) => addLabel(n, labelName, labelValue));
    87     }
    88     ```
    89  
    90  1. Run the `label_namespace` function on the `example-configs` directory:
    91  
    92     ```shell
    93     $ export CONFIGS=../../example-configs
    94     ```
    95  
    96     ```shell
    97     $ kpt fn eval $CONFIGS --exec "node dist/label_namespace_run.js" -- label_name=color label_value=orange
    98     ```
    99  
   100     As the name suggests, this function added the given label to all `Namespace`
   101     objects in the `example-configs` directory:
   102  
   103     ```shell
   104     $ git diff $CONFIGS
   105     ```
   106  
   107  1. Try modifying the function in `src/label_namespace.ts` to perform other
   108     operations and rerun the function on `example-configs` to see the changes.
   109  
   110  1. Explore validation functions like [validate-rolebinding]. Instead of
   111     transforming configuration, this function searches RoleBindings and returns a
   112     results field containing details about invalid subject names.
   113  
   114     ```typescript
   115     import { Configs, kubernetesObjectResult } from "kpt-functions";
   116     import { isRoleBinding } from "./gen/io.k8s.api.rbac.v1";
   117  
   118     const SUBJECT_NAME = "subject_name";
   119  
   120     export async function validateRolebinding(configs: Configs) {
   121       // Get the subject name parameter.
   122       const subjectName = configs.getFunctionConfigValueOrThrow(SUBJECT_NAME);
   123  
   124       // Iterate over all RoleBinding objects in the input
   125       // Filter those that have a subject we're looking for.
   126       const results = configs
   127         .get(isRoleBinding)
   128         .filter(
   129           (rb) =>
   130             rb && rb.subjects && rb.subjects.find((s) => s.name === subjectName)
   131         )
   132         .map((rb) =>
   133           kubernetesObjectResult(`Found banned subject '${subjectName}'`, rb)
   134         );
   135  
   136       configs.addResults(...results);
   137     }
   138     ```
   139  
   140  1. Run `validate-rolebinding` on `example-configs`.
   141  
   142     ```shell
   143     $ kpt fn eval $CONFIGS --exec "node dist/validate_rolebinding_run.js" -- subject_name=alice@foo-corp.com
   144     ```
   145  
   146     Look at the changes made by the function:
   147  
   148     ```shell
   149     $ git diff $CONFIGS
   150     ```
   151  
   152  1. Explore generator functions like [expand-team-cr]. This function generates a
   153     per-environment Namespace and RoleBinding object for each custom resource
   154     (CR) of type Team.
   155  
   156     ```typescript
   157     import { Configs } from "kpt-functions";
   158     import { isTeam, Team } from "./gen/dev.cft.anthos.v1alpha1";
   159     import { Namespace } from "./gen/io.k8s.api.core.v1";
   160     import { RoleBinding, Subject } from "./gen/io.k8s.api.rbac.v1";
   161  
   162     const ENVIRONMENTS = ["dev", "prod"];
   163  
   164     export async function expandTeamCr(configs: Configs) {
   165       // For each 'Team' custom resource in the input:
   166       // 1. Generate a per-enviroment Namespace.
   167       // 2. Generate RoleBindings in each Namespace.
   168       configs.get(isTeam).forEach((team) => {
   169         const name = team.metadata.name;
   170  
   171         ENVIRONMENTS.forEach((suffix) => {
   172           const ns = `${name}-${suffix}`;
   173           configs.insert(Namespace.named(ns));
   174           configs.insert(...createRoleBindings(team, ns));
   175         });
   176       });
   177     }
   178  
   179     function createRoleBindings(team: Team, namespace: string): RoleBinding[] {
   180       return (team.spec.roles || []).map((item) => {
   181         return new RoleBinding({
   182           metadata: {
   183             name: item.role,
   184             namespace,
   185           },
   186           subjects: roleSubjects(item),
   187           roleRef: {
   188             kind: "ClusterRole",
   189             name: item.role,
   190             apiGroup: "rbac.authorization.k8s.io",
   191           },
   192         });
   193       });
   194     }
   195  
   196     function roleSubjects(item: Team.Spec.Item): Subject[] {
   197       const userSubjects: Subject[] = (item.users || []).map(
   198         (user) =>
   199           new Subject({
   200             kind: "User",
   201             name: user,
   202           })
   203       );
   204       const groupSubjects: Subject[] = (item.groups || []).map(
   205         (group) =>
   206           new Subject({
   207             kind: "Group",
   208             name: group,
   209           })
   210       );
   211       return userSubjects.concat(groupSubjects);
   212     }
   213     ```
   214  
   215  1. Run `expand-team-cr` on `example-configs`.
   216  
   217     ```shell
   218     $ kpt fn eval $CONFIGS --exec "node dist/expand_team_cr_run.js"
   219     ```
   220  
   221     Look at the changes made by the function:
   222  
   223     ```shell
   224     $ git diff $CONFIGS
   225     ```
   226  
   227  ## Next Steps
   228  
   229  - Read the complete [Typescript SDK Developer Guide].
   230  - Take a look at these [example functions] to better understand how to use the
   231    TS SDK.
   232  
   233  [download-kpt]: /book/01-getting-started/01-system-requirements
   234  [download-node]: https://nodejs.org/en/download/
   235  [install-node]: https://github.com/nodejs/help/wiki/Installation/
   236  [ts sdk api]: https://googlecontainertools.github.io/kpt-functions-sdk/api/
   237  [label-namespace]:
   238    https://github.com/GoogleContainerTools/kpt-functions-sdk/blob/master/ts/demo-functions/src/label_namespace.ts
   239  [validate-rolebinding]:
   240    https://github.com/GoogleContainerTools/kpt-functions-sdk/blob/master/ts/demo-functions/src/validate_rolebinding.ts
   241  [expand-team-cr]:
   242    https://github.com/GoogleContainerTools/kpt-functions-sdk/blob/master/ts/demo-functions/src/expand_team_cr.ts
   243  [example functions]:
   244    https://github.com/GoogleContainerTools/kpt-functions-sdk/tree/master/ts/demo-functions/src/
   245  [document-oriented databases]:
   246    https://en.wikipedia.org/wiki/Document-oriented_database
   247  [typescript sdk developer guide]: /sdk/ts-guide